diff options
author | Melanie | 2011-05-05 09:49:10 +0100 |
---|---|---|
committer | Melanie | 2011-05-05 09:49:10 +0100 |
commit | 4beb0c9b9b402c1e8f70a02c0efa557c1f292f1c (patch) | |
tree | 24e24cb7b424df74b13788d28be9d7588fbd99d0 /OpenSim/Region/ClientStack/Linden | |
parent | Merge branch 'master' into careminster-presence-refactor (diff) | |
parent | Test m_Enabled on RemoveRegion. (diff) | |
download | opensim-SC-4beb0c9b9b402c1e8f70a02c0efa557c1f292f1c.zip opensim-SC-4beb0c9b9b402c1e8f70a02c0efa557c1f292f1c.tar.gz opensim-SC-4beb0c9b9b402c1e8f70a02c0efa557c1f292f1c.tar.bz2 opensim-SC-4beb0c9b9b402c1e8f70a02c0efa557c1f292f1c.tar.xz |
Merge branch 'master' into careminster-presence-refactor
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
27 files changed, 20362 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs new file mode 100644 index 0000000..95713e9 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -0,0 +1,938 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.IO; | ||
5 | using System.Reflection; | ||
6 | |||
7 | using OpenMetaverse; | ||
8 | using Nini.Config; | ||
9 | using log4net; | ||
10 | |||
11 | using OpenSim.Framework; | ||
12 | using OpenSim.Framework.Capabilities; | ||
13 | using OpenSim.Region.Framework; | ||
14 | using OpenSim.Region.Framework.Scenes; | ||
15 | using OpenSim.Framework.Servers; | ||
16 | using OpenSim.Framework.Servers.HttpServer; | ||
17 | using OpenSim.Services.Interfaces; | ||
18 | |||
19 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
20 | |||
21 | namespace OpenSim.Region.ClientStack.Linden | ||
22 | { | ||
23 | public delegate void UpLoadedAsset( | ||
24 | string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, | ||
25 | byte[] data, string inventoryType, string assetType); | ||
26 | |||
27 | public delegate void UploadedBakedTexture(UUID assetID, byte[] data); | ||
28 | |||
29 | public delegate UUID UpdateItem(UUID itemID, byte[] data); | ||
30 | |||
31 | public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); | ||
32 | |||
33 | public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); | ||
34 | |||
35 | public delegate void NewAsset(AssetBase asset); | ||
36 | |||
37 | public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data); | ||
38 | |||
39 | public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID, | ||
40 | bool isScriptRunning, byte[] data); | ||
41 | |||
42 | public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID, | ||
43 | bool fetchFolders, bool fetchItems, int sortOrder, out int version); | ||
44 | |||
45 | /// <summary> | ||
46 | /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that | ||
47 | /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want | ||
48 | /// to just pass the whole Scene into CAPS. | ||
49 | /// </summary> | ||
50 | public delegate IClientAPI GetClientDelegate(UUID agentID); | ||
51 | |||
52 | public class BunchOfCaps | ||
53 | { | ||
54 | private static readonly ILog m_log = | ||
55 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private Scene m_Scene; | ||
58 | private Caps m_HostCapsObj; | ||
59 | |||
60 | private static readonly string m_requestPath = "0000/"; | ||
61 | // private static readonly string m_mapLayerPath = "0001/"; | ||
62 | private static readonly string m_newInventory = "0002/"; | ||
63 | //private static readonly string m_requestTexture = "0003/"; | ||
64 | private static readonly string m_notecardUpdatePath = "0004/"; | ||
65 | private static readonly string m_notecardTaskUpdatePath = "0005/"; | ||
66 | // private static readonly string m_fetchInventoryPath = "0006/"; | ||
67 | // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. | ||
68 | private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. | ||
69 | |||
70 | |||
71 | // These are callbacks which will be setup by the scene so that we can update scene data when we | ||
72 | // receive capability calls | ||
73 | public NewInventoryItem AddNewInventoryItem = null; | ||
74 | public NewAsset AddNewAsset = null; | ||
75 | public ItemUpdatedCallback ItemUpdatedCall = null; | ||
76 | public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; | ||
77 | public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; | ||
78 | public GetClientDelegate GetClient = null; | ||
79 | |||
80 | private bool m_persistBakedTextures = false; | ||
81 | private IAssetService m_assetService; | ||
82 | private bool m_dumpAssetsToFile; | ||
83 | private string m_regionName; | ||
84 | |||
85 | public BunchOfCaps(Scene scene, Caps caps) | ||
86 | { | ||
87 | m_Scene = scene; | ||
88 | m_HostCapsObj = caps; | ||
89 | IConfigSource config = m_Scene.Config; | ||
90 | if (config != null) | ||
91 | { | ||
92 | IConfig sconfig = config.Configs["Startup"]; | ||
93 | if (sconfig != null) | ||
94 | m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); | ||
95 | } | ||
96 | |||
97 | m_assetService = m_Scene.AssetService; | ||
98 | m_regionName = m_Scene.RegionInfo.RegionName; | ||
99 | |||
100 | RegisterHandlers(); | ||
101 | |||
102 | AddNewInventoryItem = m_Scene.AddUploadedInventoryItem; | ||
103 | ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; | ||
104 | TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; | ||
105 | CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS; | ||
106 | GetClient = m_Scene.SceneContents.GetControllingClient; | ||
107 | |||
108 | } | ||
109 | |||
110 | /// <summary> | ||
111 | /// Register a bunch of CAPS http service handlers | ||
112 | /// </summary> | ||
113 | public void RegisterHandlers() | ||
114 | { | ||
115 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
116 | |||
117 | RegisterRegionServiceHandlers(capsBase); | ||
118 | RegisterInventoryServiceHandlers(capsBase); | ||
119 | } | ||
120 | |||
121 | public void RegisterRegionServiceHandlers(string capsBase) | ||
122 | { | ||
123 | try | ||
124 | { | ||
125 | // the root of all evil | ||
126 | m_HostCapsObj.RegisterHandler("SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest)); | ||
127 | m_log.DebugFormat( | ||
128 | "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); | ||
129 | |||
130 | //m_capsHandlers["MapLayer"] = | ||
131 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", | ||
132 | // capsBase + m_mapLayerPath, | ||
133 | // GetMapLayer); | ||
134 | IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory); | ||
135 | m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); | ||
136 | m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); | ||
137 | m_HostCapsObj.RegisterHandler("UploadBakedTexture", new RestStreamHandler("POST", capsBase + m_uploadBakedTexturePath, UploadBakedTexture)); | ||
138 | |||
139 | } | ||
140 | catch (Exception e) | ||
141 | { | ||
142 | m_log.Error("[CAPS]: " + e.ToString()); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | public void RegisterInventoryServiceHandlers(string capsBase) | ||
147 | { | ||
148 | try | ||
149 | { | ||
150 | // I don't think this one works... | ||
151 | m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST", | ||
152 | capsBase + m_newInventory, | ||
153 | NewAgentInventoryRequest)); | ||
154 | IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory); | ||
155 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); | ||
156 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); | ||
157 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); | ||
158 | |||
159 | // As of RC 1.22.9 of the Linden client this is | ||
160 | // supported | ||
161 | |||
162 | //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); | ||
163 | |||
164 | // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and | ||
165 | // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires | ||
166 | // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, | ||
167 | // but when I went on the Linden grid, the | ||
168 | // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, | ||
169 | // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP | ||
170 | // | ||
171 | // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid | ||
172 | // we will be | ||
173 | // able to get the data we need to implement the necessary part of the protocol to fix the issue above. | ||
174 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
175 | // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); | ||
176 | |||
177 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
178 | // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST", | ||
179 | // capsBase + m_fetchInventory, | ||
180 | // FetchInventory)); | ||
181 | // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", | ||
182 | // capsBase + m_requestTexture, | ||
183 | // RequestTexture); | ||
184 | } | ||
185 | catch (Exception e) | ||
186 | { | ||
187 | m_log.Error("[CAPS]: " + e.ToString()); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | /// <summary> | ||
192 | /// Construct a client response detailing all the capabilities this server can provide. | ||
193 | /// </summary> | ||
194 | /// <param name="request"></param> | ||
195 | /// <param name="path"></param> | ||
196 | /// <param name="param"></param> | ||
197 | /// <param name="httpRequest">HTTP request header object</param> | ||
198 | /// <param name="httpResponse">HTTP response header object</param> | ||
199 | /// <returns></returns> | ||
200 | public string SeedCapRequest(string request, string path, string param, | ||
201 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
202 | { | ||
203 | m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); | ||
204 | |||
205 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) | ||
206 | { | ||
207 | m_log.DebugFormat("[CAPS]: Unauthorized CAPS client"); | ||
208 | return string.Empty; | ||
209 | } | ||
210 | |||
211 | Hashtable caps = m_HostCapsObj.CapsHandlers.CapsDetails; | ||
212 | // Add the external too | ||
213 | foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers) | ||
214 | caps[kvp.Key] = kvp.Value; | ||
215 | |||
216 | string result = LLSDHelpers.SerialiseLLSDReply(caps); | ||
217 | |||
218 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); | ||
219 | |||
220 | return result; | ||
221 | } | ||
222 | |||
223 | /// <summary> | ||
224 | /// Called by the script task update handler. Provides a URL to which the client can upload a new asset. | ||
225 | /// </summary> | ||
226 | /// <param name="request"></param> | ||
227 | /// <param name="path"></param> | ||
228 | /// <param name="param"></param> | ||
229 | /// <param name="httpRequest">HTTP request header object</param> | ||
230 | /// <param name="httpResponse">HTTP response header object</param> | ||
231 | /// <returns></returns> | ||
232 | public string ScriptTaskInventory(string request, string path, string param, | ||
233 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
234 | { | ||
235 | try | ||
236 | { | ||
237 | m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName); | ||
238 | //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param); | ||
239 | |||
240 | Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
241 | LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); | ||
242 | LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); | ||
243 | |||
244 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
245 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
246 | |||
247 | TaskInventoryScriptUpdater uploader = | ||
248 | new TaskInventoryScriptUpdater( | ||
249 | llsdUpdateRequest.item_id, | ||
250 | llsdUpdateRequest.task_id, | ||
251 | llsdUpdateRequest.is_script_running, | ||
252 | capsBase + uploaderPath, | ||
253 | m_HostCapsObj.HttpListener, | ||
254 | m_dumpAssetsToFile); | ||
255 | uploader.OnUpLoad += TaskScriptUpdated; | ||
256 | |||
257 | m_HostCapsObj.HttpListener.AddStreamHandler(new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
258 | |||
259 | string protocol = "http://"; | ||
260 | |||
261 | if (m_HostCapsObj.SSLCaps) | ||
262 | protocol = "https://"; | ||
263 | |||
264 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | ||
265 | uploaderPath; | ||
266 | |||
267 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
268 | uploadResponse.uploader = uploaderURL; | ||
269 | uploadResponse.state = "upload"; | ||
270 | |||
271 | // m_log.InfoFormat("[CAPS]: " + | ||
272 | // "ScriptTaskInventory response: {0}", | ||
273 | // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); | ||
274 | |||
275 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
276 | } | ||
277 | catch (Exception e) | ||
278 | { | ||
279 | m_log.Error("[CAPS]: " + e.ToString()); | ||
280 | } | ||
281 | |||
282 | return null; | ||
283 | } | ||
284 | |||
285 | /// <summary> | ||
286 | /// Called when new asset data for an agent inventory item update has been uploaded. | ||
287 | /// </summary> | ||
288 | /// <param name="itemID">Item to update</param> | ||
289 | /// <param name="primID">Prim containing item to update</param> | ||
290 | /// <param name="isScriptRunning">Signals whether the script to update is currently running</param> | ||
291 | /// <param name="data">New asset data</param> | ||
292 | public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors) | ||
293 | { | ||
294 | if (TaskScriptUpdatedCall != null) | ||
295 | { | ||
296 | ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data); | ||
297 | foreach (Object item in e) | ||
298 | errors.Add(item); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | public string UploadBakedTexture(string request, string path, | ||
303 | string param, OSHttpRequest httpRequest, | ||
304 | OSHttpResponse httpResponse) | ||
305 | { | ||
306 | try | ||
307 | { | ||
308 | // m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " + | ||
309 | // m_regionName); | ||
310 | |||
311 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
312 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
313 | |||
314 | BakedTextureUploader uploader = | ||
315 | new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener); | ||
316 | uploader.OnUpLoad += BakedTextureUploaded; | ||
317 | |||
318 | m_HostCapsObj.HttpListener.AddStreamHandler( | ||
319 | new BinaryStreamHandler("POST", capsBase + uploaderPath, | ||
320 | uploader.uploaderCaps)); | ||
321 | |||
322 | string protocol = "http://"; | ||
323 | |||
324 | if (m_HostCapsObj.SSLCaps) | ||
325 | protocol = "https://"; | ||
326 | |||
327 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + | ||
328 | m_HostCapsObj.Port.ToString() + capsBase + uploaderPath; | ||
329 | |||
330 | LLSDAssetUploadResponse uploadResponse = | ||
331 | new LLSDAssetUploadResponse(); | ||
332 | uploadResponse.uploader = uploaderURL; | ||
333 | uploadResponse.state = "upload"; | ||
334 | |||
335 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
336 | } | ||
337 | catch (Exception e) | ||
338 | { | ||
339 | m_log.Error("[CAPS]: " + e.ToString()); | ||
340 | } | ||
341 | |||
342 | return null; | ||
343 | } | ||
344 | |||
345 | public void BakedTextureUploaded(UUID assetID, byte[] data) | ||
346 | { | ||
347 | // m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString()); | ||
348 | |||
349 | AssetBase asset; | ||
350 | asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString()); | ||
351 | asset.Data = data; | ||
352 | asset.Temporary = true; | ||
353 | asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are | ||
354 | m_assetService.Store(asset); | ||
355 | } | ||
356 | |||
357 | /// <summary> | ||
358 | /// Called when new asset data for an agent inventory item update has been uploaded. | ||
359 | /// </summary> | ||
360 | /// <param name="itemID">Item to update</param> | ||
361 | /// <param name="data">New asset data</param> | ||
362 | /// <returns></returns> | ||
363 | public UUID ItemUpdated(UUID itemID, byte[] data) | ||
364 | { | ||
365 | if (ItemUpdatedCall != null) | ||
366 | { | ||
367 | return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data); | ||
368 | } | ||
369 | |||
370 | return UUID.Zero; | ||
371 | } | ||
372 | |||
373 | /// <summary> | ||
374 | /// | ||
375 | /// </summary> | ||
376 | /// <param name="llsdRequest"></param> | ||
377 | /// <returns></returns> | ||
378 | public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest) | ||
379 | { | ||
380 | //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); | ||
381 | //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); | ||
382 | |||
383 | if (llsdRequest.asset_type == "texture" || | ||
384 | llsdRequest.asset_type == "animation" || | ||
385 | llsdRequest.asset_type == "sound") | ||
386 | { | ||
387 | IClientAPI client = null; | ||
388 | IScene scene = null; | ||
389 | if (GetClient != null) | ||
390 | { | ||
391 | client = GetClient(m_HostCapsObj.AgentID); | ||
392 | scene = client.Scene; | ||
393 | |||
394 | IMoneyModule mm = scene.RequestModuleInterface<IMoneyModule>(); | ||
395 | |||
396 | if (mm != null) | ||
397 | { | ||
398 | if (!mm.UploadCovered(client, mm.UploadCharge)) | ||
399 | { | ||
400 | if (client != null) | ||
401 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | ||
402 | |||
403 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | ||
404 | errorResponse.uploader = ""; | ||
405 | errorResponse.state = "error"; | ||
406 | return errorResponse; | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | |||
412 | string assetName = llsdRequest.name; | ||
413 | string assetDes = llsdRequest.description; | ||
414 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
415 | UUID newAsset = UUID.Random(); | ||
416 | UUID newInvItem = UUID.Random(); | ||
417 | UUID parentFolder = llsdRequest.folder_id; | ||
418 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
419 | |||
420 | AssetUploader uploader = | ||
421 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | ||
422 | llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); | ||
423 | m_HostCapsObj.HttpListener.AddStreamHandler( | ||
424 | new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
425 | |||
426 | string protocol = "http://"; | ||
427 | |||
428 | if (m_HostCapsObj.SSLCaps) | ||
429 | protocol = "https://"; | ||
430 | |||
431 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | ||
432 | uploaderPath; | ||
433 | |||
434 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
435 | uploadResponse.uploader = uploaderURL; | ||
436 | uploadResponse.state = "upload"; | ||
437 | uploader.OnUpLoad += UploadCompleteHandler; | ||
438 | return uploadResponse; | ||
439 | } | ||
440 | |||
441 | /// <summary> | ||
442 | /// | ||
443 | /// </summary> | ||
444 | /// <param name="assetID"></param> | ||
445 | /// <param name="inventoryItem"></param> | ||
446 | /// <param name="data"></param> | ||
447 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | ||
448 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | ||
449 | string assetType) | ||
450 | { | ||
451 | sbyte assType = 0; | ||
452 | sbyte inType = 0; | ||
453 | |||
454 | if (inventoryType == "sound") | ||
455 | { | ||
456 | inType = 1; | ||
457 | assType = 1; | ||
458 | } | ||
459 | else if (inventoryType == "animation") | ||
460 | { | ||
461 | inType = 19; | ||
462 | assType = 20; | ||
463 | } | ||
464 | else if (inventoryType == "wearable") | ||
465 | { | ||
466 | inType = 18; | ||
467 | switch (assetType) | ||
468 | { | ||
469 | case "bodypart": | ||
470 | assType = 13; | ||
471 | break; | ||
472 | case "clothing": | ||
473 | assType = 5; | ||
474 | break; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | AssetBase asset; | ||
479 | asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); | ||
480 | asset.Data = data; | ||
481 | if (AddNewAsset != null) | ||
482 | AddNewAsset(asset); | ||
483 | else if (m_assetService != null) | ||
484 | m_assetService.Store(asset); | ||
485 | |||
486 | InventoryItemBase item = new InventoryItemBase(); | ||
487 | item.Owner = m_HostCapsObj.AgentID; | ||
488 | item.CreatorId = m_HostCapsObj.AgentID.ToString(); | ||
489 | item.CreatorData = String.Empty; | ||
490 | item.ID = inventoryItem; | ||
491 | item.AssetID = asset.FullID; | ||
492 | item.Description = assetDescription; | ||
493 | item.Name = assetName; | ||
494 | item.AssetType = assType; | ||
495 | item.InvType = inType; | ||
496 | item.Folder = parentFolder; | ||
497 | item.CurrentPermissions = (uint)PermissionMask.All; | ||
498 | item.BasePermissions = (uint)PermissionMask.All; | ||
499 | item.EveryOnePermissions = 0; | ||
500 | item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); | ||
501 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
502 | |||
503 | if (AddNewInventoryItem != null) | ||
504 | { | ||
505 | AddNewInventoryItem(m_HostCapsObj.AgentID, item); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | |||
510 | |||
511 | /// <summary> | ||
512 | /// | ||
513 | /// </summary> | ||
514 | /// <param name="mapReq"></param> | ||
515 | /// <returns></returns> | ||
516 | public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) | ||
517 | { | ||
518 | m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName); | ||
519 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); | ||
520 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); | ||
521 | return mapResponse; | ||
522 | } | ||
523 | |||
524 | /// <summary> | ||
525 | /// | ||
526 | /// </summary> | ||
527 | /// <returns></returns> | ||
528 | protected static OSDMapLayer GetOSDMapLayerResponse() | ||
529 | { | ||
530 | OSDMapLayer mapLayer = new OSDMapLayer(); | ||
531 | mapLayer.Right = 5000; | ||
532 | mapLayer.Top = 5000; | ||
533 | mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); | ||
534 | |||
535 | return mapLayer; | ||
536 | } | ||
537 | |||
538 | /// <summary> | ||
539 | /// | ||
540 | /// </summary> | ||
541 | /// <param name="request"></param> | ||
542 | /// <param name="path"></param> | ||
543 | /// <param name="param"></param> | ||
544 | /// <returns></returns> | ||
545 | public string RequestTexture(string request, string path, string param) | ||
546 | { | ||
547 | m_log.Debug("texture request " + request); | ||
548 | // Needs implementing (added to remove compiler warning) | ||
549 | return String.Empty; | ||
550 | } | ||
551 | |||
552 | |||
553 | /// <summary> | ||
554 | /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. | ||
555 | /// </summary> | ||
556 | /// <param name="request"></param> | ||
557 | /// <param name="path"></param> | ||
558 | /// <param name="param"></param> | ||
559 | /// <returns></returns> | ||
560 | public string NoteCardAgentInventory(string request, string path, string param, | ||
561 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
562 | { | ||
563 | //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request); | ||
564 | //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request); | ||
565 | |||
566 | //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request)); | ||
567 | Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
568 | LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); | ||
569 | LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); | ||
570 | |||
571 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
572 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
573 | |||
574 | ItemUpdater uploader = | ||
575 | new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); | ||
576 | uploader.OnUpLoad += ItemUpdated; | ||
577 | |||
578 | m_HostCapsObj.HttpListener.AddStreamHandler( | ||
579 | new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
580 | |||
581 | string protocol = "http://"; | ||
582 | |||
583 | if (m_HostCapsObj.SSLCaps) | ||
584 | protocol = "https://"; | ||
585 | |||
586 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | ||
587 | uploaderPath; | ||
588 | |||
589 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
590 | uploadResponse.uploader = uploaderURL; | ||
591 | uploadResponse.state = "upload"; | ||
592 | |||
593 | // m_log.InfoFormat("[CAPS]: " + | ||
594 | // "NoteCardAgentInventory response: {0}", | ||
595 | // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); | ||
596 | |||
597 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | public class AssetUploader | ||
602 | { | ||
603 | public event UpLoadedAsset OnUpLoad; | ||
604 | private UpLoadedAsset handlerUpLoad = null; | ||
605 | |||
606 | private string uploaderPath = String.Empty; | ||
607 | private UUID newAssetID; | ||
608 | private UUID inventoryItemID; | ||
609 | private UUID parentFolder; | ||
610 | private IHttpServer httpListener; | ||
611 | private bool m_dumpAssetsToFile; | ||
612 | private string m_assetName = String.Empty; | ||
613 | private string m_assetDes = String.Empty; | ||
614 | |||
615 | private string m_invType = String.Empty; | ||
616 | private string m_assetType = String.Empty; | ||
617 | |||
618 | public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, | ||
619 | UUID parentFolderID, string invType, string assetType, string path, | ||
620 | IHttpServer httpServer, bool dumpAssetsToFile) | ||
621 | { | ||
622 | m_assetName = assetName; | ||
623 | m_assetDes = description; | ||
624 | newAssetID = assetID; | ||
625 | inventoryItemID = inventoryItem; | ||
626 | uploaderPath = path; | ||
627 | httpListener = httpServer; | ||
628 | parentFolder = parentFolderID; | ||
629 | m_assetType = assetType; | ||
630 | m_invType = invType; | ||
631 | m_dumpAssetsToFile = dumpAssetsToFile; | ||
632 | } | ||
633 | |||
634 | /// <summary> | ||
635 | /// | ||
636 | /// </summary> | ||
637 | /// <param name="data"></param> | ||
638 | /// <param name="path"></param> | ||
639 | /// <param name="param"></param> | ||
640 | /// <returns></returns> | ||
641 | public string uploaderCaps(byte[] data, string path, string param) | ||
642 | { | ||
643 | UUID inv = inventoryItemID; | ||
644 | string res = String.Empty; | ||
645 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||
646 | uploadComplete.new_asset = newAssetID.ToString(); | ||
647 | uploadComplete.new_inventory_item = inv; | ||
648 | uploadComplete.state = "complete"; | ||
649 | |||
650 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
651 | |||
652 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
653 | |||
654 | // TODO: probably make this a better set of extensions here | ||
655 | string extension = ".jp2"; | ||
656 | if (m_invType != "image") | ||
657 | { | ||
658 | extension = ".dat"; | ||
659 | } | ||
660 | |||
661 | if (m_dumpAssetsToFile) | ||
662 | { | ||
663 | SaveAssetToFile(m_assetName + extension, data); | ||
664 | } | ||
665 | handlerUpLoad = OnUpLoad; | ||
666 | if (handlerUpLoad != null) | ||
667 | { | ||
668 | handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); | ||
669 | } | ||
670 | |||
671 | return res; | ||
672 | } | ||
673 | ///Left this in and commented in case there are unforseen issues | ||
674 | //private void SaveAssetToFile(string filename, byte[] data) | ||
675 | //{ | ||
676 | // FileStream fs = File.Create(filename); | ||
677 | // BinaryWriter bw = new BinaryWriter(fs); | ||
678 | // bw.Write(data); | ||
679 | // bw.Close(); | ||
680 | // fs.Close(); | ||
681 | //} | ||
682 | private static void SaveAssetToFile(string filename, byte[] data) | ||
683 | { | ||
684 | string assetPath = "UserAssets"; | ||
685 | if (!Directory.Exists(assetPath)) | ||
686 | { | ||
687 | Directory.CreateDirectory(assetPath); | ||
688 | } | ||
689 | FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename))); | ||
690 | BinaryWriter bw = new BinaryWriter(fs); | ||
691 | bw.Write(data); | ||
692 | bw.Close(); | ||
693 | fs.Close(); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | /// <summary> | ||
698 | /// This class is a callback invoked when a client sends asset data to | ||
699 | /// an agent inventory notecard update url | ||
700 | /// </summary> | ||
701 | public class ItemUpdater | ||
702 | { | ||
703 | public event UpdateItem OnUpLoad; | ||
704 | |||
705 | private UpdateItem handlerUpdateItem = null; | ||
706 | |||
707 | private string uploaderPath = String.Empty; | ||
708 | private UUID inventoryItemID; | ||
709 | private IHttpServer httpListener; | ||
710 | private bool m_dumpAssetToFile; | ||
711 | |||
712 | public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile) | ||
713 | { | ||
714 | m_dumpAssetToFile = dumpAssetToFile; | ||
715 | |||
716 | inventoryItemID = inventoryItem; | ||
717 | uploaderPath = path; | ||
718 | httpListener = httpServer; | ||
719 | } | ||
720 | |||
721 | /// <summary> | ||
722 | /// | ||
723 | /// </summary> | ||
724 | /// <param name="data"></param> | ||
725 | /// <param name="path"></param> | ||
726 | /// <param name="param"></param> | ||
727 | /// <returns></returns> | ||
728 | public string uploaderCaps(byte[] data, string path, string param) | ||
729 | { | ||
730 | UUID inv = inventoryItemID; | ||
731 | string res = String.Empty; | ||
732 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||
733 | UUID assetID = UUID.Zero; | ||
734 | handlerUpdateItem = OnUpLoad; | ||
735 | if (handlerUpdateItem != null) | ||
736 | { | ||
737 | assetID = handlerUpdateItem(inv, data); | ||
738 | } | ||
739 | |||
740 | uploadComplete.new_asset = assetID.ToString(); | ||
741 | uploadComplete.new_inventory_item = inv; | ||
742 | uploadComplete.state = "complete"; | ||
743 | |||
744 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
745 | |||
746 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
747 | |||
748 | if (m_dumpAssetToFile) | ||
749 | { | ||
750 | SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data); | ||
751 | } | ||
752 | |||
753 | return res; | ||
754 | } | ||
755 | ///Left this in and commented in case there are unforseen issues | ||
756 | //private void SaveAssetToFile(string filename, byte[] data) | ||
757 | //{ | ||
758 | // FileStream fs = File.Create(filename); | ||
759 | // BinaryWriter bw = new BinaryWriter(fs); | ||
760 | // bw.Write(data); | ||
761 | // bw.Close(); | ||
762 | // fs.Close(); | ||
763 | //} | ||
764 | private static void SaveAssetToFile(string filename, byte[] data) | ||
765 | { | ||
766 | string assetPath = "UserAssets"; | ||
767 | if (!Directory.Exists(assetPath)) | ||
768 | { | ||
769 | Directory.CreateDirectory(assetPath); | ||
770 | } | ||
771 | FileStream fs = File.Create(Path.Combine(assetPath, filename)); | ||
772 | BinaryWriter bw = new BinaryWriter(fs); | ||
773 | bw.Write(data); | ||
774 | bw.Close(); | ||
775 | fs.Close(); | ||
776 | } | ||
777 | } | ||
778 | |||
779 | /// <summary> | ||
780 | /// This class is a callback invoked when a client sends asset data to | ||
781 | /// a task inventory script update url | ||
782 | /// </summary> | ||
783 | public class TaskInventoryScriptUpdater | ||
784 | { | ||
785 | private static readonly ILog m_log = | ||
786 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
787 | |||
788 | public event UpdateTaskScript OnUpLoad; | ||
789 | |||
790 | private UpdateTaskScript handlerUpdateTaskScript = null; | ||
791 | |||
792 | private string uploaderPath = String.Empty; | ||
793 | private UUID inventoryItemID; | ||
794 | private UUID primID; | ||
795 | private bool isScriptRunning; | ||
796 | private IHttpServer httpListener; | ||
797 | private bool m_dumpAssetToFile; | ||
798 | |||
799 | public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning, | ||
800 | string path, IHttpServer httpServer, bool dumpAssetToFile) | ||
801 | { | ||
802 | m_dumpAssetToFile = dumpAssetToFile; | ||
803 | |||
804 | this.inventoryItemID = inventoryItemID; | ||
805 | this.primID = primID; | ||
806 | |||
807 | // This comes in over the packet as an integer, but actually appears to be treated as a bool | ||
808 | this.isScriptRunning = (0 == isScriptRunning ? false : true); | ||
809 | |||
810 | uploaderPath = path; | ||
811 | httpListener = httpServer; | ||
812 | } | ||
813 | |||
814 | /// <summary> | ||
815 | /// | ||
816 | /// </summary> | ||
817 | /// <param name="data"></param> | ||
818 | /// <param name="path"></param> | ||
819 | /// <param name="param"></param> | ||
820 | /// <returns></returns> | ||
821 | public string uploaderCaps(byte[] data, string path, string param) | ||
822 | { | ||
823 | try | ||
824 | { | ||
825 | // m_log.InfoFormat("[CAPS]: " + | ||
826 | // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}", | ||
827 | // data, path, param)); | ||
828 | |||
829 | string res = String.Empty; | ||
830 | LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete(); | ||
831 | |||
832 | ArrayList errors = new ArrayList(); | ||
833 | handlerUpdateTaskScript = OnUpLoad; | ||
834 | if (handlerUpdateTaskScript != null) | ||
835 | { | ||
836 | handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors); | ||
837 | } | ||
838 | |||
839 | uploadComplete.new_asset = inventoryItemID; | ||
840 | uploadComplete.compiled = errors.Count > 0 ? false : true; | ||
841 | uploadComplete.state = "complete"; | ||
842 | uploadComplete.errors = new OSDArray(); | ||
843 | uploadComplete.errors.Array = errors; | ||
844 | |||
845 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
846 | |||
847 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
848 | |||
849 | if (m_dumpAssetToFile) | ||
850 | { | ||
851 | SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data); | ||
852 | } | ||
853 | |||
854 | // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res); | ||
855 | |||
856 | return res; | ||
857 | } | ||
858 | catch (Exception e) | ||
859 | { | ||
860 | m_log.Error("[CAPS]: " + e.ToString()); | ||
861 | } | ||
862 | |||
863 | // XXX Maybe this should be some meaningful error packet | ||
864 | return null; | ||
865 | } | ||
866 | ///Left this in and commented in case there are unforseen issues | ||
867 | //private void SaveAssetToFile(string filename, byte[] data) | ||
868 | //{ | ||
869 | // FileStream fs = File.Create(filename); | ||
870 | // BinaryWriter bw = new BinaryWriter(fs); | ||
871 | // bw.Write(data); | ||
872 | // bw.Close(); | ||
873 | // fs.Close(); | ||
874 | //} | ||
875 | private static void SaveAssetToFile(string filename, byte[] data) | ||
876 | { | ||
877 | string assetPath = "UserAssets"; | ||
878 | if (!Directory.Exists(assetPath)) | ||
879 | { | ||
880 | Directory.CreateDirectory(assetPath); | ||
881 | } | ||
882 | FileStream fs = File.Create(Path.Combine(assetPath, filename)); | ||
883 | BinaryWriter bw = new BinaryWriter(fs); | ||
884 | bw.Write(data); | ||
885 | bw.Close(); | ||
886 | fs.Close(); | ||
887 | } | ||
888 | } | ||
889 | |||
890 | public class BakedTextureUploader | ||
891 | { | ||
892 | public event UploadedBakedTexture OnUpLoad; | ||
893 | private UploadedBakedTexture handlerUpLoad = null; | ||
894 | |||
895 | private string uploaderPath = String.Empty; | ||
896 | private UUID newAssetID; | ||
897 | private IHttpServer httpListener; | ||
898 | |||
899 | public BakedTextureUploader(string path, IHttpServer httpServer) | ||
900 | { | ||
901 | newAssetID = UUID.Random(); | ||
902 | uploaderPath = path; | ||
903 | httpListener = httpServer; | ||
904 | // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); | ||
905 | } | ||
906 | |||
907 | /// <summary> | ||
908 | /// | ||
909 | /// </summary> | ||
910 | /// <param name="data"></param> | ||
911 | /// <param name="path"></param> | ||
912 | /// <param name="param"></param> | ||
913 | /// <returns></returns> | ||
914 | public string uploaderCaps(byte[] data, string path, string param) | ||
915 | { | ||
916 | handlerUpLoad = OnUpLoad; | ||
917 | if (handlerUpLoad != null) | ||
918 | { | ||
919 | Util.FireAndForget(delegate(object o) { handlerUpLoad(newAssetID, data); }); | ||
920 | } | ||
921 | |||
922 | string res = String.Empty; | ||
923 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||
924 | uploadComplete.new_asset = newAssetID.ToString(); | ||
925 | uploadComplete.new_inventory_item = UUID.Zero; | ||
926 | uploadComplete.state = "complete"; | ||
927 | |||
928 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
929 | |||
930 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
931 | |||
932 | // m_log.InfoFormat("[CAPS] baked texture upload completed for {0}",newAssetID); | ||
933 | |||
934 | return res; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs new file mode 100644 index 0000000..14160ae --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | |||
@@ -0,0 +1,91 @@ | |||
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.Generic; | ||
30 | using System.Reflection; | ||
31 | |||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using Mono.Addins; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | [assembly: Addin("LindenCaps", "0.1")] | ||
44 | [assembly: AddinDependency("OpenSim", "0.5")] | ||
45 | namespace OpenSim.Region.ClientStack.Linden | ||
46 | { | ||
47 | |||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
49 | public class BunchOfCapsModule : INonSharedRegionModule | ||
50 | { | ||
51 | private static readonly ILog m_log = | ||
52 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | |||
54 | private Scene m_Scene; | ||
55 | |||
56 | #region INonSharedRegionModule | ||
57 | |||
58 | public string Name { get { return "BunchOfCapsModule"; } } | ||
59 | |||
60 | public Type ReplaceableInterface { get { return null; } } | ||
61 | |||
62 | public void Initialise(IConfigSource source) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | public void Close() { } | ||
67 | |||
68 | public void AddRegion(Scene scene) | ||
69 | { | ||
70 | m_Scene = scene; | ||
71 | m_Scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
72 | } | ||
73 | |||
74 | public void RemoveRegion(Scene scene) | ||
75 | { | ||
76 | } | ||
77 | |||
78 | public void RegionLoaded(Scene scene) | ||
79 | { | ||
80 | } | ||
81 | |||
82 | public void PostInitialise() { } | ||
83 | #endregion | ||
84 | |||
85 | private void OnRegisterCaps(UUID agentID, Caps caps) | ||
86 | { | ||
87 | new BunchOfCaps(m_Scene, caps); | ||
88 | } | ||
89 | |||
90 | } | ||
91 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs new file mode 100644 index 0000000..139d8b8 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -0,0 +1,731 @@ | |||
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.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Mono.Addins; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.Messages.Linden; | ||
39 | using OpenMetaverse.Packets; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.HttpServer; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>; | ||
47 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
48 | |||
49 | namespace OpenSim.Region.ClientStack.Linden | ||
50 | { | ||
51 | public struct QueueItem | ||
52 | { | ||
53 | public int id; | ||
54 | public OSDMap body; | ||
55 | } | ||
56 | |||
57 | //[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
58 | public class EventQueueGetModule : IEventQueue, IRegionModule | ||
59 | { | ||
60 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
61 | protected Scene m_scene = null; | ||
62 | private IConfigSource m_gConfig; | ||
63 | bool enabledYN = false; | ||
64 | |||
65 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | ||
66 | |||
67 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); | ||
68 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | ||
69 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | ||
70 | |||
71 | #region IRegionModule methods | ||
72 | public virtual void Initialise(Scene scene, IConfigSource config) | ||
73 | { | ||
74 | m_gConfig = config; | ||
75 | |||
76 | IConfig startupConfig = m_gConfig.Configs["Startup"]; | ||
77 | |||
78 | ReadConfigAndPopulate(scene, startupConfig, "Startup"); | ||
79 | |||
80 | if (enabledYN) | ||
81 | { | ||
82 | m_scene = scene; | ||
83 | scene.RegisterModuleInterface<IEventQueue>(this); | ||
84 | |||
85 | // Register fallback handler | ||
86 | // Why does EQG Fail on region crossings! | ||
87 | |||
88 | //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); | ||
89 | |||
90 | scene.EventManager.OnNewClient += OnNewClient; | ||
91 | |||
92 | // TODO: Leaving these open, or closing them when we | ||
93 | // become a child is incorrect. It messes up TP in a big | ||
94 | // way. CAPS/EQ need to be active as long as the UDP | ||
95 | // circuit is there. | ||
96 | |||
97 | scene.EventManager.OnClientClosed += ClientClosed; | ||
98 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | ||
99 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | m_gConfig = null; | ||
104 | } | ||
105 | |||
106 | } | ||
107 | |||
108 | private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string p) | ||
109 | { | ||
110 | enabledYN = startupConfig.GetBoolean("EventQueue", true); | ||
111 | } | ||
112 | |||
113 | public void PostInitialise() | ||
114 | { | ||
115 | } | ||
116 | |||
117 | public virtual void Close() | ||
118 | { | ||
119 | } | ||
120 | |||
121 | public virtual string Name | ||
122 | { | ||
123 | get { return "EventQueueGetModule"; } | ||
124 | } | ||
125 | |||
126 | public bool IsSharedModule | ||
127 | { | ||
128 | get { return false; } | ||
129 | } | ||
130 | #endregion | ||
131 | |||
132 | /// <summary> | ||
133 | /// Always returns a valid queue | ||
134 | /// </summary> | ||
135 | /// <param name="agentId"></param> | ||
136 | /// <returns></returns> | ||
137 | private Queue<OSD> TryGetQueue(UUID agentId) | ||
138 | { | ||
139 | lock (queues) | ||
140 | { | ||
141 | if (!queues.ContainsKey(agentId)) | ||
142 | { | ||
143 | /* | ||
144 | m_log.DebugFormat( | ||
145 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | ||
146 | agentId, m_scene.RegionInfo.RegionName); | ||
147 | */ | ||
148 | queues[agentId] = new Queue<OSD>(); | ||
149 | } | ||
150 | |||
151 | return queues[agentId]; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /// <summary> | ||
156 | /// May return a null queue | ||
157 | /// </summary> | ||
158 | /// <param name="agentId"></param> | ||
159 | /// <returns></returns> | ||
160 | private Queue<OSD> GetQueue(UUID agentId) | ||
161 | { | ||
162 | lock (queues) | ||
163 | { | ||
164 | if (queues.ContainsKey(agentId)) | ||
165 | { | ||
166 | return queues[agentId]; | ||
167 | } | ||
168 | else | ||
169 | return null; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | #region IEventQueue Members | ||
174 | |||
175 | public bool Enqueue(OSD ev, UUID avatarID) | ||
176 | { | ||
177 | //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); | ||
178 | try | ||
179 | { | ||
180 | Queue<OSD> queue = GetQueue(avatarID); | ||
181 | if (queue != null) | ||
182 | queue.Enqueue(ev); | ||
183 | } | ||
184 | catch(NullReferenceException e) | ||
185 | { | ||
186 | m_log.Error("[EVENTQUEUE] Caught exception: " + e); | ||
187 | return false; | ||
188 | } | ||
189 | |||
190 | return true; | ||
191 | } | ||
192 | |||
193 | #endregion | ||
194 | |||
195 | private void OnNewClient(IClientAPI client) | ||
196 | { | ||
197 | //client.OnLogout += ClientClosed; | ||
198 | } | ||
199 | |||
200 | // private void ClientClosed(IClientAPI client) | ||
201 | // { | ||
202 | // ClientClosed(client.AgentId); | ||
203 | // } | ||
204 | |||
205 | private void ClientClosed(UUID AgentID, Scene scene) | ||
206 | { | ||
207 | //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName); | ||
208 | |||
209 | int count = 0; | ||
210 | while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5) | ||
211 | { | ||
212 | Thread.Sleep(1000); | ||
213 | } | ||
214 | |||
215 | lock (queues) | ||
216 | { | ||
217 | queues.Remove(AgentID); | ||
218 | } | ||
219 | List<UUID> removeitems = new List<UUID>(); | ||
220 | lock (m_AvatarQueueUUIDMapping) | ||
221 | { | ||
222 | foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) | ||
223 | { | ||
224 | if (ky == AgentID) | ||
225 | { | ||
226 | removeitems.Add(ky); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | foreach (UUID ky in removeitems) | ||
231 | { | ||
232 | m_AvatarQueueUUIDMapping.Remove(ky); | ||
233 | MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/"); | ||
234 | } | ||
235 | |||
236 | } | ||
237 | UUID searchval = UUID.Zero; | ||
238 | |||
239 | removeitems.Clear(); | ||
240 | |||
241 | lock (m_QueueUUIDAvatarMapping) | ||
242 | { | ||
243 | foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) | ||
244 | { | ||
245 | searchval = m_QueueUUIDAvatarMapping[ky]; | ||
246 | |||
247 | if (searchval == AgentID) | ||
248 | { | ||
249 | removeitems.Add(ky); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | foreach (UUID ky in removeitems) | ||
254 | m_QueueUUIDAvatarMapping.Remove(ky); | ||
255 | |||
256 | } | ||
257 | } | ||
258 | |||
259 | private void MakeChildAgent(ScenePresence avatar) | ||
260 | { | ||
261 | //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); | ||
262 | //lock (m_ids) | ||
263 | // { | ||
264 | //if (m_ids.ContainsKey(avatar.UUID)) | ||
265 | //{ | ||
266 | // close the event queue. | ||
267 | //m_ids[avatar.UUID] = -1; | ||
268 | //} | ||
269 | //} | ||
270 | } | ||
271 | |||
272 | public void OnRegisterCaps(UUID agentID, Caps caps) | ||
273 | { | ||
274 | // Register an event queue for the client | ||
275 | |||
276 | //m_log.DebugFormat( | ||
277 | // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | ||
278 | // agentID, caps, m_scene.RegionInfo.RegionName); | ||
279 | |||
280 | // Let's instantiate a Queue for this agent right now | ||
281 | TryGetQueue(agentID); | ||
282 | |||
283 | string capsBase = "/CAPS/EQG/"; | ||
284 | UUID EventQueueGetUUID = UUID.Zero; | ||
285 | |||
286 | lock (m_AvatarQueueUUIDMapping) | ||
287 | { | ||
288 | // Reuse open queues. The client does! | ||
289 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
290 | { | ||
291 | //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | ||
292 | EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | EventQueueGetUUID = UUID.Random(); | ||
297 | //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | lock (m_QueueUUIDAvatarMapping) | ||
302 | { | ||
303 | if (!m_QueueUUIDAvatarMapping.ContainsKey(EventQueueGetUUID)) | ||
304 | m_QueueUUIDAvatarMapping.Add(EventQueueGetUUID, agentID); | ||
305 | } | ||
306 | |||
307 | lock (m_AvatarQueueUUIDMapping) | ||
308 | { | ||
309 | if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
310 | m_AvatarQueueUUIDMapping.Add(agentID, EventQueueGetUUID); | ||
311 | } | ||
312 | |||
313 | // Register this as a caps handler | ||
314 | caps.RegisterHandler("EventQueueGet", | ||
315 | new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/", | ||
316 | delegate(Hashtable m_dhttpMethod) | ||
317 | { | ||
318 | return ProcessQueue(m_dhttpMethod, agentID, caps); | ||
319 | })); | ||
320 | |||
321 | // This will persist this beyond the expiry of the caps handlers | ||
322 | MainServer.Instance.AddPollServiceHTTPHandler( | ||
323 | capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePoll, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID)); | ||
324 | |||
325 | Random rnd = new Random(Environment.TickCount); | ||
326 | lock (m_ids) | ||
327 | { | ||
328 | if (!m_ids.ContainsKey(agentID)) | ||
329 | m_ids.Add(agentID, rnd.Next(30000000)); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | public bool HasEvents(UUID requestID, UUID agentID) | ||
334 | { | ||
335 | // Don't use this, because of race conditions at agent closing time | ||
336 | //Queue<OSD> queue = TryGetQueue(agentID); | ||
337 | |||
338 | Queue<OSD> queue = GetQueue(agentID); | ||
339 | if (queue != null) | ||
340 | lock (queue) | ||
341 | { | ||
342 | if (queue.Count > 0) | ||
343 | return true; | ||
344 | else | ||
345 | return false; | ||
346 | } | ||
347 | return false; | ||
348 | } | ||
349 | |||
350 | public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) | ||
351 | { | ||
352 | Queue<OSD> queue = TryGetQueue(pAgentId); | ||
353 | OSD element; | ||
354 | lock (queue) | ||
355 | { | ||
356 | if (queue.Count == 0) | ||
357 | return NoEvents(requestID, pAgentId); | ||
358 | element = queue.Dequeue(); // 15s timeout | ||
359 | } | ||
360 | |||
361 | |||
362 | |||
363 | int thisID = 0; | ||
364 | lock (m_ids) | ||
365 | thisID = m_ids[pAgentId]; | ||
366 | |||
367 | OSDArray array = new OSDArray(); | ||
368 | if (element == null) // didn't have an event in 15s | ||
369 | { | ||
370 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
371 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
372 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | array.Add(element); | ||
377 | lock (queue) | ||
378 | { | ||
379 | while (queue.Count > 0) | ||
380 | { | ||
381 | array.Add(queue.Dequeue()); | ||
382 | thisID++; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | OSDMap events = new OSDMap(); | ||
388 | events.Add("events", array); | ||
389 | |||
390 | events.Add("id", new OSDInteger(thisID)); | ||
391 | lock (m_ids) | ||
392 | { | ||
393 | m_ids[pAgentId] = thisID + 1; | ||
394 | } | ||
395 | Hashtable responsedata = new Hashtable(); | ||
396 | responsedata["int_response_code"] = 200; | ||
397 | responsedata["content_type"] = "application/xml"; | ||
398 | responsedata["keepalive"] = false; | ||
399 | responsedata["reusecontext"] = false; | ||
400 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
401 | //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
402 | return responsedata; | ||
403 | } | ||
404 | |||
405 | public Hashtable NoEvents(UUID requestID, UUID agentID) | ||
406 | { | ||
407 | Hashtable responsedata = new Hashtable(); | ||
408 | responsedata["int_response_code"] = 502; | ||
409 | responsedata["content_type"] = "text/plain"; | ||
410 | responsedata["keepalive"] = false; | ||
411 | responsedata["reusecontext"] = false; | ||
412 | responsedata["str_response_string"] = "Upstream error: "; | ||
413 | responsedata["error_status_text"] = "Upstream error:"; | ||
414 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
415 | return responsedata; | ||
416 | } | ||
417 | |||
418 | public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | ||
419 | { | ||
420 | // TODO: this has to be redone to not busy-wait (and block the thread), | ||
421 | // TODO: as soon as we have a non-blocking way to handle HTTP-requests. | ||
422 | |||
423 | // if (m_log.IsDebugEnabled) | ||
424 | // { | ||
425 | // String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; | ||
426 | // foreach (object key in request.Keys) | ||
427 | // { | ||
428 | // debug += key.ToString() + "=" + request[key].ToString() + " "; | ||
429 | // } | ||
430 | // m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | ||
431 | // } | ||
432 | |||
433 | Queue<OSD> queue = TryGetQueue(agentID); | ||
434 | OSD element = queue.Dequeue(); // 15s timeout | ||
435 | |||
436 | Hashtable responsedata = new Hashtable(); | ||
437 | |||
438 | int thisID = 0; | ||
439 | lock (m_ids) | ||
440 | thisID = m_ids[agentID]; | ||
441 | |||
442 | if (element == null) | ||
443 | { | ||
444 | //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); | ||
445 | if (thisID == -1) // close-request | ||
446 | { | ||
447 | m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); | ||
448 | responsedata["int_response_code"] = 404; //501; //410; //404; | ||
449 | responsedata["content_type"] = "text/plain"; | ||
450 | responsedata["keepalive"] = false; | ||
451 | responsedata["str_response_string"] = "Closed EQG"; | ||
452 | return responsedata; | ||
453 | } | ||
454 | responsedata["int_response_code"] = 502; | ||
455 | responsedata["content_type"] = "text/plain"; | ||
456 | responsedata["keepalive"] = false; | ||
457 | responsedata["str_response_string"] = "Upstream error: "; | ||
458 | responsedata["error_status_text"] = "Upstream error:"; | ||
459 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
460 | return responsedata; | ||
461 | } | ||
462 | |||
463 | OSDArray array = new OSDArray(); | ||
464 | if (element == null) // didn't have an event in 15s | ||
465 | { | ||
466 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
467 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
468 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | array.Add(element); | ||
473 | while (queue.Count > 0) | ||
474 | { | ||
475 | array.Add(queue.Dequeue()); | ||
476 | thisID++; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | OSDMap events = new OSDMap(); | ||
481 | events.Add("events", array); | ||
482 | |||
483 | events.Add("id", new OSDInteger(thisID)); | ||
484 | lock (m_ids) | ||
485 | { | ||
486 | m_ids[agentID] = thisID + 1; | ||
487 | } | ||
488 | |||
489 | responsedata["int_response_code"] = 200; | ||
490 | responsedata["content_type"] = "application/xml"; | ||
491 | responsedata["keepalive"] = false; | ||
492 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
493 | //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
494 | |||
495 | return responsedata; | ||
496 | } | ||
497 | |||
498 | public Hashtable EventQueuePoll(Hashtable request) | ||
499 | { | ||
500 | return new Hashtable(); | ||
501 | } | ||
502 | |||
503 | public Hashtable EventQueuePath2(Hashtable request) | ||
504 | { | ||
505 | string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); | ||
506 | // pull off the last "/" in the path. | ||
507 | Hashtable responsedata = new Hashtable(); | ||
508 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
509 | capuuid = capuuid.Replace("/CAPS/EQG/", ""); | ||
510 | UUID AvatarID = UUID.Zero; | ||
511 | UUID capUUID = UUID.Zero; | ||
512 | |||
513 | // parse the path and search for the avatar with it registered | ||
514 | if (UUID.TryParse(capuuid, out capUUID)) | ||
515 | { | ||
516 | lock (m_QueueUUIDAvatarMapping) | ||
517 | { | ||
518 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
519 | { | ||
520 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
521 | } | ||
522 | } | ||
523 | if (AvatarID != UUID.Zero) | ||
524 | { | ||
525 | return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); | ||
526 | } | ||
527 | else | ||
528 | { | ||
529 | responsedata["int_response_code"] = 404; | ||
530 | responsedata["content_type"] = "text/plain"; | ||
531 | responsedata["keepalive"] = false; | ||
532 | responsedata["str_response_string"] = "Not Found"; | ||
533 | responsedata["error_status_text"] = "Not Found"; | ||
534 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
535 | return responsedata; | ||
536 | // return 404 | ||
537 | } | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | responsedata["int_response_code"] = 404; | ||
542 | responsedata["content_type"] = "text/plain"; | ||
543 | responsedata["keepalive"] = false; | ||
544 | responsedata["str_response_string"] = "Not Found"; | ||
545 | responsedata["error_status_text"] = "Not Found"; | ||
546 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
547 | return responsedata; | ||
548 | // return 404 | ||
549 | } | ||
550 | |||
551 | } | ||
552 | |||
553 | public OSD EventQueueFallBack(string path, OSD request, string endpoint) | ||
554 | { | ||
555 | // This is a fallback element to keep the client from loosing EventQueueGet | ||
556 | // Why does CAPS fail sometimes!? | ||
557 | m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); | ||
558 | string capuuid = path.Replace("/CAPS/EQG/",""); | ||
559 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
560 | |||
561 | // UUID AvatarID = UUID.Zero; | ||
562 | UUID capUUID = UUID.Zero; | ||
563 | if (UUID.TryParse(capuuid, out capUUID)) | ||
564 | { | ||
565 | /* Don't remove this yet code cleaners! | ||
566 | * Still testing this! | ||
567 | * | ||
568 | lock (m_QueueUUIDAvatarMapping) | ||
569 | { | ||
570 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
571 | { | ||
572 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | |||
577 | if (AvatarID != UUID.Zero) | ||
578 | { | ||
579 | // Repair the CAP! | ||
580 | //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); | ||
581 | //string capsBase = "/CAPS/EQG/"; | ||
582 | //caps.RegisterHandler("EventQueueGet", | ||
583 | //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", | ||
584 | //delegate(Hashtable m_dhttpMethod) | ||
585 | //{ | ||
586 | // return ProcessQueue(m_dhttpMethod, AvatarID, caps); | ||
587 | //})); | ||
588 | // start new ID sequence. | ||
589 | Random rnd = new Random(System.Environment.TickCount); | ||
590 | lock (m_ids) | ||
591 | { | ||
592 | if (!m_ids.ContainsKey(AvatarID)) | ||
593 | m_ids.Add(AvatarID, rnd.Next(30000000)); | ||
594 | } | ||
595 | |||
596 | |||
597 | int thisID = 0; | ||
598 | lock (m_ids) | ||
599 | thisID = m_ids[AvatarID]; | ||
600 | |||
601 | BlockingLLSDQueue queue = GetQueue(AvatarID); | ||
602 | OSDArray array = new OSDArray(); | ||
603 | LLSD element = queue.Dequeue(15000); // 15s timeout | ||
604 | if (element == null) | ||
605 | { | ||
606 | |||
607 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | array.Add(element); | ||
612 | while (queue.Count() > 0) | ||
613 | { | ||
614 | array.Add(queue.Dequeue(1)); | ||
615 | thisID++; | ||
616 | } | ||
617 | } | ||
618 | OSDMap events = new OSDMap(); | ||
619 | events.Add("events", array); | ||
620 | |||
621 | events.Add("id", new LLSDInteger(thisID)); | ||
622 | |||
623 | lock (m_ids) | ||
624 | { | ||
625 | m_ids[AvatarID] = thisID + 1; | ||
626 | } | ||
627 | |||
628 | return events; | ||
629 | } | ||
630 | else | ||
631 | { | ||
632 | return new LLSD(); | ||
633 | } | ||
634 | * | ||
635 | */ | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | //return new LLSD(); | ||
640 | } | ||
641 | |||
642 | return new OSDString("shutdown404!"); | ||
643 | } | ||
644 | |||
645 | public void DisableSimulator(ulong handle, UUID avatarID) | ||
646 | { | ||
647 | OSD item = EventQueueHelper.DisableSimulator(handle); | ||
648 | Enqueue(item, avatarID); | ||
649 | } | ||
650 | |||
651 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) | ||
652 | { | ||
653 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); | ||
654 | Enqueue(item, avatarID); | ||
655 | } | ||
656 | |||
657 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) | ||
658 | { | ||
659 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); | ||
660 | Enqueue(item, avatarID); | ||
661 | } | ||
662 | |||
663 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | ||
664 | IPEndPoint regionExternalEndPoint, | ||
665 | uint locationID, uint flags, string capsURL, | ||
666 | UUID avatarID) | ||
667 | { | ||
668 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, | ||
669 | locationID, flags, capsURL, avatarID); | ||
670 | Enqueue(item, avatarID); | ||
671 | } | ||
672 | |||
673 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | ||
674 | IPEndPoint newRegionExternalEndPoint, | ||
675 | string capsURL, UUID avatarID, UUID sessionID) | ||
676 | { | ||
677 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, | ||
678 | capsURL, avatarID, sessionID); | ||
679 | Enqueue(item, avatarID); | ||
680 | } | ||
681 | |||
682 | public void ChatterboxInvitation(UUID sessionID, string sessionName, | ||
683 | UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, | ||
684 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, | ||
685 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
686 | { | ||
687 | OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, | ||
688 | timeStamp, offline, parentEstateID, position, ttl, transactionID, | ||
689 | fromGroup, binaryBucket); | ||
690 | Enqueue(item, toAgent); | ||
691 | //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); | ||
692 | |||
693 | } | ||
694 | |||
695 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, | ||
696 | bool isModerator, bool textMute) | ||
697 | { | ||
698 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | ||
699 | isModerator, textMute); | ||
700 | Enqueue(item, toAgent); | ||
701 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | ||
702 | } | ||
703 | |||
704 | public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) | ||
705 | { | ||
706 | OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); | ||
707 | Enqueue(item, avatarID); | ||
708 | } | ||
709 | |||
710 | public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) | ||
711 | { | ||
712 | OSD item = EventQueueHelper.GroupMembership(groupUpdate); | ||
713 | Enqueue(item, avatarID); | ||
714 | } | ||
715 | public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) | ||
716 | { | ||
717 | OSD item = EventQueueHelper.PlacesQuery(groupUpdate); | ||
718 | Enqueue(item, avatarID); | ||
719 | } | ||
720 | |||
721 | public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono) | ||
722 | { | ||
723 | return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono); | ||
724 | } | ||
725 | |||
726 | public OSD BuildEvent(string eventName, OSD eventBody) | ||
727 | { | ||
728 | return EventQueueHelper.BuildEvent(eventName, eventBody); | ||
729 | } | ||
730 | } | ||
731 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs new file mode 100644 index 0000000..3f49aba --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs | |||
@@ -0,0 +1,399 @@ | |||
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.Net; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.Packets; | ||
32 | using OpenMetaverse.StructuredData; | ||
33 | using OpenMetaverse.Messages.Linden; | ||
34 | |||
35 | namespace OpenSim.Region.ClientStack.Linden | ||
36 | { | ||
37 | public class EventQueueHelper | ||
38 | { | ||
39 | private EventQueueHelper() {} // no construction possible, it's an utility class | ||
40 | |||
41 | private static byte[] ulongToByteArray(ulong uLongValue) | ||
42 | { | ||
43 | // Reverse endianness of RegionHandle | ||
44 | return new byte[] | ||
45 | { | ||
46 | (byte)((uLongValue >> 56) % 256), | ||
47 | (byte)((uLongValue >> 48) % 256), | ||
48 | (byte)((uLongValue >> 40) % 256), | ||
49 | (byte)((uLongValue >> 32) % 256), | ||
50 | (byte)((uLongValue >> 24) % 256), | ||
51 | (byte)((uLongValue >> 16) % 256), | ||
52 | (byte)((uLongValue >> 8) % 256), | ||
53 | (byte)(uLongValue % 256) | ||
54 | }; | ||
55 | } | ||
56 | |||
57 | // private static byte[] uintToByteArray(uint uIntValue) | ||
58 | // { | ||
59 | // byte[] result = new byte[4]; | ||
60 | // Utils.UIntToBytesBig(uIntValue, result, 0); | ||
61 | // return result; | ||
62 | // } | ||
63 | |||
64 | public static OSD BuildEvent(string eventName, OSD eventBody) | ||
65 | { | ||
66 | OSDMap llsdEvent = new OSDMap(2); | ||
67 | llsdEvent.Add("message", new OSDString(eventName)); | ||
68 | llsdEvent.Add("body", eventBody); | ||
69 | |||
70 | return llsdEvent; | ||
71 | } | ||
72 | |||
73 | public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint) | ||
74 | { | ||
75 | OSDMap llsdSimInfo = new OSDMap(3); | ||
76 | |||
77 | llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); | ||
78 | llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); | ||
79 | llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); | ||
80 | |||
81 | OSDArray arr = new OSDArray(1); | ||
82 | arr.Add(llsdSimInfo); | ||
83 | |||
84 | OSDMap llsdBody = new OSDMap(1); | ||
85 | llsdBody.Add("SimulatorInfo", arr); | ||
86 | |||
87 | return BuildEvent("EnableSimulator", llsdBody); | ||
88 | } | ||
89 | |||
90 | public static OSD DisableSimulator(ulong handle) | ||
91 | { | ||
92 | //OSDMap llsdSimInfo = new OSDMap(1); | ||
93 | |||
94 | //llsdSimInfo.Add("Handle", new OSDBinary(regionHandleToByteArray(handle))); | ||
95 | |||
96 | //OSDArray arr = new OSDArray(1); | ||
97 | //arr.Add(llsdSimInfo); | ||
98 | |||
99 | OSDMap llsdBody = new OSDMap(0); | ||
100 | //llsdBody.Add("SimulatorInfo", arr); | ||
101 | |||
102 | return BuildEvent("DisableSimulator", llsdBody); | ||
103 | } | ||
104 | |||
105 | public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | ||
106 | IPEndPoint newRegionExternalEndPoint, | ||
107 | string capsURL, UUID agentID, UUID sessionID) | ||
108 | { | ||
109 | OSDArray lookAtArr = new OSDArray(3); | ||
110 | lookAtArr.Add(OSD.FromReal(lookAt.X)); | ||
111 | lookAtArr.Add(OSD.FromReal(lookAt.Y)); | ||
112 | lookAtArr.Add(OSD.FromReal(lookAt.Z)); | ||
113 | |||
114 | OSDArray positionArr = new OSDArray(3); | ||
115 | positionArr.Add(OSD.FromReal(pos.X)); | ||
116 | positionArr.Add(OSD.FromReal(pos.Y)); | ||
117 | positionArr.Add(OSD.FromReal(pos.Z)); | ||
118 | |||
119 | OSDMap infoMap = new OSDMap(2); | ||
120 | infoMap.Add("LookAt", lookAtArr); | ||
121 | infoMap.Add("Position", positionArr); | ||
122 | |||
123 | OSDArray infoArr = new OSDArray(1); | ||
124 | infoArr.Add(infoMap); | ||
125 | |||
126 | OSDMap agentDataMap = new OSDMap(2); | ||
127 | agentDataMap.Add("AgentID", OSD.FromUUID(agentID)); | ||
128 | agentDataMap.Add("SessionID", OSD.FromUUID(sessionID)); | ||
129 | |||
130 | OSDArray agentDataArr = new OSDArray(1); | ||
131 | agentDataArr.Add(agentDataMap); | ||
132 | |||
133 | OSDMap regionDataMap = new OSDMap(4); | ||
134 | regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); | ||
135 | regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); | ||
136 | regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); | ||
137 | regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); | ||
138 | |||
139 | OSDArray regionDataArr = new OSDArray(1); | ||
140 | regionDataArr.Add(regionDataMap); | ||
141 | |||
142 | OSDMap llsdBody = new OSDMap(3); | ||
143 | llsdBody.Add("Info", infoArr); | ||
144 | llsdBody.Add("AgentData", agentDataArr); | ||
145 | llsdBody.Add("RegionData", regionDataArr); | ||
146 | |||
147 | return BuildEvent("CrossedRegion", llsdBody); | ||
148 | } | ||
149 | |||
150 | public static OSD TeleportFinishEvent( | ||
151 | ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, | ||
152 | uint locationID, uint flags, string capsURL, UUID agentID) | ||
153 | { | ||
154 | OSDMap info = new OSDMap(); | ||
155 | info.Add("AgentID", OSD.FromUUID(agentID)); | ||
156 | info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? | ||
157 | info.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(regionHandle))); | ||
158 | info.Add("SeedCapability", OSD.FromString(capsURL)); | ||
159 | info.Add("SimAccess", OSD.FromInteger(simAccess)); | ||
160 | info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); | ||
161 | info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); | ||
162 | info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation | ||
163 | |||
164 | OSDArray infoArr = new OSDArray(); | ||
165 | infoArr.Add(info); | ||
166 | |||
167 | OSDMap body = new OSDMap(); | ||
168 | body.Add("Info", infoArr); | ||
169 | |||
170 | return BuildEvent("TeleportFinish", body); | ||
171 | } | ||
172 | |||
173 | public static OSD ScriptRunningReplyEvent(UUID objectID, UUID itemID, bool running, bool mono) | ||
174 | { | ||
175 | OSDMap script = new OSDMap(); | ||
176 | script.Add("ObjectID", OSD.FromUUID(objectID)); | ||
177 | script.Add("ItemID", OSD.FromUUID(itemID)); | ||
178 | script.Add("Running", OSD.FromBoolean(running)); | ||
179 | script.Add("Mono", OSD.FromBoolean(mono)); | ||
180 | |||
181 | OSDArray scriptArr = new OSDArray(); | ||
182 | scriptArr.Add(script); | ||
183 | |||
184 | OSDMap body = new OSDMap(); | ||
185 | body.Add("Script", scriptArr); | ||
186 | |||
187 | return BuildEvent("ScriptRunningReply", body); | ||
188 | } | ||
189 | |||
190 | public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap) | ||
191 | { | ||
192 | OSDMap body = new OSDMap(3); | ||
193 | body.Add("agent-id", new OSDUUID(agentID)); | ||
194 | body.Add("sim-ip-and-port", new OSDString(simIpAndPort)); | ||
195 | body.Add("seed-capability", new OSDString(seedcap)); | ||
196 | |||
197 | return BuildEvent("EstablishAgentCommunication", body); | ||
198 | } | ||
199 | |||
200 | public static OSD KeepAliveEvent() | ||
201 | { | ||
202 | return BuildEvent("FAKEEVENT", new OSDMap()); | ||
203 | } | ||
204 | |||
205 | public static OSD AgentParams(UUID agentID, bool checkEstate, int godLevel, bool limitedToEstate) | ||
206 | { | ||
207 | OSDMap body = new OSDMap(4); | ||
208 | |||
209 | body.Add("agent_id", new OSDUUID(agentID)); | ||
210 | body.Add("check_estate", new OSDInteger(checkEstate ? 1 : 0)); | ||
211 | body.Add("god_level", new OSDInteger(godLevel)); | ||
212 | body.Add("limited_to_estate", new OSDInteger(limitedToEstate ? 1 : 0)); | ||
213 | |||
214 | return body; | ||
215 | } | ||
216 | |||
217 | public static OSD InstantMessageParams(UUID fromAgent, string message, UUID toAgent, | ||
218 | string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID, | ||
219 | Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
220 | { | ||
221 | OSDMap messageParams = new OSDMap(15); | ||
222 | messageParams.Add("type", new OSDInteger((int)dialog)); | ||
223 | |||
224 | OSDArray positionArray = new OSDArray(3); | ||
225 | positionArray.Add(OSD.FromReal(position.X)); | ||
226 | positionArray.Add(OSD.FromReal(position.Y)); | ||
227 | positionArray.Add(OSD.FromReal(position.Z)); | ||
228 | messageParams.Add("position", positionArray); | ||
229 | |||
230 | messageParams.Add("region_id", new OSDUUID(UUID.Zero)); | ||
231 | messageParams.Add("to_id", new OSDUUID(toAgent)); | ||
232 | messageParams.Add("source", new OSDInteger(0)); | ||
233 | |||
234 | OSDMap data = new OSDMap(1); | ||
235 | data.Add("binary_bucket", OSD.FromBinary(binaryBucket)); | ||
236 | messageParams.Add("data", data); | ||
237 | messageParams.Add("message", new OSDString(message)); | ||
238 | messageParams.Add("id", new OSDUUID(transactionID)); | ||
239 | messageParams.Add("from_name", new OSDString(fromName)); | ||
240 | messageParams.Add("timestamp", new OSDInteger((int)timeStamp)); | ||
241 | messageParams.Add("offline", new OSDInteger(offline ? 1 : 0)); | ||
242 | messageParams.Add("parent_estate_id", new OSDInteger(parentEstateID)); | ||
243 | messageParams.Add("ttl", new OSDInteger((int)ttl)); | ||
244 | messageParams.Add("from_id", new OSDUUID(fromAgent)); | ||
245 | messageParams.Add("from_group", new OSDInteger(fromGroup ? 1 : 0)); | ||
246 | |||
247 | return messageParams; | ||
248 | } | ||
249 | |||
250 | public static OSD InstantMessage(UUID fromAgent, string message, UUID toAgent, | ||
251 | string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID, | ||
252 | Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket, | ||
253 | bool checkEstate, int godLevel, bool limitedToEstate) | ||
254 | { | ||
255 | OSDMap im = new OSDMap(2); | ||
256 | im.Add("message_params", InstantMessageParams(fromAgent, message, toAgent, | ||
257 | fromName, dialog, timeStamp, offline, parentEstateID, | ||
258 | position, ttl, transactionID, fromGroup, binaryBucket)); | ||
259 | |||
260 | im.Add("agent_params", AgentParams(fromAgent, checkEstate, godLevel, limitedToEstate)); | ||
261 | |||
262 | return im; | ||
263 | } | ||
264 | |||
265 | |||
266 | public static OSD ChatterboxInvitation(UUID sessionID, string sessionName, | ||
267 | UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, | ||
268 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, | ||
269 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
270 | { | ||
271 | OSDMap body = new OSDMap(5); | ||
272 | body.Add("session_id", new OSDUUID(sessionID)); | ||
273 | body.Add("from_name", new OSDString(fromName)); | ||
274 | body.Add("session_name", new OSDString(sessionName)); | ||
275 | body.Add("from_id", new OSDUUID(fromAgent)); | ||
276 | |||
277 | body.Add("instantmessage", InstantMessage(fromAgent, message, toAgent, | ||
278 | fromName, dialog, timeStamp, offline, parentEstateID, position, | ||
279 | ttl, transactionID, fromGroup, binaryBucket, true, 0, true)); | ||
280 | |||
281 | OSDMap chatterboxInvitation = new OSDMap(2); | ||
282 | chatterboxInvitation.Add("message", new OSDString("ChatterBoxInvitation")); | ||
283 | chatterboxInvitation.Add("body", body); | ||
284 | return chatterboxInvitation; | ||
285 | } | ||
286 | |||
287 | public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID, | ||
288 | UUID agentID, bool canVoiceChat, bool isModerator, bool textMute) | ||
289 | { | ||
290 | OSDMap body = new OSDMap(); | ||
291 | OSDMap agentUpdates = new OSDMap(); | ||
292 | OSDMap infoDetail = new OSDMap(); | ||
293 | OSDMap mutes = new OSDMap(); | ||
294 | |||
295 | mutes.Add("text", OSD.FromBoolean(textMute)); | ||
296 | infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat)); | ||
297 | infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator)); | ||
298 | infoDetail.Add("mutes", mutes); | ||
299 | OSDMap info = new OSDMap(); | ||
300 | info.Add("info", infoDetail); | ||
301 | agentUpdates.Add(agentID.ToString(), info); | ||
302 | body.Add("agent_updates", agentUpdates); | ||
303 | body.Add("session_id", OSD.FromUUID(sessionID)); | ||
304 | body.Add("updates", new OSD()); | ||
305 | |||
306 | OSDMap chatterBoxSessionAgentListUpdates = new OSDMap(); | ||
307 | chatterBoxSessionAgentListUpdates.Add("message", OSD.FromString("ChatterBoxSessionAgentListUpdates")); | ||
308 | chatterBoxSessionAgentListUpdates.Add("body", body); | ||
309 | |||
310 | return chatterBoxSessionAgentListUpdates; | ||
311 | } | ||
312 | |||
313 | public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket) | ||
314 | { | ||
315 | OSDMap groupUpdate = new OSDMap(); | ||
316 | groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate")); | ||
317 | |||
318 | OSDMap body = new OSDMap(); | ||
319 | OSDArray agentData = new OSDArray(); | ||
320 | OSDMap agentDataMap = new OSDMap(); | ||
321 | agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID)); | ||
322 | agentData.Add(agentDataMap); | ||
323 | body.Add("AgentData", agentData); | ||
324 | |||
325 | OSDArray groupData = new OSDArray(); | ||
326 | |||
327 | foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData) | ||
328 | { | ||
329 | OSDMap groupDataMap = new OSDMap(); | ||
330 | groupDataMap.Add("ListInProfile", OSD.FromBoolean(false)); | ||
331 | groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID)); | ||
332 | groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID)); | ||
333 | groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution)); | ||
334 | groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers))); | ||
335 | groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName))); | ||
336 | groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices)); | ||
337 | |||
338 | groupData.Add(groupDataMap); | ||
339 | |||
340 | } | ||
341 | body.Add("GroupData", groupData); | ||
342 | groupUpdate.Add("body", body); | ||
343 | |||
344 | return groupUpdate; | ||
345 | } | ||
346 | |||
347 | public static OSD PlacesQuery(PlacesReplyPacket PlacesReply) | ||
348 | { | ||
349 | OSDMap placesReply = new OSDMap(); | ||
350 | placesReply.Add("message", OSD.FromString("PlacesReplyMessage")); | ||
351 | |||
352 | OSDMap body = new OSDMap(); | ||
353 | OSDArray agentData = new OSDArray(); | ||
354 | OSDMap agentDataMap = new OSDMap(); | ||
355 | agentDataMap.Add("AgentID", OSD.FromUUID(PlacesReply.AgentData.AgentID)); | ||
356 | agentDataMap.Add("QueryID", OSD.FromUUID(PlacesReply.AgentData.QueryID)); | ||
357 | agentDataMap.Add("TransactionID", OSD.FromUUID(PlacesReply.TransactionData.TransactionID)); | ||
358 | agentData.Add(agentDataMap); | ||
359 | body.Add("AgentData", agentData); | ||
360 | |||
361 | OSDArray QueryData = new OSDArray(); | ||
362 | |||
363 | foreach (PlacesReplyPacket.QueryDataBlock groupDataBlock in PlacesReply.QueryData) | ||
364 | { | ||
365 | OSDMap QueryDataMap = new OSDMap(); | ||
366 | QueryDataMap.Add("ActualArea", OSD.FromInteger(groupDataBlock.ActualArea)); | ||
367 | QueryDataMap.Add("BillableArea", OSD.FromInteger(groupDataBlock.BillableArea)); | ||
368 | QueryDataMap.Add("Description", OSD.FromBinary(groupDataBlock.Desc)); | ||
369 | QueryDataMap.Add("Dwell", OSD.FromInteger((int)groupDataBlock.Dwell)); | ||
370 | QueryDataMap.Add("Flags", OSD.FromString(Convert.ToString(groupDataBlock.Flags))); | ||
371 | QueryDataMap.Add("GlobalX", OSD.FromInteger((int)groupDataBlock.GlobalX)); | ||
372 | QueryDataMap.Add("GlobalY", OSD.FromInteger((int)groupDataBlock.GlobalY)); | ||
373 | QueryDataMap.Add("GlobalZ", OSD.FromInteger((int)groupDataBlock.GlobalZ)); | ||
374 | QueryDataMap.Add("Name", OSD.FromBinary(groupDataBlock.Name)); | ||
375 | QueryDataMap.Add("OwnerID", OSD.FromUUID(groupDataBlock.OwnerID)); | ||
376 | QueryDataMap.Add("SimName", OSD.FromBinary(groupDataBlock.SimName)); | ||
377 | QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID)); | ||
378 | QueryDataMap.Add("ProductSku", OSD.FromInteger(0)); | ||
379 | QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price)); | ||
380 | |||
381 | QueryData.Add(QueryDataMap); | ||
382 | } | ||
383 | body.Add("QueryData", QueryData); | ||
384 | placesReply.Add("QueryData[]", body); | ||
385 | |||
386 | return placesReply; | ||
387 | } | ||
388 | |||
389 | public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage) | ||
390 | { | ||
391 | OSDMap message = new OSDMap(); | ||
392 | message.Add("message", OSD.FromString("ParcelProperties")); | ||
393 | OSD message_body = parcelPropertiesMessage.Serialize(); | ||
394 | message.Add("body", message_body); | ||
395 | return message; | ||
396 | } | ||
397 | |||
398 | } | ||
399 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs new file mode 100644 index 0000000..e0807ee --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |||
@@ -0,0 +1,139 @@ | |||
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.Capabilities.Handlers; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | |||
48 | namespace OpenSim.Region.ClientStack.Linden | ||
49 | { | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
51 | public class GetMeshModule : INonSharedRegionModule | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private Scene m_scene; | ||
57 | private IAssetService m_AssetService; | ||
58 | private bool m_Enabled = true; | ||
59 | private string m_URL; | ||
60 | |||
61 | #region IRegionModuleBase Members | ||
62 | |||
63 | public Type ReplaceableInterface | ||
64 | { | ||
65 | get { return null; } | ||
66 | } | ||
67 | |||
68 | public void Initialise(IConfigSource source) | ||
69 | { | ||
70 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
71 | if (config == null) | ||
72 | return; | ||
73 | |||
74 | m_URL = config.GetString("Cap_GetMesh", string.Empty); | ||
75 | // Cap doesn't exist | ||
76 | if (m_URL != string.Empty) | ||
77 | m_Enabled = true; | ||
78 | } | ||
79 | |||
80 | public void AddRegion(Scene pScene) | ||
81 | { | ||
82 | if (!m_Enabled) | ||
83 | return; | ||
84 | |||
85 | m_scene = pScene; | ||
86 | } | ||
87 | |||
88 | public void RemoveRegion(Scene scene) | ||
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 scene) | ||
98 | { | ||
99 | if (!m_Enabled) | ||
100 | return; | ||
101 | |||
102 | m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
103 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
104 | } | ||
105 | |||
106 | |||
107 | public void Close() { } | ||
108 | |||
109 | public string Name { get { return "GetMeshModule"; } } | ||
110 | |||
111 | #endregion | ||
112 | |||
113 | |||
114 | public void RegisterCaps(UUID agentID, Caps caps) | ||
115 | { | ||
116 | UUID capID = UUID.Random(); | ||
117 | |||
118 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | ||
119 | if (m_URL == "localhost") | ||
120 | { | ||
121 | m_log.InfoFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
122 | GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); | ||
123 | IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), | ||
124 | delegate(Hashtable m_dhttpMethod) | ||
125 | { | ||
126 | return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null); | ||
127 | }); | ||
128 | |||
129 | caps.RegisterHandler("GetMesh", reqHandler); | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | m_log.InfoFormat("[GETMESH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
134 | caps.RegisterHandler("GetMesh", m_URL); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | } | ||
139 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs new file mode 100644 index 0000000..35eedb4 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -0,0 +1,142 @@ | |||
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")] | ||
55 | public class GetTextureModule : INonSharedRegionModule | ||
56 | { | ||
57 | private static readonly ILog m_log = | ||
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | private Scene m_scene; | ||
60 | private IAssetService m_assetService; | ||
61 | |||
62 | private bool m_Enabled = false; | ||
63 | |||
64 | // TODO: Change this to a config option | ||
65 | const string REDIRECT_URL = null; | ||
66 | |||
67 | private string m_URL; | ||
68 | |||
69 | #region ISharedRegionModule Members | ||
70 | |||
71 | public void Initialise(IConfigSource source) | ||
72 | { | ||
73 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
74 | if (config == null) | ||
75 | return; | ||
76 | |||
77 | m_URL = config.GetString("Cap_GetTexture", string.Empty); | ||
78 | // Cap doesn't exist | ||
79 | if (m_URL != string.Empty) | ||
80 | m_Enabled = true; | ||
81 | } | ||
82 | |||
83 | public void AddRegion(Scene s) | ||
84 | { | ||
85 | if (!m_Enabled) | ||
86 | return; | ||
87 | |||
88 | m_scene = s; | ||
89 | } | ||
90 | |||
91 | public void RemoveRegion(Scene s) | ||
92 | { | ||
93 | if (!m_Enabled) | ||
94 | return; | ||
95 | |||
96 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
97 | m_scene = null; | ||
98 | } | ||
99 | |||
100 | public void RegionLoaded(Scene s) | ||
101 | { | ||
102 | if (!m_Enabled) | ||
103 | return; | ||
104 | |||
105 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
106 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
107 | } | ||
108 | |||
109 | public void PostInitialise() | ||
110 | { | ||
111 | } | ||
112 | |||
113 | public void Close() { } | ||
114 | |||
115 | public string Name { get { return "GetTextureModule"; } } | ||
116 | |||
117 | public Type ReplaceableInterface | ||
118 | { | ||
119 | get { return null; } | ||
120 | } | ||
121 | |||
122 | #endregion | ||
123 | |||
124 | public void RegisterCaps(UUID agentID, Caps caps) | ||
125 | { | ||
126 | UUID capID = UUID.Random(); | ||
127 | |||
128 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | ||
129 | if (m_URL == "localhost") | ||
130 | { | ||
131 | m_log.InfoFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
132 | caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService)); | ||
133 | } | ||
134 | else | ||
135 | { | ||
136 | m_log.InfoFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
137 | caps.RegisterHandler("GetTexture", m_URL); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | } | ||
142 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs new file mode 100644 index 0000000..b7e79cc --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs | |||
@@ -0,0 +1,275 @@ | |||
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 | |||
48 | namespace OpenSim.Region.ClientStack.Linden | ||
49 | { | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
51 | public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule | ||
52 | { | ||
53 | // private static readonly ILog m_log = | ||
54 | // 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 | |||
61 | #region IRegionModuleBase Members | ||
62 | |||
63 | |||
64 | public Type ReplaceableInterface | ||
65 | { | ||
66 | get { return null; } | ||
67 | } | ||
68 | |||
69 | public void Initialise(IConfigSource source) | ||
70 | { | ||
71 | IConfig meshConfig = source.Configs["Mesh"]; | ||
72 | if (meshConfig == null) | ||
73 | return; | ||
74 | |||
75 | m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true); | ||
76 | } | ||
77 | |||
78 | public void AddRegion(Scene pScene) | ||
79 | { | ||
80 | m_scene = pScene; | ||
81 | } | ||
82 | |||
83 | public void RemoveRegion(Scene scene) | ||
84 | { | ||
85 | |||
86 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
87 | m_scene = null; | ||
88 | } | ||
89 | |||
90 | public void RegionLoaded(Scene scene) | ||
91 | { | ||
92 | |||
93 | // m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
94 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
95 | } | ||
96 | |||
97 | #endregion | ||
98 | |||
99 | |||
100 | #region IRegionModule Members | ||
101 | |||
102 | |||
103 | |||
104 | public void Close() { } | ||
105 | |||
106 | public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } } | ||
107 | |||
108 | |||
109 | public void RegisterCaps(UUID agentID, Caps caps) | ||
110 | { | ||
111 | if(!m_enabled) | ||
112 | return; | ||
113 | |||
114 | UUID capID = UUID.Random(); | ||
115 | |||
116 | // m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID); | ||
117 | caps.RegisterHandler("NewFileAgentInventoryVariablePrice", | ||
118 | |||
119 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST", | ||
120 | "/CAPS/" + capID.ToString(), | ||
121 | delegate(LLSDAssetUploadRequest req) | ||
122 | { | ||
123 | return NewAgentInventoryRequest(req,agentID); | ||
124 | })); | ||
125 | |||
126 | } | ||
127 | |||
128 | #endregion | ||
129 | |||
130 | public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID) | ||
131 | { | ||
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 and | ||
135 | |||
136 | |||
137 | //if (llsdRequest.asset_type == "texture" || | ||
138 | // llsdRequest.asset_type == "animation" || | ||
139 | // llsdRequest.asset_type == "sound") | ||
140 | // { | ||
141 | IClientAPI client = null; | ||
142 | |||
143 | |||
144 | IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>(); | ||
145 | |||
146 | if (mm != null) | ||
147 | { | ||
148 | if (m_scene.TryGetClient(agentID, out client)) | ||
149 | { | ||
150 | if (!mm.UploadCovered(client, mm.UploadCharge)) | ||
151 | { | ||
152 | if (client != null) | ||
153 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | ||
154 | |||
155 | LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
156 | errorResponse.rsvp = ""; | ||
157 | errorResponse.state = "error"; | ||
158 | return errorResponse; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | // } | ||
163 | |||
164 | |||
165 | |||
166 | string assetName = llsdRequest.name; | ||
167 | string assetDes = llsdRequest.description; | ||
168 | string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/"; | ||
169 | UUID newAsset = UUID.Random(); | ||
170 | UUID newInvItem = UUID.Random(); | ||
171 | UUID parentFolder = llsdRequest.folder_id; | ||
172 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/"; | ||
173 | |||
174 | AssetUploader uploader = | ||
175 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | ||
176 | llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile); | ||
177 | MainServer.Instance.AddStreamHandler( | ||
178 | new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
179 | |||
180 | string protocol = "http://"; | ||
181 | |||
182 | if (MainServer.Instance.UseSSL) | ||
183 | protocol = "https://"; | ||
184 | |||
185 | string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase + | ||
186 | uploaderPath; | ||
187 | |||
188 | |||
189 | LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
190 | |||
191 | |||
192 | uploadResponse.rsvp = uploaderURL; | ||
193 | uploadResponse.state = "upload"; | ||
194 | uploadResponse.resource_cost = 0; | ||
195 | uploadResponse.upload_price = 0; | ||
196 | |||
197 | uploader.OnUpLoad += //UploadCompleteHandler; | ||
198 | |||
199 | delegate( | ||
200 | string passetName, string passetDescription, UUID passetID, | ||
201 | UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType, | ||
202 | string passetType) | ||
203 | { | ||
204 | UploadCompleteHandler(passetName, passetDescription, passetID, | ||
205 | pinventoryItem, pparentFolder, pdata, pinventoryType, | ||
206 | passetType,agentID); | ||
207 | }; | ||
208 | return uploadResponse; | ||
209 | } | ||
210 | |||
211 | |||
212 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | ||
213 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | ||
214 | string assetType,UUID AgentID) | ||
215 | { | ||
216 | |||
217 | sbyte assType = 0; | ||
218 | sbyte inType = 0; | ||
219 | |||
220 | if (inventoryType == "sound") | ||
221 | { | ||
222 | inType = 1; | ||
223 | assType = 1; | ||
224 | } | ||
225 | else if (inventoryType == "animation") | ||
226 | { | ||
227 | inType = 19; | ||
228 | assType = 20; | ||
229 | } | ||
230 | else if (inventoryType == "wearable") | ||
231 | { | ||
232 | inType = 18; | ||
233 | switch (assetType) | ||
234 | { | ||
235 | case "bodypart": | ||
236 | assType = 13; | ||
237 | break; | ||
238 | case "clothing": | ||
239 | assType = 5; | ||
240 | break; | ||
241 | } | ||
242 | } | ||
243 | else if (inventoryType == "mesh") | ||
244 | { | ||
245 | inType = (sbyte)InventoryType.Mesh; | ||
246 | assType = (sbyte)AssetType.Mesh; | ||
247 | } | ||
248 | |||
249 | AssetBase asset; | ||
250 | asset = new AssetBase(assetID, assetName, assType, AgentID.ToString()); | ||
251 | asset.Data = data; | ||
252 | |||
253 | if (m_scene.AssetService != null) | ||
254 | m_scene.AssetService.Store(asset); | ||
255 | |||
256 | InventoryItemBase item = new InventoryItemBase(); | ||
257 | item.Owner = AgentID; | ||
258 | item.CreatorId = AgentID.ToString(); | ||
259 | item.ID = inventoryItem; | ||
260 | item.AssetID = asset.FullID; | ||
261 | item.Description = assetDescription; | ||
262 | item.Name = assetName; | ||
263 | item.AssetType = assType; | ||
264 | item.InvType = inType; | ||
265 | item.Folder = parentFolder; | ||
266 | item.CurrentPermissions = (uint)PermissionMask.All; | ||
267 | item.BasePermissions = (uint)PermissionMask.All; | ||
268 | item.EveryOnePermissions = 0; | ||
269 | item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); | ||
270 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
271 | m_scene.AddInventoryItem(item); | ||
272 | |||
273 | } | ||
274 | } | ||
275 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs new file mode 100644 index 0000000..15139a3 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs | |||
@@ -0,0 +1,370 @@ | |||
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.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Servers; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
41 | |||
42 | namespace OpenSim.Region.ClientStack.Linden | ||
43 | { | ||
44 | public class ObjectAdd : IRegionModule | ||
45 | { | ||
46 | // private static readonly ILog m_log = | ||
47 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private Scene m_scene; | ||
50 | #region IRegionModule Members | ||
51 | |||
52 | public void Initialise(Scene pScene, IConfigSource pSource) | ||
53 | { | ||
54 | m_scene = pScene; | ||
55 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
56 | } | ||
57 | |||
58 | public void PostInitialise() | ||
59 | { | ||
60 | |||
61 | } | ||
62 | |||
63 | public void RegisterCaps(UUID agentID, Caps caps) | ||
64 | { | ||
65 | UUID capuuid = UUID.Random(); | ||
66 | |||
67 | // m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/"); | ||
68 | |||
69 | caps.RegisterHandler("ObjectAdd", | ||
70 | new RestHTTPHandler("POST", "/CAPS/OA/" + capuuid + "/", | ||
71 | delegate(Hashtable m_dhttpMethod) | ||
72 | { | ||
73 | return ProcessAdd(m_dhttpMethod, agentID, caps); | ||
74 | })); | ||
75 | } | ||
76 | |||
77 | public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap) | ||
78 | { | ||
79 | Hashtable responsedata = new Hashtable(); | ||
80 | responsedata["int_response_code"] = 400; //501; //410; //404; | ||
81 | responsedata["content_type"] = "text/plain"; | ||
82 | responsedata["keepalive"] = false; | ||
83 | responsedata["str_response_string"] = "Request wasn't what was expected"; | ||
84 | ScenePresence avatar; | ||
85 | |||
86 | if (!m_scene.TryGetScenePresence(AgentId, out avatar)) | ||
87 | return responsedata; | ||
88 | |||
89 | |||
90 | OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]); | ||
91 | //UUID session_id = UUID.Zero; | ||
92 | bool bypass_raycast = false; | ||
93 | uint everyone_mask = 0; | ||
94 | uint group_mask = 0; | ||
95 | uint next_owner_mask = 0; | ||
96 | uint flags = 0; | ||
97 | UUID group_id = UUID.Zero; | ||
98 | int hollow = 0; | ||
99 | int material = 0; | ||
100 | int p_code = 0; | ||
101 | int path_begin = 0; | ||
102 | int path_curve = 0; | ||
103 | int path_end = 0; | ||
104 | int path_radius_offset = 0; | ||
105 | int path_revolutions = 0; | ||
106 | int path_scale_x = 0; | ||
107 | int path_scale_y = 0; | ||
108 | int path_shear_x = 0; | ||
109 | int path_shear_y = 0; | ||
110 | int path_skew = 0; | ||
111 | int path_taper_x = 0; | ||
112 | int path_taper_y = 0; | ||
113 | int path_twist = 0; | ||
114 | int path_twist_begin = 0; | ||
115 | int profile_begin = 0; | ||
116 | int profile_curve = 0; | ||
117 | int profile_end = 0; | ||
118 | Vector3 ray_end = Vector3.Zero; | ||
119 | bool ray_end_is_intersection = false; | ||
120 | Vector3 ray_start = Vector3.Zero; | ||
121 | UUID ray_target_id = UUID.Zero; | ||
122 | Quaternion rotation = Quaternion.Identity; | ||
123 | Vector3 scale = Vector3.Zero; | ||
124 | int state = 0; | ||
125 | |||
126 | if (r.Type != OSDType.Map) // not a proper req | ||
127 | return responsedata; | ||
128 | |||
129 | OSDMap rm = (OSDMap)r; | ||
130 | |||
131 | if (rm.ContainsKey("ObjectData")) //v2 | ||
132 | { | ||
133 | if (rm["ObjectData"].Type != OSDType.Map) | ||
134 | { | ||
135 | responsedata["str_response_string"] = "Has ObjectData key, but data not in expected format"; | ||
136 | return responsedata; | ||
137 | } | ||
138 | |||
139 | OSDMap ObjMap = (OSDMap) rm["ObjectData"]; | ||
140 | |||
141 | bypass_raycast = ObjMap["BypassRaycast"].AsBoolean(); | ||
142 | everyone_mask = readuintval(ObjMap["EveryoneMask"]); | ||
143 | flags = readuintval(ObjMap["Flags"]); | ||
144 | group_mask = readuintval(ObjMap["GroupMask"]); | ||
145 | material = ObjMap["Material"].AsInteger(); | ||
146 | next_owner_mask = readuintval(ObjMap["NextOwnerMask"]); | ||
147 | p_code = ObjMap["PCode"].AsInteger(); | ||
148 | |||
149 | if (ObjMap.ContainsKey("Path")) | ||
150 | { | ||
151 | if (ObjMap["Path"].Type != OSDType.Map) | ||
152 | { | ||
153 | responsedata["str_response_string"] = "Has Path key, but data not in expected format"; | ||
154 | return responsedata; | ||
155 | } | ||
156 | |||
157 | OSDMap PathMap = (OSDMap)ObjMap["Path"]; | ||
158 | path_begin = PathMap["Begin"].AsInteger(); | ||
159 | path_curve = PathMap["Curve"].AsInteger(); | ||
160 | path_end = PathMap["End"].AsInteger(); | ||
161 | path_radius_offset = PathMap["RadiusOffset"].AsInteger(); | ||
162 | path_revolutions = PathMap["Revolutions"].AsInteger(); | ||
163 | path_scale_x = PathMap["ScaleX"].AsInteger(); | ||
164 | path_scale_y = PathMap["ScaleY"].AsInteger(); | ||
165 | path_shear_x = PathMap["ShearX"].AsInteger(); | ||
166 | path_shear_y = PathMap["ShearY"].AsInteger(); | ||
167 | path_skew = PathMap["Skew"].AsInteger(); | ||
168 | path_taper_x = PathMap["TaperX"].AsInteger(); | ||
169 | path_taper_y = PathMap["TaperY"].AsInteger(); | ||
170 | path_twist = PathMap["Twist"].AsInteger(); | ||
171 | path_twist_begin = PathMap["TwistBegin"].AsInteger(); | ||
172 | |||
173 | } | ||
174 | |||
175 | if (ObjMap.ContainsKey("Profile")) | ||
176 | { | ||
177 | if (ObjMap["Profile"].Type != OSDType.Map) | ||
178 | { | ||
179 | responsedata["str_response_string"] = "Has Profile key, but data not in expected format"; | ||
180 | return responsedata; | ||
181 | } | ||
182 | |||
183 | OSDMap ProfileMap = (OSDMap)ObjMap["Profile"]; | ||
184 | |||
185 | profile_begin = ProfileMap["Begin"].AsInteger(); | ||
186 | profile_curve = ProfileMap["Curve"].AsInteger(); | ||
187 | profile_end = ProfileMap["End"].AsInteger(); | ||
188 | hollow = ProfileMap["Hollow"].AsInteger(); | ||
189 | } | ||
190 | ray_end_is_intersection = ObjMap["RayEndIsIntersection"].AsBoolean(); | ||
191 | |||
192 | ray_target_id = ObjMap["RayTargetId"].AsUUID(); | ||
193 | state = ObjMap["State"].AsInteger(); | ||
194 | try | ||
195 | { | ||
196 | ray_end = ((OSDArray) ObjMap["RayEnd"]).AsVector3(); | ||
197 | ray_start = ((OSDArray) ObjMap["RayStart"]).AsVector3(); | ||
198 | scale = ((OSDArray) ObjMap["Scale"]).AsVector3(); | ||
199 | rotation = ((OSDArray)ObjMap["Rotation"]).AsQuaternion(); | ||
200 | } | ||
201 | catch (Exception) | ||
202 | { | ||
203 | responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format"; | ||
204 | return responsedata; | ||
205 | } | ||
206 | |||
207 | if (rm.ContainsKey("AgentData")) | ||
208 | { | ||
209 | if (rm["AgentData"].Type != OSDType.Map) | ||
210 | { | ||
211 | responsedata["str_response_string"] = "Has AgentData key, but data not in expected format"; | ||
212 | return responsedata; | ||
213 | } | ||
214 | |||
215 | OSDMap AgentDataMap = (OSDMap) rm["AgentData"]; | ||
216 | |||
217 | //session_id = AgentDataMap["SessionId"].AsUUID(); | ||
218 | group_id = AgentDataMap["GroupId"].AsUUID(); | ||
219 | } | ||
220 | |||
221 | } | ||
222 | else | ||
223 | { //v1 | ||
224 | bypass_raycast = rm["bypass_raycast"].AsBoolean(); | ||
225 | |||
226 | everyone_mask = readuintval(rm["everyone_mask"]); | ||
227 | flags = readuintval(rm["flags"]); | ||
228 | group_id = rm["group_id"].AsUUID(); | ||
229 | group_mask = readuintval(rm["group_mask"]); | ||
230 | hollow = rm["hollow"].AsInteger(); | ||
231 | material = rm["material"].AsInteger(); | ||
232 | next_owner_mask = readuintval(rm["next_owner_mask"]); | ||
233 | hollow = rm["hollow"].AsInteger(); | ||
234 | p_code = rm["p_code"].AsInteger(); | ||
235 | path_begin = rm["path_begin"].AsInteger(); | ||
236 | path_curve = rm["path_curve"].AsInteger(); | ||
237 | path_end = rm["path_end"].AsInteger(); | ||
238 | path_radius_offset = rm["path_radius_offset"].AsInteger(); | ||
239 | path_revolutions = rm["path_revolutions"].AsInteger(); | ||
240 | path_scale_x = rm["path_scale_x"].AsInteger(); | ||
241 | path_scale_y = rm["path_scale_y"].AsInteger(); | ||
242 | path_shear_x = rm["path_shear_x"].AsInteger(); | ||
243 | path_shear_y = rm["path_shear_y"].AsInteger(); | ||
244 | path_skew = rm["path_skew"].AsInteger(); | ||
245 | path_taper_x = rm["path_taper_x"].AsInteger(); | ||
246 | path_taper_y = rm["path_taper_y"].AsInteger(); | ||
247 | path_twist = rm["path_twist"].AsInteger(); | ||
248 | path_twist_begin = rm["path_twist_begin"].AsInteger(); | ||
249 | profile_begin = rm["profile_begin"].AsInteger(); | ||
250 | profile_curve = rm["profile_curve"].AsInteger(); | ||
251 | profile_end = rm["profile_end"].AsInteger(); | ||
252 | |||
253 | ray_end_is_intersection = rm["ray_end_is_intersection"].AsBoolean(); | ||
254 | |||
255 | ray_target_id = rm["ray_target_id"].AsUUID(); | ||
256 | |||
257 | |||
258 | //session_id = rm["session_id"].AsUUID(); | ||
259 | state = rm["state"].AsInteger(); | ||
260 | try | ||
261 | { | ||
262 | ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); | ||
263 | ray_start = ((OSDArray)rm["ray_start"]).AsVector3(); | ||
264 | rotation = ((OSDArray)rm["rotation"]).AsQuaternion(); | ||
265 | scale = ((OSDArray)rm["scale"]).AsVector3(); | ||
266 | } | ||
267 | catch (Exception) | ||
268 | { | ||
269 | responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format"; | ||
270 | return responsedata; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | |||
276 | 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); | ||
277 | |||
278 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | ||
279 | |||
280 | pbs.PathBegin = (ushort)path_begin; | ||
281 | pbs.PathCurve = (byte)path_curve; | ||
282 | pbs.PathEnd = (ushort)path_end; | ||
283 | pbs.PathRadiusOffset = (sbyte)path_radius_offset; | ||
284 | pbs.PathRevolutions = (byte)path_revolutions; | ||
285 | pbs.PathScaleX = (byte)path_scale_x; | ||
286 | pbs.PathScaleY = (byte)path_scale_y; | ||
287 | pbs.PathShearX = (byte) path_shear_x; | ||
288 | pbs.PathShearY = (byte)path_shear_y; | ||
289 | pbs.PathSkew = (sbyte)path_skew; | ||
290 | pbs.PathTaperX = (sbyte)path_taper_x; | ||
291 | pbs.PathTaperY = (sbyte)path_taper_y; | ||
292 | pbs.PathTwist = (sbyte)path_twist; | ||
293 | pbs.PathTwistBegin = (sbyte)path_twist_begin; | ||
294 | pbs.HollowShape = (HollowShape) hollow; | ||
295 | pbs.PCode = (byte)p_code; | ||
296 | pbs.ProfileBegin = (ushort) profile_begin; | ||
297 | pbs.ProfileCurve = (byte) profile_curve; | ||
298 | pbs.ProfileEnd = (ushort)profile_end; | ||
299 | pbs.Scale = scale; | ||
300 | pbs.State = (byte)state; | ||
301 | |||
302 | SceneObjectGroup obj = null; ; | ||
303 | |||
304 | if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) | ||
305 | { | ||
306 | // rez ON the ground, not IN the ground | ||
307 | // pos.Z += 0.25F; | ||
308 | |||
309 | obj = m_scene.AddNewPrim(avatar.UUID, group_id, pos, rotation, pbs); | ||
310 | } | ||
311 | |||
312 | |||
313 | if (obj == null) | ||
314 | return responsedata; | ||
315 | |||
316 | SceneObjectPart rootpart = obj.RootPart; | ||
317 | rootpart.Shape = pbs; | ||
318 | rootpart.Flags |= (PrimFlags)flags; | ||
319 | rootpart.EveryoneMask = everyone_mask; | ||
320 | rootpart.GroupID = group_id; | ||
321 | rootpart.GroupMask = group_mask; | ||
322 | rootpart.NextOwnerMask = next_owner_mask; | ||
323 | rootpart.Material = (byte)material; | ||
324 | |||
325 | |||
326 | |||
327 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | ||
328 | |||
329 | responsedata["int_response_code"] = 200; //501; //410; //404; | ||
330 | responsedata["content_type"] = "text/plain"; | ||
331 | responsedata["keepalive"] = false; | ||
332 | responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>",ConvertUintToBytes(obj.LocalId)); | ||
333 | |||
334 | return responsedata; | ||
335 | } | ||
336 | |||
337 | private uint readuintval(OSD obj) | ||
338 | { | ||
339 | byte[] tmp = obj.AsBinary(); | ||
340 | if (BitConverter.IsLittleEndian) | ||
341 | Array.Reverse(tmp); | ||
342 | return Utils.BytesToUInt(tmp); | ||
343 | |||
344 | } | ||
345 | private string ConvertUintToBytes(uint val) | ||
346 | { | ||
347 | byte[] resultbytes = Utils.UIntToBytes(val); | ||
348 | if (BitConverter.IsLittleEndian) | ||
349 | Array.Reverse(resultbytes); | ||
350 | return String.Format("<binary encoding=\"base64\">{0}</binary>",Convert.ToBase64String(resultbytes)); | ||
351 | } | ||
352 | |||
353 | public void Close() | ||
354 | { | ||
355 | |||
356 | } | ||
357 | |||
358 | public string Name | ||
359 | { | ||
360 | get { return "ObjectAddModule"; } | ||
361 | } | ||
362 | |||
363 | public bool IsSharedModule | ||
364 | { | ||
365 | get { return false; } | ||
366 | } | ||
367 | |||
368 | #endregion | ||
369 | } | ||
370 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs new file mode 100644 index 0000000..3809f84 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs | |||
@@ -0,0 +1,374 @@ | |||
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 OpenMetaverse.Messages.Linden; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | using OSD = OpenMetaverse.StructuredData.OSD; | ||
48 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
49 | using OpenSim.Framework.Capabilities; | ||
50 | using ExtraParamType = OpenMetaverse.ExtraParamType; | ||
51 | |||
52 | namespace OpenSim.Region.ClientStack.Linden | ||
53 | { | ||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
55 | public class UploadObjectAssetModule : INonSharedRegionModule | ||
56 | { | ||
57 | private static readonly ILog m_log = | ||
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | private Scene m_scene; | ||
60 | |||
61 | #region IRegionModuleBase Members | ||
62 | |||
63 | |||
64 | public Type ReplaceableInterface | ||
65 | { | ||
66 | get { return null; } | ||
67 | } | ||
68 | |||
69 | public void Initialise(IConfigSource source) | ||
70 | { | ||
71 | |||
72 | } | ||
73 | |||
74 | public void AddRegion(Scene pScene) | ||
75 | { | ||
76 | m_scene = pScene; | ||
77 | } | ||
78 | |||
79 | public void RemoveRegion(Scene scene) | ||
80 | { | ||
81 | |||
82 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
83 | m_scene = null; | ||
84 | } | ||
85 | |||
86 | public void RegionLoaded(Scene scene) | ||
87 | { | ||
88 | |||
89 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
90 | } | ||
91 | |||
92 | #endregion | ||
93 | |||
94 | |||
95 | #region IRegionModule Members | ||
96 | |||
97 | |||
98 | |||
99 | public void Close() { } | ||
100 | |||
101 | public string Name { get { return "UploadObjectAssetModuleModule"; } } | ||
102 | |||
103 | |||
104 | public void RegisterCaps(UUID agentID, Caps caps) | ||
105 | { | ||
106 | UUID capID = UUID.Random(); | ||
107 | |||
108 | // m_log.Debug("[UPLOAD OBJECT ASSET MODULE]: /CAPS/" + capID); | ||
109 | caps.RegisterHandler("UploadObjectAsset", | ||
110 | new RestHTTPHandler("POST", "/CAPS/OA/" + capID + "/", | ||
111 | delegate(Hashtable m_dhttpMethod) | ||
112 | { | ||
113 | return ProcessAdd(m_dhttpMethod, agentID, caps); | ||
114 | })); | ||
115 | /* | ||
116 | caps.RegisterHandler("NewFileAgentInventoryVariablePrice", | ||
117 | |||
118 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST", | ||
119 | "/CAPS/" + capID.ToString(), | ||
120 | delegate(LLSDAssetUploadRequest req) | ||
121 | { | ||
122 | return NewAgentInventoryRequest(req,agentID); | ||
123 | })); | ||
124 | */ | ||
125 | |||
126 | } | ||
127 | |||
128 | #endregion | ||
129 | |||
130 | |||
131 | /// <summary> | ||
132 | /// Parses ad request | ||
133 | /// </summary> | ||
134 | /// <param name="request"></param> | ||
135 | /// <param name="AgentId"></param> | ||
136 | /// <param name="cap"></param> | ||
137 | /// <returns></returns> | ||
138 | public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap) | ||
139 | { | ||
140 | Hashtable responsedata = new Hashtable(); | ||
141 | responsedata["int_response_code"] = 400; //501; //410; //404; | ||
142 | responsedata["content_type"] = "text/plain"; | ||
143 | responsedata["keepalive"] = false; | ||
144 | responsedata["str_response_string"] = "Request wasn't what was expected"; | ||
145 | ScenePresence avatar; | ||
146 | |||
147 | if (!m_scene.TryGetScenePresence(AgentId, out avatar)) | ||
148 | return responsedata; | ||
149 | |||
150 | OSDMap r = (OSDMap)OSDParser.Deserialize((string)request["requestbody"]); | ||
151 | UploadObjectAssetMessage message = new UploadObjectAssetMessage(); | ||
152 | try | ||
153 | { | ||
154 | message.Deserialize(r); | ||
155 | |||
156 | } | ||
157 | catch (Exception ex) | ||
158 | { | ||
159 | m_log.Error("[UPLOAD OBJECT ASSET MODULE]: Error deserializing message " + ex.ToString()); | ||
160 | message = null; | ||
161 | } | ||
162 | |||
163 | if (message == null) | ||
164 | { | ||
165 | responsedata["int_response_code"] = 400; //501; //410; //404; | ||
166 | responsedata["content_type"] = "text/plain"; | ||
167 | responsedata["keepalive"] = false; | ||
168 | responsedata["str_response_string"] = | ||
169 | "<llsd><map><key>error</key><string>Error parsing Object</string></map></llsd>"; | ||
170 | |||
171 | return responsedata; | ||
172 | } | ||
173 | |||
174 | Vector3 pos = avatar.AbsolutePosition + (Vector3.UnitX * avatar.Rotation); | ||
175 | Quaternion rot = Quaternion.Identity; | ||
176 | Vector3 rootpos = Vector3.Zero; | ||
177 | // Quaternion rootrot = Quaternion.Identity; | ||
178 | |||
179 | SceneObjectGroup rootGroup = null; | ||
180 | SceneObjectGroup[] allparts = new SceneObjectGroup[message.Objects.Length]; | ||
181 | for (int i = 0; i < message.Objects.Length; i++) | ||
182 | { | ||
183 | UploadObjectAssetMessage.Object obj = message.Objects[i]; | ||
184 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | ||
185 | |||
186 | if (i == 0) | ||
187 | { | ||
188 | rootpos = obj.Position; | ||
189 | // rootrot = obj.Rotation; | ||
190 | } | ||
191 | |||
192 | // Combine the extraparams data into it's ugly blob again.... | ||
193 | //int bytelength = 0; | ||
194 | //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++) | ||
195 | //{ | ||
196 | // bytelength += obj.ExtraParams[extparams].ExtraParamData.Length; | ||
197 | //} | ||
198 | //byte[] extraparams = new byte[bytelength]; | ||
199 | //int position = 0; | ||
200 | |||
201 | |||
202 | |||
203 | //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++) | ||
204 | //{ | ||
205 | // Buffer.BlockCopy(obj.ExtraParams[extparams].ExtraParamData, 0, extraparams, position, | ||
206 | // obj.ExtraParams[extparams].ExtraParamData.Length); | ||
207 | // | ||
208 | // position += obj.ExtraParams[extparams].ExtraParamData.Length; | ||
209 | // } | ||
210 | |||
211 | //pbs.ExtraParams = extraparams; | ||
212 | for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++) | ||
213 | { | ||
214 | UploadObjectAssetMessage.Object.ExtraParam extraParam = obj.ExtraParams[extparams]; | ||
215 | switch ((ushort)extraParam.Type) | ||
216 | { | ||
217 | case (ushort)ExtraParamType.Sculpt: | ||
218 | Primitive.SculptData sculpt = new Primitive.SculptData(extraParam.ExtraParamData, 0); | ||
219 | |||
220 | pbs.SculptEntry = true; | ||
221 | |||
222 | pbs.SculptTexture = obj.SculptID; | ||
223 | pbs.SculptType = (byte)sculpt.Type; | ||
224 | |||
225 | break; | ||
226 | case (ushort)ExtraParamType.Flexible: | ||
227 | Primitive.FlexibleData flex = new Primitive.FlexibleData(extraParam.ExtraParamData, 0); | ||
228 | pbs.FlexiEntry = true; | ||
229 | pbs.FlexiDrag = flex.Drag; | ||
230 | pbs.FlexiForceX = flex.Force.X; | ||
231 | pbs.FlexiForceY = flex.Force.Y; | ||
232 | pbs.FlexiForceZ = flex.Force.Z; | ||
233 | pbs.FlexiGravity = flex.Gravity; | ||
234 | pbs.FlexiSoftness = flex.Softness; | ||
235 | pbs.FlexiTension = flex.Tension; | ||
236 | pbs.FlexiWind = flex.Wind; | ||
237 | break; | ||
238 | case (ushort)ExtraParamType.Light: | ||
239 | Primitive.LightData light = new Primitive.LightData(extraParam.ExtraParamData, 0); | ||
240 | pbs.LightColorA = light.Color.A; | ||
241 | pbs.LightColorB = light.Color.B; | ||
242 | pbs.LightColorG = light.Color.G; | ||
243 | pbs.LightColorR = light.Color.R; | ||
244 | pbs.LightCutoff = light.Cutoff; | ||
245 | pbs.LightEntry = true; | ||
246 | pbs.LightFalloff = light.Falloff; | ||
247 | pbs.LightIntensity = light.Intensity; | ||
248 | pbs.LightRadius = light.Radius; | ||
249 | break; | ||
250 | case 0x40: | ||
251 | pbs.ReadProjectionData(extraParam.ExtraParamData, 0); | ||
252 | break; | ||
253 | |||
254 | } | ||
255 | |||
256 | |||
257 | } | ||
258 | pbs.PathBegin = (ushort) obj.PathBegin; | ||
259 | pbs.PathCurve = (byte) obj.PathCurve; | ||
260 | pbs.PathEnd = (ushort) obj.PathEnd; | ||
261 | pbs.PathRadiusOffset = (sbyte) obj.RadiusOffset; | ||
262 | pbs.PathRevolutions = (byte) obj.Revolutions; | ||
263 | pbs.PathScaleX = (byte) obj.ScaleX; | ||
264 | pbs.PathScaleY = (byte) obj.ScaleY; | ||
265 | pbs.PathShearX = (byte) obj.ShearX; | ||
266 | pbs.PathShearY = (byte) obj.ShearY; | ||
267 | pbs.PathSkew = (sbyte) obj.Skew; | ||
268 | pbs.PathTaperX = (sbyte) obj.TaperX; | ||
269 | pbs.PathTaperY = (sbyte) obj.TaperY; | ||
270 | pbs.PathTwist = (sbyte) obj.Twist; | ||
271 | pbs.PathTwistBegin = (sbyte) obj.TwistBegin; | ||
272 | pbs.HollowShape = (HollowShape) obj.ProfileHollow; | ||
273 | pbs.PCode = (byte) PCode.Prim; | ||
274 | pbs.ProfileBegin = (ushort) obj.ProfileBegin; | ||
275 | pbs.ProfileCurve = (byte) obj.ProfileCurve; | ||
276 | pbs.ProfileEnd = (ushort) obj.ProfileEnd; | ||
277 | pbs.Scale = obj.Scale; | ||
278 | pbs.State = (byte) 0; | ||
279 | SceneObjectPart prim = new SceneObjectPart(); | ||
280 | prim.UUID = UUID.Random(); | ||
281 | prim.CreatorID = AgentId; | ||
282 | prim.OwnerID = AgentId; | ||
283 | prim.GroupID = obj.GroupID; | ||
284 | prim.LastOwnerID = prim.OwnerID; | ||
285 | prim.CreationDate = Util.UnixTimeSinceEpoch(); | ||
286 | prim.Name = obj.Name; | ||
287 | prim.Description = ""; | ||
288 | |||
289 | prim.PayPrice[0] = -2; | ||
290 | prim.PayPrice[1] = -2; | ||
291 | prim.PayPrice[2] = -2; | ||
292 | prim.PayPrice[3] = -2; | ||
293 | prim.PayPrice[4] = -2; | ||
294 | Primitive.TextureEntry tmp = | ||
295 | new Primitive.TextureEntry(UUID.Parse("89556747-24cb-43ed-920b-47caed15465f")); | ||
296 | |||
297 | for (int j = 0; j < obj.Faces.Length; j++) | ||
298 | { | ||
299 | UploadObjectAssetMessage.Object.Face face = obj.Faces[j]; | ||
300 | |||
301 | Primitive.TextureEntryFace primFace = tmp.CreateFace((uint) j); | ||
302 | |||
303 | primFace.Bump = face.Bump; | ||
304 | primFace.RGBA = face.Color; | ||
305 | primFace.Fullbright = face.Fullbright; | ||
306 | primFace.Glow = face.Glow; | ||
307 | primFace.TextureID = face.ImageID; | ||
308 | primFace.Rotation = face.ImageRot; | ||
309 | primFace.MediaFlags = ((face.MediaFlags & 1) != 0); | ||
310 | |||
311 | primFace.OffsetU = face.OffsetS; | ||
312 | primFace.OffsetV = face.OffsetT; | ||
313 | primFace.RepeatU = face.ScaleS; | ||
314 | primFace.RepeatV = face.ScaleT; | ||
315 | primFace.TexMapType = (MappingType) (face.MediaFlags & 6); | ||
316 | } | ||
317 | pbs.TextureEntry = tmp.GetBytes(); | ||
318 | prim.Shape = pbs; | ||
319 | prim.Scale = obj.Scale; | ||
320 | |||
321 | |||
322 | SceneObjectGroup grp = new SceneObjectGroup(); | ||
323 | |||
324 | grp.SetRootPart(prim); | ||
325 | prim.ParentID = 0; | ||
326 | if (i == 0) | ||
327 | { | ||
328 | rootGroup = grp; | ||
329 | |||
330 | } | ||
331 | grp.AttachToScene(m_scene); | ||
332 | grp.AbsolutePosition = obj.Position; | ||
333 | prim.RotationOffset = obj.Rotation; | ||
334 | |||
335 | grp.RootPart.IsAttachment = false; | ||
336 | // Required for linking | ||
337 | grp.RootPart.UpdateFlag = 0; | ||
338 | |||
339 | if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) | ||
340 | { | ||
341 | m_scene.AddSceneObject(grp); | ||
342 | grp.AbsolutePosition = obj.Position; | ||
343 | } | ||
344 | allparts[i] = grp; | ||
345 | |||
346 | } | ||
347 | |||
348 | for (int j = 1; j < allparts.Length; j++) | ||
349 | { | ||
350 | rootGroup.RootPart.UpdateFlag = 0; | ||
351 | allparts[j].RootPart.UpdateFlag = 0; | ||
352 | rootGroup.LinkToGroup(allparts[j]); | ||
353 | } | ||
354 | |||
355 | rootGroup.ScheduleGroupForFullUpdate(); | ||
356 | pos = m_scene.GetNewRezLocation(Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale(), false); | ||
357 | |||
358 | responsedata["int_response_code"] = 200; //501; //410; //404; | ||
359 | responsedata["content_type"] = "text/plain"; | ||
360 | responsedata["keepalive"] = false; | ||
361 | responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>", ConvertUintToBytes(allparts[0].LocalId)); | ||
362 | |||
363 | return responsedata; | ||
364 | } | ||
365 | |||
366 | private string ConvertUintToBytes(uint val) | ||
367 | { | ||
368 | byte[] resultbytes = Utils.UIntToBytes(val); | ||
369 | if (BitConverter.IsLittleEndian) | ||
370 | Array.Reverse(resultbytes); | ||
371 | return String.Format("<binary encoding=\"base64\">{0}</binary>", Convert.ToBase64String(resultbytes)); | ||
372 | } | ||
373 | } | ||
374 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs new file mode 100644 index 0000000..94629a2 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -0,0 +1,134 @@ | |||
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.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using Mono.Addins; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
41 | using OpenSim.Capabilities.Handlers; | ||
42 | |||
43 | namespace OpenSim.Region.ClientStack.Linden | ||
44 | { | ||
45 | |||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
47 | public class WebFetchInvDescModule : INonSharedRegionModule | ||
48 | { | ||
49 | private static readonly ILog m_log = | ||
50 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | private Scene m_scene; | ||
52 | |||
53 | private IInventoryService m_InventoryService; | ||
54 | private ILibraryService m_LibraryService; | ||
55 | private bool m_Enabled = false; | ||
56 | private string m_URL; | ||
57 | |||
58 | #region ISharedRegionModule Members | ||
59 | |||
60 | public void Initialise(IConfigSource source) | ||
61 | { | ||
62 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
63 | if (config == null) | ||
64 | return; | ||
65 | |||
66 | m_URL = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); | ||
67 | // Cap doesn't exist | ||
68 | if (m_URL != string.Empty) | ||
69 | m_Enabled = true; | ||
70 | } | ||
71 | |||
72 | public void AddRegion(Scene s) | ||
73 | { | ||
74 | if (!m_Enabled) | ||
75 | return; | ||
76 | |||
77 | m_scene = s; | ||
78 | } | ||
79 | |||
80 | public void RemoveRegion(Scene s) | ||
81 | { | ||
82 | if (!m_Enabled) | ||
83 | return; | ||
84 | |||
85 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
86 | m_scene = null; | ||
87 | } | ||
88 | |||
89 | public void RegionLoaded(Scene s) | ||
90 | { | ||
91 | if (!m_Enabled) | ||
92 | return; | ||
93 | |||
94 | m_InventoryService = m_scene.InventoryService; ; | ||
95 | m_LibraryService = m_scene.LibraryService; | ||
96 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
97 | } | ||
98 | |||
99 | public void PostInitialise() | ||
100 | { | ||
101 | } | ||
102 | |||
103 | public void Close() { } | ||
104 | |||
105 | public string Name { get { return "WebFetchInvDescModule"; } } | ||
106 | |||
107 | public Type ReplaceableInterface | ||
108 | { | ||
109 | get { return null; } | ||
110 | } | ||
111 | |||
112 | #endregion | ||
113 | |||
114 | public void RegisterCaps(UUID agentID, Caps caps) | ||
115 | { | ||
116 | UUID capID = UUID.Random(); | ||
117 | |||
118 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | ||
119 | if (m_URL == "localhost") | ||
120 | { | ||
121 | m_log.InfoFormat("[WEBFETCHINVENTORYDESCENDANTS]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
122 | WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); | ||
123 | IRequestHandler reqHandler = new RestStreamHandler("POST", "/CAPS/" + UUID.Random(), webFetchHandler.FetchInventoryDescendentsRequest); | ||
124 | caps.RegisterHandler("WebFetchInventoryDescendents", reqHandler); | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | m_log.InfoFormat("[WEBFETCHINVENTORYDESCENDANTS]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
129 | caps.RegisterHandler("WebFetchInventoryDescendents", m_URL); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | } | ||
134 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs new file mode 100644 index 0000000..90b3ede --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs | |||
@@ -0,0 +1,57 @@ | |||
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 OpenSim.Framework; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.Packets; | ||
32 | |||
33 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Holds a reference to a <seealso cref="LLUDPClient"/> and a <seealso cref="Packet"/> | ||
37 | /// for incoming packets | ||
38 | /// </summary> | ||
39 | public sealed class IncomingPacket | ||
40 | { | ||
41 | /// <summary>Client this packet came from</summary> | ||
42 | public LLUDPClient Client; | ||
43 | /// <summary>Packet data that has been received</summary> | ||
44 | public Packet Packet; | ||
45 | |||
46 | /// <summary> | ||
47 | /// Default constructor | ||
48 | /// </summary> | ||
49 | /// <param name="client">Reference to the client this packet came from</param> | ||
50 | /// <param name="packet">Packet data</param> | ||
51 | public IncomingPacket(LLUDPClient client, Packet packet) | ||
52 | { | ||
53 | Client = client; | ||
54 | Packet = packet; | ||
55 | } | ||
56 | } | ||
57 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs new file mode 100644 index 0000000..1f73a1d --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs | |||
@@ -0,0 +1,73 @@ | |||
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.Generic; | ||
30 | |||
31 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
32 | { | ||
33 | /// <summary> | ||
34 | /// A circular buffer and hashset for tracking incoming packet sequence | ||
35 | /// numbers | ||
36 | /// </summary> | ||
37 | public sealed class IncomingPacketHistoryCollection | ||
38 | { | ||
39 | private readonly uint[] m_items; | ||
40 | private HashSet<uint> m_hashSet; | ||
41 | private int m_first; | ||
42 | private int m_next; | ||
43 | private int m_capacity; | ||
44 | |||
45 | public IncomingPacketHistoryCollection(int capacity) | ||
46 | { | ||
47 | this.m_capacity = capacity; | ||
48 | m_items = new uint[capacity]; | ||
49 | m_hashSet = new HashSet<uint>(); | ||
50 | } | ||
51 | |||
52 | public bool TryEnqueue(uint ack) | ||
53 | { | ||
54 | lock (m_hashSet) | ||
55 | { | ||
56 | if (m_hashSet.Add(ack)) | ||
57 | { | ||
58 | m_items[m_next] = ack; | ||
59 | m_next = (m_next + 1) % m_capacity; | ||
60 | if (m_next == m_first) | ||
61 | { | ||
62 | m_hashSet.Remove(m_items[m_first]); | ||
63 | m_first = (m_first + 1) % m_capacity; | ||
64 | } | ||
65 | |||
66 | return true; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | return false; | ||
71 | } | ||
72 | } | ||
73 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs new file mode 100644 index 0000000..9dd6663 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | |||
@@ -0,0 +1,401 @@ | |||
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.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.Imaging; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Framework.Interfaces; | ||
34 | using OpenSim.Services.Interfaces; | ||
35 | using log4net; | ||
36 | using System.Reflection; | ||
37 | |||
38 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Stores information about a current texture download and a reference to the texture asset | ||
42 | /// </summary> | ||
43 | public class J2KImage | ||
44 | { | ||
45 | private const int IMAGE_PACKET_SIZE = 1000; | ||
46 | private const int FIRST_PACKET_SIZE = 600; | ||
47 | |||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | public uint LastSequence; | ||
51 | public float Priority; | ||
52 | public uint StartPacket; | ||
53 | public sbyte DiscardLevel; | ||
54 | public UUID TextureID; | ||
55 | public IJ2KDecoder J2KDecoder; | ||
56 | public IAssetService AssetService; | ||
57 | public UUID AgentID; | ||
58 | public IInventoryAccessModule InventoryAccessModule; | ||
59 | public OpenJPEG.J2KLayerInfo[] Layers; | ||
60 | public bool IsDecoded; | ||
61 | public bool HasAsset; | ||
62 | public C5.IPriorityQueueHandle<J2KImage> PriorityQueueHandle; | ||
63 | |||
64 | private uint m_currentPacket; | ||
65 | private bool m_decodeRequested; | ||
66 | private bool m_assetRequested; | ||
67 | private bool m_sentInfo; | ||
68 | private uint m_stopPacket; | ||
69 | private byte[] m_asset; | ||
70 | private LLImageManager m_imageManager; | ||
71 | |||
72 | public J2KImage(LLImageManager imageManager) | ||
73 | { | ||
74 | m_imageManager = imageManager; | ||
75 | } | ||
76 | |||
77 | /// <summary> | ||
78 | /// Sends packets for this texture to a client until packetsToSend is | ||
79 | /// hit or the transfer completes | ||
80 | /// </summary> | ||
81 | /// <param name="client">Reference to the client that the packets are destined for</param> | ||
82 | /// <param name="packetsToSend">Maximum number of packets to send during this call</param> | ||
83 | /// <param name="packetsSent">Number of packets sent during this call</param> | ||
84 | /// <returns>True if the transfer completes at the current discard level, otherwise false</returns> | ||
85 | public bool SendPackets(LLClientView client, int packetsToSend, out int packetsSent) | ||
86 | { | ||
87 | packetsSent = 0; | ||
88 | |||
89 | if (m_currentPacket <= m_stopPacket) | ||
90 | { | ||
91 | bool sendMore = true; | ||
92 | |||
93 | if (!m_sentInfo || (m_currentPacket == 0)) | ||
94 | { | ||
95 | sendMore = !SendFirstPacket(client); | ||
96 | |||
97 | m_sentInfo = true; | ||
98 | ++m_currentPacket; | ||
99 | ++packetsSent; | ||
100 | } | ||
101 | if (m_currentPacket < 2) | ||
102 | { | ||
103 | m_currentPacket = 2; | ||
104 | } | ||
105 | |||
106 | while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket) | ||
107 | { | ||
108 | sendMore = SendPacket(client); | ||
109 | ++m_currentPacket; | ||
110 | ++packetsSent; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | return (m_currentPacket > m_stopPacket); | ||
115 | } | ||
116 | |||
117 | public void RunUpdate() | ||
118 | { | ||
119 | //This is where we decide what we need to update | ||
120 | //and assign the real discardLevel and packetNumber | ||
121 | //assuming of course that the connected client might be bonkers | ||
122 | |||
123 | if (!HasAsset) | ||
124 | { | ||
125 | if (!m_assetRequested) | ||
126 | { | ||
127 | m_assetRequested = true; | ||
128 | AssetService.Get(TextureID.ToString(), this, AssetReceived); | ||
129 | } | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | if (!IsDecoded) | ||
134 | { | ||
135 | //We need to decode the requested image first | ||
136 | if (!m_decodeRequested) | ||
137 | { | ||
138 | //Request decode | ||
139 | m_decodeRequested = true; | ||
140 | // Do we have a jpeg decoder? | ||
141 | if (J2KDecoder != null) | ||
142 | { | ||
143 | if (m_asset == null) | ||
144 | { | ||
145 | J2KDecodedCallback(TextureID, new OpenJPEG.J2KLayerInfo[0]); | ||
146 | } | ||
147 | else | ||
148 | { | ||
149 | // Send it off to the jpeg decoder | ||
150 | J2KDecoder.BeginDecode(TextureID, m_asset, J2KDecodedCallback); | ||
151 | } | ||
152 | |||
153 | } | ||
154 | else | ||
155 | { | ||
156 | J2KDecodedCallback(TextureID, new OpenJPEG.J2KLayerInfo[0]); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | // Check for missing image asset data | ||
163 | if (m_asset == null) | ||
164 | { | ||
165 | m_log.Warn("[J2KIMAGE]: RunUpdate() called with missing asset data (no missing image texture?). Canceling texture transfer"); | ||
166 | m_currentPacket = m_stopPacket; | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | if (DiscardLevel >= 0 || m_stopPacket == 0) | ||
171 | { | ||
172 | // This shouldn't happen, but if it does, we really can't proceed | ||
173 | if (Layers == null) | ||
174 | { | ||
175 | m_log.Warn("[J2KIMAGE]: RunUpdate() called with missing Layers. Canceling texture transfer"); | ||
176 | m_currentPacket = m_stopPacket; | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | int maxDiscardLevel = Math.Max(0, Layers.Length - 1); | ||
181 | |||
182 | // Treat initial texture downloads with a DiscardLevel of -1 a request for the highest DiscardLevel | ||
183 | if (DiscardLevel < 0 && m_stopPacket == 0) | ||
184 | DiscardLevel = (sbyte)maxDiscardLevel; | ||
185 | |||
186 | // Clamp at the highest discard level | ||
187 | DiscardLevel = (sbyte)Math.Min(DiscardLevel, maxDiscardLevel); | ||
188 | |||
189 | //Calculate the m_stopPacket | ||
190 | if (Layers.Length > 0) | ||
191 | { | ||
192 | m_stopPacket = (uint)GetPacketForBytePosition(Layers[(Layers.Length - 1) - DiscardLevel].End); | ||
193 | //I don't know why, but the viewer seems to expect the final packet if the file | ||
194 | //is just one packet bigger. | ||
195 | if (TexturePacketCount() == m_stopPacket + 1) | ||
196 | { | ||
197 | m_stopPacket = TexturePacketCount(); | ||
198 | } | ||
199 | } | ||
200 | else | ||
201 | { | ||
202 | m_stopPacket = TexturePacketCount(); | ||
203 | } | ||
204 | |||
205 | //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way) | ||
206 | if (m_stopPacket == 1 && Layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++; | ||
207 | |||
208 | m_currentPacket = StartPacket; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | private bool SendFirstPacket(LLClientView client) | ||
215 | { | ||
216 | if (client == null) | ||
217 | return false; | ||
218 | |||
219 | if (m_asset == null) | ||
220 | { | ||
221 | m_log.Warn("[J2KIMAGE]: Sending ImageNotInDatabase for texture " + TextureID); | ||
222 | client.SendImageNotFound(TextureID); | ||
223 | return true; | ||
224 | } | ||
225 | else if (m_asset.Length <= FIRST_PACKET_SIZE) | ||
226 | { | ||
227 | // We have less then one packet's worth of data | ||
228 | client.SendImageFirstPart(1, TextureID, (uint)m_asset.Length, m_asset, 2); | ||
229 | m_stopPacket = 0; | ||
230 | return true; | ||
231 | } | ||
232 | else | ||
233 | { | ||
234 | // This is going to be a multi-packet texture download | ||
235 | byte[] firstImageData = new byte[FIRST_PACKET_SIZE]; | ||
236 | |||
237 | try { Buffer.BlockCopy(m_asset, 0, firstImageData, 0, FIRST_PACKET_SIZE); } | ||
238 | catch (Exception) | ||
239 | { | ||
240 | m_log.ErrorFormat("[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}", TextureID, m_asset.Length); | ||
241 | return true; | ||
242 | } | ||
243 | |||
244 | client.SendImageFirstPart(TexturePacketCount(), TextureID, (uint)m_asset.Length, firstImageData, (byte)ImageCodec.J2C); | ||
245 | } | ||
246 | return false; | ||
247 | } | ||
248 | |||
249 | private bool SendPacket(LLClientView client) | ||
250 | { | ||
251 | if (client == null) | ||
252 | return false; | ||
253 | |||
254 | bool complete = false; | ||
255 | int imagePacketSize = ((int)m_currentPacket == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE; | ||
256 | |||
257 | try | ||
258 | { | ||
259 | if ((CurrentBytePosition() + IMAGE_PACKET_SIZE) > m_asset.Length) | ||
260 | { | ||
261 | imagePacketSize = LastPacketSize(); | ||
262 | complete = true; | ||
263 | if ((CurrentBytePosition() + imagePacketSize) > m_asset.Length) | ||
264 | { | ||
265 | imagePacketSize = m_asset.Length - CurrentBytePosition(); | ||
266 | complete = true; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | // It's concievable that the client might request packet one | ||
271 | // from a one packet image, which is really packet 0, | ||
272 | // which would leave us with a negative imagePacketSize.. | ||
273 | if (imagePacketSize > 0) | ||
274 | { | ||
275 | byte[] imageData = new byte[imagePacketSize]; | ||
276 | int currentPosition = CurrentBytePosition(); | ||
277 | |||
278 | try { Buffer.BlockCopy(m_asset, currentPosition, imageData, 0, imagePacketSize); } | ||
279 | catch (Exception e) | ||
280 | { | ||
281 | m_log.ErrorFormat("[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}, currentposition={2}, imagepacketsize={3}, exception={4}", | ||
282 | TextureID, m_asset.Length, currentPosition, imagePacketSize, e.Message); | ||
283 | return false; | ||
284 | } | ||
285 | |||
286 | //Send the packet | ||
287 | client.SendImageNextPart((ushort)(m_currentPacket - 1), TextureID, imageData); | ||
288 | } | ||
289 | |||
290 | return !complete; | ||
291 | } | ||
292 | catch (Exception) | ||
293 | { | ||
294 | return false; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | private ushort TexturePacketCount() | ||
299 | { | ||
300 | if (!IsDecoded) | ||
301 | return 0; | ||
302 | |||
303 | if (m_asset == null) | ||
304 | return 0; | ||
305 | |||
306 | if (m_asset.Length <= FIRST_PACKET_SIZE) | ||
307 | return 1; | ||
308 | |||
309 | return (ushort)(((m_asset.Length - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1); | ||
310 | } | ||
311 | |||
312 | private int GetPacketForBytePosition(int bytePosition) | ||
313 | { | ||
314 | return ((bytePosition - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1; | ||
315 | } | ||
316 | |||
317 | private int LastPacketSize() | ||
318 | { | ||
319 | if (m_currentPacket == 1) | ||
320 | return m_asset.Length; | ||
321 | int lastsize = (m_asset.Length - FIRST_PACKET_SIZE) % IMAGE_PACKET_SIZE; | ||
322 | //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary | ||
323 | if (lastsize == 0) | ||
324 | { | ||
325 | lastsize = IMAGE_PACKET_SIZE; | ||
326 | } | ||
327 | return lastsize; | ||
328 | } | ||
329 | |||
330 | private int CurrentBytePosition() | ||
331 | { | ||
332 | if (m_currentPacket == 0) | ||
333 | return 0; | ||
334 | if (m_currentPacket == 1) | ||
335 | return FIRST_PACKET_SIZE; | ||
336 | |||
337 | int result = FIRST_PACKET_SIZE + ((int)m_currentPacket - 2) * IMAGE_PACKET_SIZE; | ||
338 | if (result < 0) | ||
339 | { | ||
340 | result = FIRST_PACKET_SIZE; | ||
341 | } | ||
342 | return result; | ||
343 | } | ||
344 | |||
345 | private void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers) | ||
346 | { | ||
347 | Layers = layers; | ||
348 | IsDecoded = true; | ||
349 | RunUpdate(); | ||
350 | } | ||
351 | |||
352 | private void AssetDataCallback(UUID AssetID, AssetBase asset) | ||
353 | { | ||
354 | HasAsset = true; | ||
355 | |||
356 | if (asset == null || asset.Data == null) | ||
357 | { | ||
358 | if (m_imageManager.MissingImage != null) | ||
359 | { | ||
360 | m_asset = m_imageManager.MissingImage.Data; | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | m_asset = null; | ||
365 | IsDecoded = true; | ||
366 | } | ||
367 | } | ||
368 | else | ||
369 | { | ||
370 | m_asset = asset.Data; | ||
371 | } | ||
372 | |||
373 | RunUpdate(); | ||
374 | } | ||
375 | |||
376 | private void AssetReceived(string id, Object sender, AssetBase asset) | ||
377 | { | ||
378 | UUID assetID = UUID.Zero; | ||
379 | if (asset != null) | ||
380 | assetID = asset.FullID; | ||
381 | else if ((InventoryAccessModule != null) && (sender != InventoryAccessModule)) | ||
382 | { | ||
383 | // Unfortunately we need this here, there's no other way. | ||
384 | // This is due to the fact that textures opened directly from the agent's inventory | ||
385 | // don't have any distinguishing feature. As such, in order to serve those when the | ||
386 | // foreign user is visiting, we need to try again after the first fail to the local | ||
387 | // asset service. | ||
388 | string assetServerURL = string.Empty; | ||
389 | if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) | ||
390 | { | ||
391 | m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", id); | ||
392 | AssetService.Get(assetServerURL + "/" + id, InventoryAccessModule, AssetReceived); | ||
393 | return; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | AssetDataCallback(assetID, asset); | ||
398 | |||
399 | } | ||
400 | } | ||
401 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs new file mode 100644 index 0000000..910fb76 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -0,0 +1,12218 @@ | |||
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.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | using System.Threading; | ||
35 | using System.Timers; | ||
36 | using System.Xml; | ||
37 | using log4net; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.Packets; | ||
40 | using OpenMetaverse.Messages.Linden; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | using OpenSim.Framework; | ||
43 | using OpenSim.Framework.Client; | ||
44 | using OpenSim.Framework.Statistics; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | using Timer = System.Timers.Timer; | ||
49 | using AssetLandmark = OpenSim.Framework.AssetLandmark; | ||
50 | using Nini.Config; | ||
51 | |||
52 | using System.IO; | ||
53 | |||
54 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
55 | { | ||
56 | public delegate bool PacketMethod(IClientAPI simClient, Packet packet); | ||
57 | |||
58 | /// <summary> | ||
59 | /// Handles new client connections | ||
60 | /// Constructor takes a single Packet and authenticates everything | ||
61 | /// </summary> | ||
62 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector | ||
63 | { | ||
64 | /// <value> | ||
65 | /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details. | ||
66 | /// </value> | ||
67 | protected int m_debugPacketLevel = 0; | ||
68 | |||
69 | #region Events | ||
70 | |||
71 | public event GenericMessage OnGenericMessage; | ||
72 | public event BinaryGenericMessage OnBinaryGenericMessage; | ||
73 | public event Action<IClientAPI> OnLogout; | ||
74 | public event ObjectPermissions OnObjectPermissions; | ||
75 | public event Action<IClientAPI> OnConnectionClosed; | ||
76 | public event ViewerEffectEventHandler OnViewerEffect; | ||
77 | public event ImprovedInstantMessage OnInstantMessage; | ||
78 | public event ChatMessage OnChatFromClient; | ||
79 | public event TextureRequest OnRequestTexture; | ||
80 | public event RezObject OnRezObject; | ||
81 | public event DeRezObject OnDeRezObject; | ||
82 | public event ModifyTerrain OnModifyTerrain; | ||
83 | public event Action<IClientAPI> OnRegionHandShakeReply; | ||
84 | public event GenericCall1 OnRequestWearables; | ||
85 | public event SetAppearance OnSetAppearance; | ||
86 | public event AvatarNowWearing OnAvatarNowWearing; | ||
87 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | ||
88 | public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; | ||
89 | public event UUIDNameRequest OnDetachAttachmentIntoInv; | ||
90 | public event ObjectAttach OnObjectAttach; | ||
91 | public event ObjectDeselect OnObjectDetach; | ||
92 | public event ObjectDrop OnObjectDrop; | ||
93 | public event GenericCall1 OnCompleteMovementToRegion; | ||
94 | public event UpdateAgent OnPreAgentUpdate; | ||
95 | public event UpdateAgent OnAgentUpdate; | ||
96 | public event AgentRequestSit OnAgentRequestSit; | ||
97 | public event AgentSit OnAgentSit; | ||
98 | public event AvatarPickerRequest OnAvatarPickerRequest; | ||
99 | public event StartAnim OnStartAnim; | ||
100 | public event StopAnim OnStopAnim; | ||
101 | public event Action<IClientAPI> OnRequestAvatarsData; | ||
102 | public event LinkObjects OnLinkObjects; | ||
103 | public event DelinkObjects OnDelinkObjects; | ||
104 | public event GrabObject OnGrabObject; | ||
105 | public event DeGrabObject OnDeGrabObject; | ||
106 | public event SpinStart OnSpinStart; | ||
107 | public event SpinStop OnSpinStop; | ||
108 | public event ObjectDuplicate OnObjectDuplicate; | ||
109 | public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; | ||
110 | public event MoveObject OnGrabUpdate; | ||
111 | public event SpinObject OnSpinUpdate; | ||
112 | public event AddNewPrim OnAddPrim; | ||
113 | public event RequestGodlikePowers OnRequestGodlikePowers; | ||
114 | public event GodKickUser OnGodKickUser; | ||
115 | public event ObjectExtraParams OnUpdateExtraParams; | ||
116 | public event UpdateShape OnUpdatePrimShape; | ||
117 | public event ObjectRequest OnObjectRequest; | ||
118 | public event ObjectSelect OnObjectSelect; | ||
119 | public event ObjectDeselect OnObjectDeselect; | ||
120 | public event GenericCall7 OnObjectDescription; | ||
121 | public event GenericCall7 OnObjectName; | ||
122 | public event GenericCall7 OnObjectClickAction; | ||
123 | public event GenericCall7 OnObjectMaterial; | ||
124 | public event ObjectIncludeInSearch OnObjectIncludeInSearch; | ||
125 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | ||
126 | public event UpdatePrimFlags OnUpdatePrimFlags; | ||
127 | public event UpdatePrimTexture OnUpdatePrimTexture; | ||
128 | public event UpdateVector OnUpdatePrimGroupPosition; | ||
129 | public event UpdateVector OnUpdatePrimSinglePosition; | ||
130 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | ||
131 | public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; | ||
132 | public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; | ||
133 | public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; | ||
134 | public event UpdateVector OnUpdatePrimScale; | ||
135 | public event UpdateVector OnUpdatePrimGroupScale; | ||
136 | public event StatusChange OnChildAgentStatus; | ||
137 | public event GenericCall2 OnStopMovement; | ||
138 | public event Action<UUID> OnRemoveAvatar; | ||
139 | public event RequestMapBlocks OnRequestMapBlocks; | ||
140 | public event RequestMapName OnMapNameRequest; | ||
141 | public event TeleportLocationRequest OnTeleportLocationRequest; | ||
142 | public event TeleportLandmarkRequest OnTeleportLandmarkRequest; | ||
143 | public event DisconnectUser OnDisconnectUser; | ||
144 | public event RequestAvatarProperties OnRequestAvatarProperties; | ||
145 | public event SetAlwaysRun OnSetAlwaysRun; | ||
146 | public event FetchInventory OnAgentDataUpdateRequest; | ||
147 | public event TeleportLocationRequest OnSetStartLocationRequest; | ||
148 | public event UpdateAvatarProperties OnUpdateAvatarProperties; | ||
149 | public event CreateNewInventoryItem OnCreateNewInventoryItem; | ||
150 | public event LinkInventoryItem OnLinkInventoryItem; | ||
151 | public event CreateInventoryFolder OnCreateNewInventoryFolder; | ||
152 | public event UpdateInventoryFolder OnUpdateInventoryFolder; | ||
153 | public event MoveInventoryFolder OnMoveInventoryFolder; | ||
154 | public event FetchInventoryDescendents OnFetchInventoryDescendents; | ||
155 | public event PurgeInventoryDescendents OnPurgeInventoryDescendents; | ||
156 | public event FetchInventory OnFetchInventory; | ||
157 | public event RequestTaskInventory OnRequestTaskInventory; | ||
158 | public event UpdateInventoryItem OnUpdateInventoryItem; | ||
159 | public event CopyInventoryItem OnCopyInventoryItem; | ||
160 | public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy; | ||
161 | public event MoveInventoryItem OnMoveInventoryItem; | ||
162 | public event RemoveInventoryItem OnRemoveInventoryItem; | ||
163 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | ||
164 | public event UDPAssetUploadRequest OnAssetUploadRequest; | ||
165 | public event XferReceive OnXferReceive; | ||
166 | public event RequestXfer OnRequestXfer; | ||
167 | public event ConfirmXfer OnConfirmXfer; | ||
168 | public event AbortXfer OnAbortXfer; | ||
169 | public event RequestTerrain OnRequestTerrain; | ||
170 | public event RezScript OnRezScript; | ||
171 | public event UpdateTaskInventory OnUpdateTaskInventory; | ||
172 | public event MoveTaskInventory OnMoveTaskItem; | ||
173 | public event RemoveTaskInventory OnRemoveTaskItem; | ||
174 | public event RequestAsset OnRequestAsset; | ||
175 | public event UUIDNameRequest OnNameFromUUIDRequest; | ||
176 | public event ParcelAccessListRequest OnParcelAccessListRequest; | ||
177 | public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; | ||
178 | public event ParcelPropertiesRequest OnParcelPropertiesRequest; | ||
179 | public event ParcelDivideRequest OnParcelDivideRequest; | ||
180 | public event ParcelJoinRequest OnParcelJoinRequest; | ||
181 | public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; | ||
182 | public event ParcelSelectObjects OnParcelSelectObjects; | ||
183 | public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; | ||
184 | public event ParcelAbandonRequest OnParcelAbandonRequest; | ||
185 | public event ParcelGodForceOwner OnParcelGodForceOwner; | ||
186 | public event ParcelReclaim OnParcelReclaim; | ||
187 | public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; | ||
188 | public event ParcelDeedToGroup OnParcelDeedToGroup; | ||
189 | public event RegionInfoRequest OnRegionInfoRequest; | ||
190 | public event EstateCovenantRequest OnEstateCovenantRequest; | ||
191 | public event FriendActionDelegate OnApproveFriendRequest; | ||
192 | public event FriendActionDelegate OnDenyFriendRequest; | ||
193 | public event FriendshipTermination OnTerminateFriendship; | ||
194 | public event GrantUserFriendRights OnGrantUserRights; | ||
195 | public event MoneyTransferRequest OnMoneyTransferRequest; | ||
196 | public event EconomyDataRequest OnEconomyDataRequest; | ||
197 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | ||
198 | public event ParcelBuy OnParcelBuy; | ||
199 | public event UUIDNameRequest OnTeleportHomeRequest; | ||
200 | public event UUIDNameRequest OnUUIDGroupNameRequest; | ||
201 | public event ScriptAnswer OnScriptAnswer; | ||
202 | public event RequestPayPrice OnRequestPayPrice; | ||
203 | public event ObjectSaleInfo OnObjectSaleInfo; | ||
204 | public event ObjectBuy OnObjectBuy; | ||
205 | public event BuyObjectInventory OnBuyObjectInventory; | ||
206 | public event AgentSit OnUndo; | ||
207 | public event AgentSit OnRedo; | ||
208 | public event LandUndo OnLandUndo; | ||
209 | public event ForceReleaseControls OnForceReleaseControls; | ||
210 | public event GodLandStatRequest OnLandStatRequest; | ||
211 | public event RequestObjectPropertiesFamily OnObjectGroupRequest; | ||
212 | public event DetailedEstateDataRequest OnDetailedEstateDataRequest; | ||
213 | public event SetEstateFlagsRequest OnSetEstateFlagsRequest; | ||
214 | public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; | ||
215 | public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; | ||
216 | public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; | ||
217 | public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; | ||
218 | public event SetRegionTerrainSettings OnSetRegionTerrainSettings; | ||
219 | public event BakeTerrain OnBakeTerrain; | ||
220 | public event RequestTerrain OnUploadTerrain; | ||
221 | public event EstateChangeInfo OnEstateChangeInfo; | ||
222 | public event EstateRestartSimRequest OnEstateRestartSimRequest; | ||
223 | public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; | ||
224 | public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; | ||
225 | public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; | ||
226 | public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; | ||
227 | public event EstateDebugRegionRequest OnEstateDebugRegionRequest; | ||
228 | public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; | ||
229 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | ||
230 | public event RegionHandleRequest OnRegionHandleRequest; | ||
231 | public event ParcelInfoRequest OnParcelInfoRequest; | ||
232 | public event ScriptReset OnScriptReset; | ||
233 | public event GetScriptRunning OnGetScriptRunning; | ||
234 | public event SetScriptRunning OnSetScriptRunning; | ||
235 | public event UpdateVector OnAutoPilotGo; | ||
236 | public event TerrainUnacked OnUnackedTerrain; | ||
237 | public event ActivateGesture OnActivateGesture; | ||
238 | public event DeactivateGesture OnDeactivateGesture; | ||
239 | public event ObjectOwner OnObjectOwner; | ||
240 | public event DirPlacesQuery OnDirPlacesQuery; | ||
241 | public event DirFindQuery OnDirFindQuery; | ||
242 | public event DirLandQuery OnDirLandQuery; | ||
243 | public event DirPopularQuery OnDirPopularQuery; | ||
244 | public event DirClassifiedQuery OnDirClassifiedQuery; | ||
245 | public event EventInfoRequest OnEventInfoRequest; | ||
246 | public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; | ||
247 | public event MapItemRequest OnMapItemRequest; | ||
248 | public event OfferCallingCard OnOfferCallingCard; | ||
249 | public event AcceptCallingCard OnAcceptCallingCard; | ||
250 | public event DeclineCallingCard OnDeclineCallingCard; | ||
251 | public event SoundTrigger OnSoundTrigger; | ||
252 | public event StartLure OnStartLure; | ||
253 | public event TeleportLureRequest OnTeleportLureRequest; | ||
254 | public event NetworkStats OnNetworkStatsUpdate; | ||
255 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | ||
256 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | ||
257 | public event ClassifiedDelete OnClassifiedDelete; | ||
258 | public event ClassifiedGodDelete OnClassifiedGodDelete; | ||
259 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | ||
260 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | ||
261 | public event EventGodDelete OnEventGodDelete; | ||
262 | public event ParcelDwellRequest OnParcelDwellRequest; | ||
263 | public event UserInfoRequest OnUserInfoRequest; | ||
264 | public event UpdateUserInfo OnUpdateUserInfo; | ||
265 | public event RetrieveInstantMessages OnRetrieveInstantMessages; | ||
266 | public event PickDelete OnPickDelete; | ||
267 | public event PickGodDelete OnPickGodDelete; | ||
268 | public event PickInfoUpdate OnPickInfoUpdate; | ||
269 | public event AvatarNotesUpdate OnAvatarNotesUpdate; | ||
270 | public event MuteListRequest OnMuteListRequest; | ||
271 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | ||
272 | public event PlacesQuery OnPlacesQuery; | ||
273 | public event AgentFOV OnAgentFOV; | ||
274 | public event FindAgentUpdate OnFindAgent; | ||
275 | public event TrackAgentUpdate OnTrackAgent; | ||
276 | public event NewUserReport OnUserReport; | ||
277 | public event SaveStateHandler OnSaveState; | ||
278 | public event GroupAccountSummaryRequest OnGroupAccountSummaryRequest; | ||
279 | public event GroupAccountDetailsRequest OnGroupAccountDetailsRequest; | ||
280 | public event GroupAccountTransactionsRequest OnGroupAccountTransactionsRequest; | ||
281 | public event FreezeUserUpdate OnParcelFreezeUser; | ||
282 | public event EjectUserUpdate OnParcelEjectUser; | ||
283 | public event ParcelBuyPass OnParcelBuyPass; | ||
284 | public event ParcelGodMark OnParcelGodMark; | ||
285 | public event GroupActiveProposalsRequest OnGroupActiveProposalsRequest; | ||
286 | public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; | ||
287 | public event SimWideDeletesDelegate OnSimWideDeletes; | ||
288 | public event SendPostcard OnSendPostcard; | ||
289 | public event MuteListEntryUpdate OnUpdateMuteListEntry; | ||
290 | public event MuteListEntryRemove OnRemoveMuteListEntry; | ||
291 | public event GodlikeMessage onGodlikeMessage; | ||
292 | public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; | ||
293 | |||
294 | #endregion Events | ||
295 | |||
296 | #region Class Members | ||
297 | |||
298 | // LLClientView Only | ||
299 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); | ||
300 | |||
301 | /// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary> | ||
302 | private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; | ||
303 | |||
304 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
305 | protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients | ||
306 | |||
307 | private readonly LLUDPServer m_udpServer; | ||
308 | private readonly LLUDPClient m_udpClient; | ||
309 | private readonly UUID m_sessionId; | ||
310 | private readonly UUID m_secureSessionId; | ||
311 | protected readonly UUID m_agentId; | ||
312 | private readonly uint m_circuitCode; | ||
313 | private readonly byte[] m_channelVersion = Utils.EmptyBytes; | ||
314 | private readonly Dictionary<string, UUID> m_defaultAnimations = new Dictionary<string, UUID>(); | ||
315 | private readonly IGroupsModule m_GroupsModule; | ||
316 | |||
317 | private int m_cachedTextureSerial; | ||
318 | private PriorityQueue m_entityUpdates; | ||
319 | private PriorityQueue m_entityProps; | ||
320 | private Prioritizer m_prioritizer; | ||
321 | private bool m_disableFacelights = false; | ||
322 | |||
323 | /// <value> | ||
324 | /// List used in construction of data blocks for an object update packet. This is to stop us having to | ||
325 | /// continually recreate it. | ||
326 | /// </value> | ||
327 | protected List<ObjectUpdatePacket.ObjectDataBlock> m_fullUpdateDataBlocksBuilder; | ||
328 | |||
329 | /// <value> | ||
330 | /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the | ||
331 | /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an | ||
332 | /// ownerless phantom. | ||
333 | /// | ||
334 | /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock | ||
335 | /// | ||
336 | /// </value> | ||
337 | protected HashSet<uint> m_killRecord; | ||
338 | |||
339 | // protected HashSet<uint> m_attachmentsSent; | ||
340 | |||
341 | private int m_moneyBalance; | ||
342 | private bool m_deliverPackets = true; | ||
343 | private int m_animationSequenceNumber = 1; | ||
344 | private bool m_SendLogoutPacketWhenClosing = true; | ||
345 | private AgentUpdateArgs lastarg; | ||
346 | private bool m_IsActive = true; | ||
347 | private bool m_IsLoggingOut = false; | ||
348 | |||
349 | protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); | ||
350 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers | ||
351 | protected Scene m_scene; | ||
352 | protected LLImageManager m_imageManager; | ||
353 | protected string m_firstName; | ||
354 | protected string m_lastName; | ||
355 | protected Thread m_clientThread; | ||
356 | protected Vector3 m_startpos; | ||
357 | protected EndPoint m_userEndPoint; | ||
358 | protected UUID m_activeGroupID; | ||
359 | protected string m_activeGroupName = String.Empty; | ||
360 | protected ulong m_activeGroupPowers; | ||
361 | protected Dictionary<UUID, ulong> m_groupPowers = new Dictionary<UUID, ulong>(); | ||
362 | protected int m_terrainCheckerCount; | ||
363 | protected uint m_agentFOVCounter; | ||
364 | |||
365 | protected IAssetService m_assetService; | ||
366 | private const bool m_checkPackets = true; | ||
367 | |||
368 | #endregion Class Members | ||
369 | |||
370 | #region Properties | ||
371 | |||
372 | public LLUDPClient UDPClient { get { return m_udpClient; } } | ||
373 | public LLUDPServer UDPServer { get { return m_udpServer; } } | ||
374 | public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } } | ||
375 | public UUID SecureSessionId { get { return m_secureSessionId; } } | ||
376 | public IScene Scene { get { return m_scene; } } | ||
377 | public UUID SessionId { get { return m_sessionId; } } | ||
378 | public Vector3 StartPos | ||
379 | { | ||
380 | get { return m_startpos; } | ||
381 | set { m_startpos = value; } | ||
382 | } | ||
383 | public bool DeliverPackets | ||
384 | { | ||
385 | get { return m_deliverPackets; } | ||
386 | set { | ||
387 | m_deliverPackets = value; | ||
388 | m_udpClient.m_deliverPackets = value; | ||
389 | } | ||
390 | } | ||
391 | public UUID AgentId { get { return m_agentId; } } | ||
392 | public UUID ActiveGroupId { get { return m_activeGroupID; } } | ||
393 | public string ActiveGroupName { get { return m_activeGroupName; } } | ||
394 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } | ||
395 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } | ||
396 | |||
397 | /// <summary> | ||
398 | /// Entity update queues | ||
399 | /// </summary> | ||
400 | public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } } | ||
401 | |||
402 | /// <summary> | ||
403 | /// First name of the agent/avatar represented by the client | ||
404 | /// </summary> | ||
405 | public string FirstName { get { return m_firstName; } } | ||
406 | |||
407 | /// <summary> | ||
408 | /// Last name of the agent/avatar represented by the client | ||
409 | /// </summary> | ||
410 | public string LastName { get { return m_lastName; } } | ||
411 | |||
412 | /// <summary> | ||
413 | /// Full name of the client (first name and last name) | ||
414 | /// </summary> | ||
415 | public string Name { get { return FirstName + " " + LastName; } } | ||
416 | |||
417 | public uint CircuitCode { get { return m_circuitCode; } } | ||
418 | public int MoneyBalance { get { return m_moneyBalance; } } | ||
419 | public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } | ||
420 | public bool IsActive | ||
421 | { | ||
422 | get { return m_IsActive; } | ||
423 | set { m_IsActive = value; } | ||
424 | } | ||
425 | public bool IsLoggingOut | ||
426 | { | ||
427 | get { return m_IsLoggingOut; } | ||
428 | set { m_IsLoggingOut = value; } | ||
429 | } | ||
430 | |||
431 | public bool DisableFacelights | ||
432 | { | ||
433 | get { return m_disableFacelights; } | ||
434 | set { m_disableFacelights = value; } | ||
435 | } | ||
436 | |||
437 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } | ||
438 | |||
439 | #endregion Properties | ||
440 | |||
441 | /// <summary> | ||
442 | /// Constructor | ||
443 | /// </summary> | ||
444 | public LLClientView(EndPoint remoteEP, Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, | ||
445 | UUID agentId, UUID sessionId, uint circuitCode) | ||
446 | { | ||
447 | RegisterInterface<IClientIM>(this); | ||
448 | RegisterInterface<IClientChat>(this); | ||
449 | RegisterInterface<IClientIPEndpoint>(this); | ||
450 | |||
451 | InitDefaultAnimations(); | ||
452 | |||
453 | m_scene = scene; | ||
454 | |||
455 | m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); | ||
456 | m_entityProps = new PriorityQueue(m_scene.Entities.Count); | ||
457 | m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); | ||
458 | m_killRecord = new HashSet<uint>(); | ||
459 | // m_attachmentsSent = new HashSet<uint>(); | ||
460 | |||
461 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
462 | m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); | ||
463 | m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); | ||
464 | m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion()); | ||
465 | m_agentId = agentId; | ||
466 | m_sessionId = sessionId; | ||
467 | m_secureSessionId = sessionInfo.LoginInfo.SecureSession; | ||
468 | m_circuitCode = circuitCode; | ||
469 | m_userEndPoint = remoteEP; | ||
470 | m_firstName = sessionInfo.LoginInfo.First; | ||
471 | m_lastName = sessionInfo.LoginInfo.Last; | ||
472 | m_startpos = sessionInfo.LoginInfo.StartPos; | ||
473 | m_moneyBalance = 1000; | ||
474 | |||
475 | m_udpServer = udpServer; | ||
476 | m_udpClient = udpClient; | ||
477 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; | ||
478 | m_udpClient.OnPacketStats += PopulateStats; | ||
479 | |||
480 | m_prioritizer = new Prioritizer(m_scene); | ||
481 | |||
482 | RegisterLocalPacketHandlers(); | ||
483 | } | ||
484 | |||
485 | public void SetDebugPacketLevel(int newDebug) | ||
486 | { | ||
487 | m_debugPacketLevel = newDebug; | ||
488 | } | ||
489 | |||
490 | #region Client Methods | ||
491 | |||
492 | |||
493 | /// <summary> | ||
494 | /// Shut down the client view | ||
495 | /// </summary> | ||
496 | public void Close() | ||
497 | { | ||
498 | Close(true); | ||
499 | } | ||
500 | |||
501 | /// <summary> | ||
502 | /// Shut down the client view | ||
503 | /// </summary> | ||
504 | public void Close(bool sendStop) | ||
505 | { | ||
506 | m_log.DebugFormat( | ||
507 | "[CLIENT]: Close has been called for {0} attached to scene {1}", | ||
508 | Name, m_scene.RegionInfo.RegionName); | ||
509 | |||
510 | if (sendStop) | ||
511 | { | ||
512 | // Send the STOP packet | ||
513 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
514 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
515 | } | ||
516 | |||
517 | IsActive = false; | ||
518 | |||
519 | // Shutdown the image manager | ||
520 | if (m_imageManager != null) | ||
521 | m_imageManager.Close(); | ||
522 | |||
523 | // Fire the callback for this connection closing | ||
524 | if (OnConnectionClosed != null) | ||
525 | OnConnectionClosed(this); | ||
526 | |||
527 | // Flush all of the packets out of the UDP server for this client | ||
528 | if (m_udpServer != null) | ||
529 | m_udpServer.Flush(m_udpClient); | ||
530 | |||
531 | // Remove ourselves from the scene | ||
532 | m_scene.RemoveClient(AgentId); | ||
533 | |||
534 | // We can't reach into other scenes and close the connection | ||
535 | // We need to do this over grid communications | ||
536 | //m_scene.CloseAllAgents(CircuitCode); | ||
537 | |||
538 | // Disable UDP handling for this client | ||
539 | m_udpClient.Shutdown(); | ||
540 | |||
541 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | ||
542 | //GC.Collect(); | ||
543 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | ||
544 | } | ||
545 | |||
546 | public void Kick(string message) | ||
547 | { | ||
548 | if (!ChildAgentStatus()) | ||
549 | { | ||
550 | KickUserPacket kupack = (KickUserPacket)PacketPool.Instance.GetPacket(PacketType.KickUser); | ||
551 | kupack.UserInfo.AgentID = AgentId; | ||
552 | kupack.UserInfo.SessionID = SessionId; | ||
553 | kupack.TargetBlock.TargetIP = 0; | ||
554 | kupack.TargetBlock.TargetPort = 0; | ||
555 | kupack.UserInfo.Reason = Util.StringToBytes256(message); | ||
556 | OutPacket(kupack, ThrottleOutPacketType.Task); | ||
557 | // You must sleep here or users get no message! | ||
558 | Thread.Sleep(500); | ||
559 | } | ||
560 | } | ||
561 | |||
562 | public void Stop() | ||
563 | { | ||
564 | |||
565 | } | ||
566 | |||
567 | #endregion Client Methods | ||
568 | |||
569 | #region Packet Handling | ||
570 | |||
571 | public void PopulateStats(int inPackets, int outPackets, int unAckedBytes) | ||
572 | { | ||
573 | NetworkStats handlerNetworkStatsUpdate = OnNetworkStatsUpdate; | ||
574 | if (handlerNetworkStatsUpdate != null) | ||
575 | { | ||
576 | handlerNetworkStatsUpdate(inPackets, outPackets, unAckedBytes); | ||
577 | } | ||
578 | } | ||
579 | |||
580 | public static bool AddPacketHandler(PacketType packetType, PacketMethod handler) | ||
581 | { | ||
582 | bool result = false; | ||
583 | lock (PacketHandlers) | ||
584 | { | ||
585 | if (!PacketHandlers.ContainsKey(packetType)) | ||
586 | { | ||
587 | PacketHandlers.Add(packetType, handler); | ||
588 | result = true; | ||
589 | } | ||
590 | } | ||
591 | return result; | ||
592 | } | ||
593 | |||
594 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler) | ||
595 | { | ||
596 | return AddLocalPacketHandler(packetType, handler, true); | ||
597 | } | ||
598 | |||
599 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool async) | ||
600 | { | ||
601 | bool result = false; | ||
602 | lock (m_packetHandlers) | ||
603 | { | ||
604 | if (!m_packetHandlers.ContainsKey(packetType)) | ||
605 | { | ||
606 | m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = async }); | ||
607 | result = true; | ||
608 | } | ||
609 | } | ||
610 | return result; | ||
611 | } | ||
612 | |||
613 | public bool AddGenericPacketHandler(string MethodName, GenericMessage handler) | ||
614 | { | ||
615 | MethodName = MethodName.ToLower().Trim(); | ||
616 | |||
617 | bool result = false; | ||
618 | lock (m_genericPacketHandlers) | ||
619 | { | ||
620 | if (!m_genericPacketHandlers.ContainsKey(MethodName)) | ||
621 | { | ||
622 | m_genericPacketHandlers.Add(MethodName, handler); | ||
623 | result = true; | ||
624 | } | ||
625 | } | ||
626 | return result; | ||
627 | } | ||
628 | |||
629 | /// <summary> | ||
630 | /// Try to process a packet using registered packet handlers | ||
631 | /// </summary> | ||
632 | /// <param name="packet"></param> | ||
633 | /// <returns>True if a handler was found which successfully processed the packet.</returns> | ||
634 | protected virtual bool ProcessPacketMethod(Packet packet) | ||
635 | { | ||
636 | bool result = false; | ||
637 | PacketProcessor pprocessor; | ||
638 | if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) | ||
639 | { | ||
640 | //there is a local handler for this packet type | ||
641 | if (pprocessor.Async) | ||
642 | { | ||
643 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | ||
644 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); | ||
645 | result = true; | ||
646 | } | ||
647 | else | ||
648 | { | ||
649 | result = pprocessor.method(this, packet); | ||
650 | } | ||
651 | } | ||
652 | else | ||
653 | { | ||
654 | //there is not a local handler so see if there is a Global handler | ||
655 | PacketMethod method = null; | ||
656 | bool found; | ||
657 | lock (PacketHandlers) | ||
658 | { | ||
659 | found = PacketHandlers.TryGetValue(packet.Type, out method); | ||
660 | } | ||
661 | if (found) | ||
662 | { | ||
663 | result = method(this, packet); | ||
664 | } | ||
665 | } | ||
666 | return result; | ||
667 | } | ||
668 | |||
669 | public void ProcessSpecificPacketAsync(object state) | ||
670 | { | ||
671 | AsyncPacketProcess packetObject = (AsyncPacketProcess)state; | ||
672 | |||
673 | try | ||
674 | { | ||
675 | packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack); | ||
676 | } | ||
677 | catch (Exception e) | ||
678 | { | ||
679 | // Make sure that we see any exception caused by the asynchronous operation. | ||
680 | m_log.ErrorFormat( | ||
681 | "[LLCLIENTVIEW]: Caught exception while processing {0} for {1}, {2} {3}", | ||
682 | packetObject.Pack, Name, e.Message, e.StackTrace); | ||
683 | } | ||
684 | } | ||
685 | |||
686 | #endregion Packet Handling | ||
687 | |||
688 | # region Setup | ||
689 | |||
690 | public virtual void Start() | ||
691 | { | ||
692 | m_scene.AddNewClient(this); | ||
693 | |||
694 | RefreshGroupMembership(); | ||
695 | } | ||
696 | |||
697 | # endregion | ||
698 | |||
699 | public void ActivateGesture(UUID assetId, UUID gestureId) | ||
700 | { | ||
701 | } | ||
702 | |||
703 | public void DeactivateGesture(UUID assetId, UUID gestureId) | ||
704 | { | ||
705 | } | ||
706 | |||
707 | // Sound | ||
708 | public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid, UUID ParentId, float Gain, Vector3 Position, UInt64 Handle) | ||
709 | { | ||
710 | } | ||
711 | |||
712 | #region Scene/Avatar to Client | ||
713 | |||
714 | public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) | ||
715 | { | ||
716 | RegionHandshakePacket handshake = (RegionHandshakePacket)PacketPool.Instance.GetPacket(PacketType.RegionHandshake); | ||
717 | handshake.RegionInfo = new RegionHandshakePacket.RegionInfoBlock(); | ||
718 | handshake.RegionInfo.BillableFactor = args.billableFactor; | ||
719 | handshake.RegionInfo.IsEstateManager = args.isEstateManager; | ||
720 | handshake.RegionInfo.TerrainHeightRange00 = args.terrainHeightRange0; | ||
721 | handshake.RegionInfo.TerrainHeightRange01 = args.terrainHeightRange1; | ||
722 | handshake.RegionInfo.TerrainHeightRange10 = args.terrainHeightRange2; | ||
723 | handshake.RegionInfo.TerrainHeightRange11 = args.terrainHeightRange3; | ||
724 | handshake.RegionInfo.TerrainStartHeight00 = args.terrainStartHeight0; | ||
725 | handshake.RegionInfo.TerrainStartHeight01 = args.terrainStartHeight1; | ||
726 | handshake.RegionInfo.TerrainStartHeight10 = args.terrainStartHeight2; | ||
727 | handshake.RegionInfo.TerrainStartHeight11 = args.terrainStartHeight3; | ||
728 | handshake.RegionInfo.SimAccess = args.simAccess; | ||
729 | handshake.RegionInfo.WaterHeight = args.waterHeight; | ||
730 | |||
731 | handshake.RegionInfo.RegionFlags = args.regionFlags; | ||
732 | handshake.RegionInfo.SimName = Util.StringToBytes256(args.regionName); | ||
733 | handshake.RegionInfo.SimOwner = args.SimOwner; | ||
734 | handshake.RegionInfo.TerrainBase0 = args.terrainBase0; | ||
735 | handshake.RegionInfo.TerrainBase1 = args.terrainBase1; | ||
736 | handshake.RegionInfo.TerrainBase2 = args.terrainBase2; | ||
737 | handshake.RegionInfo.TerrainBase3 = args.terrainBase3; | ||
738 | handshake.RegionInfo.TerrainDetail0 = args.terrainDetail0; | ||
739 | handshake.RegionInfo.TerrainDetail1 = args.terrainDetail1; | ||
740 | handshake.RegionInfo.TerrainDetail2 = args.terrainDetail2; | ||
741 | handshake.RegionInfo.TerrainDetail3 = args.terrainDetail3; | ||
742 | handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting? | ||
743 | handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block(); | ||
744 | handshake.RegionInfo2.RegionID = regionInfo.RegionID; | ||
745 | |||
746 | handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block(); | ||
747 | handshake.RegionInfo3.CPUClassID = 9; | ||
748 | handshake.RegionInfo3.CPURatio = 1; | ||
749 | |||
750 | handshake.RegionInfo3.ColoName = Utils.EmptyBytes; | ||
751 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | ||
752 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | ||
753 | |||
754 | OutPacket(handshake, ThrottleOutPacketType.Task); | ||
755 | } | ||
756 | |||
757 | /// <summary> | ||
758 | /// | ||
759 | /// </summary> | ||
760 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | ||
761 | { | ||
762 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | ||
763 | mov.SimData.ChannelVersion = m_channelVersion; | ||
764 | mov.AgentData.SessionID = m_sessionId; | ||
765 | mov.AgentData.AgentID = AgentId; | ||
766 | mov.Data.RegionHandle = regInfo.RegionHandle; | ||
767 | mov.Data.Timestamp = (uint)Util.UnixTimeSinceEpoch(); | ||
768 | |||
769 | if ((pos.X == 0) && (pos.Y == 0) && (pos.Z == 0)) | ||
770 | { | ||
771 | mov.Data.Position = m_startpos; | ||
772 | } | ||
773 | else | ||
774 | { | ||
775 | mov.Data.Position = pos; | ||
776 | } | ||
777 | mov.Data.LookAt = look; | ||
778 | |||
779 | // Hack to get this out immediately and skip the throttles | ||
780 | OutPacket(mov, ThrottleOutPacketType.Unknown); | ||
781 | } | ||
782 | |||
783 | public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, | ||
784 | UUID fromAgentID, byte source, byte audible) | ||
785 | { | ||
786 | ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); | ||
787 | reply.ChatData.Audible = audible; | ||
788 | reply.ChatData.Message = Util.StringToBytes1024(message); | ||
789 | reply.ChatData.ChatType = type; | ||
790 | reply.ChatData.SourceType = source; | ||
791 | reply.ChatData.Position = fromPos; | ||
792 | reply.ChatData.FromName = Util.StringToBytes256(fromName); | ||
793 | reply.ChatData.OwnerID = fromAgentID; | ||
794 | reply.ChatData.SourceID = fromAgentID; | ||
795 | |||
796 | OutPacket(reply, ThrottleOutPacketType.Unknown); | ||
797 | } | ||
798 | |||
799 | /// <summary> | ||
800 | /// Send an instant message to this client | ||
801 | /// </summary> | ||
802 | // | ||
803 | // Don't remove transaction ID! Groups and item gives need to set it! | ||
804 | public void SendInstantMessage(GridInstantMessage im) | ||
805 | { | ||
806 | if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID))) | ||
807 | { | ||
808 | ImprovedInstantMessagePacket msg | ||
809 | = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage); | ||
810 | |||
811 | msg.AgentData.AgentID = new UUID(im.fromAgentID); | ||
812 | msg.AgentData.SessionID = UUID.Zero; | ||
813 | msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); | ||
814 | msg.MessageBlock.Dialog = im.dialog; | ||
815 | msg.MessageBlock.FromGroup = im.fromGroup; | ||
816 | if (im.imSessionID == UUID.Zero.Guid) | ||
817 | msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID); | ||
818 | else | ||
819 | msg.MessageBlock.ID = new UUID(im.imSessionID); | ||
820 | msg.MessageBlock.Offline = im.offline; | ||
821 | msg.MessageBlock.ParentEstateID = im.ParentEstateID; | ||
822 | msg.MessageBlock.Position = im.Position; | ||
823 | msg.MessageBlock.RegionID = new UUID(im.RegionID); | ||
824 | msg.MessageBlock.Timestamp = im.timestamp; | ||
825 | msg.MessageBlock.ToAgentID = new UUID(im.toAgentID); | ||
826 | msg.MessageBlock.Message = Util.StringToBytes1024(im.message); | ||
827 | msg.MessageBlock.BinaryBucket = im.binaryBucket; | ||
828 | |||
829 | if (im.message.StartsWith("[grouptest]")) | ||
830 | { // this block is test code for implementing group IM - delete when group IM is finished | ||
831 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | ||
832 | if (eq != null) | ||
833 | { | ||
834 | im.dialog = 17; | ||
835 | |||
836 | //eq.ChatterboxInvitation( | ||
837 | // new UUID("00000000-68f9-1111-024e-222222111123"), | ||
838 | // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0, | ||
839 | // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket); | ||
840 | |||
841 | eq.ChatterboxInvitation( | ||
842 | new UUID("00000000-68f9-1111-024e-222222111123"), | ||
843 | "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0, | ||
844 | false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing")); | ||
845 | |||
846 | eq.ChatterBoxSessionAgentListUpdates( | ||
847 | new UUID("00000000-68f9-1111-024e-222222111123"), | ||
848 | new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false); | ||
849 | } | ||
850 | |||
851 | Console.WriteLine("SendInstantMessage: " + msg); | ||
852 | } | ||
853 | else | ||
854 | OutPacket(msg, ThrottleOutPacketType.Task); | ||
855 | } | ||
856 | } | ||
857 | |||
858 | public void SendGenericMessage(string method, List<string> message) | ||
859 | { | ||
860 | GenericMessagePacket gmp = new GenericMessagePacket(); | ||
861 | gmp.MethodData.Method = Util.StringToBytes256(method); | ||
862 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; | ||
863 | int i = 0; | ||
864 | foreach (string val in message) | ||
865 | { | ||
866 | gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); | ||
867 | gmp.ParamList[i++].Parameter = Util.StringToBytes256(val); | ||
868 | } | ||
869 | |||
870 | OutPacket(gmp, ThrottleOutPacketType.Task); | ||
871 | } | ||
872 | |||
873 | public void SendGenericMessage(string method, List<byte[]> message) | ||
874 | { | ||
875 | GenericMessagePacket gmp = new GenericMessagePacket(); | ||
876 | gmp.MethodData.Method = Util.StringToBytes256(method); | ||
877 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; | ||
878 | int i = 0; | ||
879 | foreach (byte[] val in message) | ||
880 | { | ||
881 | gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); | ||
882 | gmp.ParamList[i++].Parameter = val; | ||
883 | } | ||
884 | |||
885 | OutPacket(gmp, ThrottleOutPacketType.Task); | ||
886 | } | ||
887 | |||
888 | public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals) | ||
889 | { | ||
890 | int i = 0; | ||
891 | foreach (GroupActiveProposals Proposal in Proposals) | ||
892 | { | ||
893 | GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket(); | ||
894 | |||
895 | GAPIRP.AgentData.AgentID = AgentId; | ||
896 | GAPIRP.AgentData.GroupID = groupID; | ||
897 | GAPIRP.TransactionData.TransactionID = transactionID; | ||
898 | GAPIRP.TransactionData.TotalNumItems = ((uint)i+1); | ||
899 | GroupActiveProposalItemReplyPacket.ProposalDataBlock ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock(); | ||
900 | GAPIRP.ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock[1]; | ||
901 | ProposalData.VoteCast = Utils.StringToBytes("false"); | ||
902 | ProposalData.VoteID = new UUID(Proposal.VoteID); | ||
903 | ProposalData.VoteInitiator = new UUID(Proposal.VoteInitiator); | ||
904 | ProposalData.Majority = (float)Convert.ToInt32(Proposal.Majority); | ||
905 | ProposalData.Quorum = Convert.ToInt32(Proposal.Quorum); | ||
906 | ProposalData.TerseDateID = Utils.StringToBytes(Proposal.TerseDateID); | ||
907 | ProposalData.StartDateTime = Utils.StringToBytes(Proposal.StartDateTime); | ||
908 | ProposalData.EndDateTime = Utils.StringToBytes(Proposal.EndDateTime); | ||
909 | ProposalData.ProposalText = Utils.StringToBytes(Proposal.ProposalText); | ||
910 | ProposalData.AlreadyVoted = false; | ||
911 | GAPIRP.ProposalData[i] = ProposalData; | ||
912 | OutPacket(GAPIRP, ThrottleOutPacketType.Task); | ||
913 | i++; | ||
914 | } | ||
915 | if (Proposals.Length == 0) | ||
916 | { | ||
917 | GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket(); | ||
918 | |||
919 | GAPIRP.AgentData.AgentID = AgentId; | ||
920 | GAPIRP.AgentData.GroupID = groupID; | ||
921 | GAPIRP.TransactionData.TransactionID = transactionID; | ||
922 | GAPIRP.TransactionData.TotalNumItems = 1; | ||
923 | GroupActiveProposalItemReplyPacket.ProposalDataBlock ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock(); | ||
924 | GAPIRP.ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock[1]; | ||
925 | ProposalData.VoteCast = Utils.StringToBytes("false"); | ||
926 | ProposalData.VoteID = UUID.Zero; | ||
927 | ProposalData.VoteInitiator = UUID.Zero; | ||
928 | ProposalData.Majority = 0; | ||
929 | ProposalData.Quorum = 0; | ||
930 | ProposalData.TerseDateID = Utils.StringToBytes(""); | ||
931 | ProposalData.StartDateTime = Utils.StringToBytes(""); | ||
932 | ProposalData.EndDateTime = Utils.StringToBytes(""); | ||
933 | ProposalData.ProposalText = Utils.StringToBytes(""); | ||
934 | ProposalData.AlreadyVoted = false; | ||
935 | GAPIRP.ProposalData[0] = ProposalData; | ||
936 | OutPacket(GAPIRP, ThrottleOutPacketType.Task); | ||
937 | } | ||
938 | } | ||
939 | |||
940 | public void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes) | ||
941 | { | ||
942 | int i = 0; | ||
943 | foreach (GroupVoteHistory Vote in Votes) | ||
944 | { | ||
945 | GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket(); | ||
946 | |||
947 | GVHIRP.AgentData.AgentID = AgentId; | ||
948 | GVHIRP.AgentData.GroupID = groupID; | ||
949 | GVHIRP.TransactionData.TransactionID = transactionID; | ||
950 | GVHIRP.TransactionData.TotalNumItems = ((uint)i+1); | ||
951 | GVHIRP.HistoryItemData.VoteID = new UUID(Vote.VoteID); | ||
952 | GVHIRP.HistoryItemData.VoteInitiator = new UUID(Vote.VoteInitiator); | ||
953 | GVHIRP.HistoryItemData.Majority = (float)Convert.ToInt32(Vote.Majority); | ||
954 | GVHIRP.HistoryItemData.Quorum = Convert.ToInt32(Vote.Quorum); | ||
955 | GVHIRP.HistoryItemData.TerseDateID = Utils.StringToBytes(Vote.TerseDateID); | ||
956 | GVHIRP.HistoryItemData.StartDateTime = Utils.StringToBytes(Vote.StartDateTime); | ||
957 | GVHIRP.HistoryItemData.EndDateTime = Utils.StringToBytes(Vote.EndDateTime); | ||
958 | GVHIRP.HistoryItemData.VoteType = Utils.StringToBytes(Vote.VoteType); | ||
959 | GVHIRP.HistoryItemData.VoteResult = Utils.StringToBytes(Vote.VoteResult); | ||
960 | GVHIRP.HistoryItemData.ProposalText = Utils.StringToBytes(Vote.ProposalText); | ||
961 | GroupVoteHistoryItemReplyPacket.VoteItemBlock VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock(); | ||
962 | GVHIRP.VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock[1]; | ||
963 | VoteItem.CandidateID = UUID.Zero; | ||
964 | VoteItem.NumVotes = 0; //TODO: FIX THIS!!! | ||
965 | VoteItem.VoteCast = Utils.StringToBytes("Yes"); | ||
966 | GVHIRP.VoteItem[i] = VoteItem; | ||
967 | OutPacket(GVHIRP, ThrottleOutPacketType.Task); | ||
968 | i++; | ||
969 | } | ||
970 | if (Votes.Length == 0) | ||
971 | { | ||
972 | GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket(); | ||
973 | |||
974 | GVHIRP.AgentData.AgentID = AgentId; | ||
975 | GVHIRP.AgentData.GroupID = groupID; | ||
976 | GVHIRP.TransactionData.TransactionID = transactionID; | ||
977 | GVHIRP.TransactionData.TotalNumItems = 0; | ||
978 | GVHIRP.HistoryItemData.VoteID = UUID.Zero; | ||
979 | GVHIRP.HistoryItemData.VoteInitiator = UUID.Zero; | ||
980 | GVHIRP.HistoryItemData.Majority = 0; | ||
981 | GVHIRP.HistoryItemData.Quorum = 0; | ||
982 | GVHIRP.HistoryItemData.TerseDateID = Utils.StringToBytes(""); | ||
983 | GVHIRP.HistoryItemData.StartDateTime = Utils.StringToBytes(""); | ||
984 | GVHIRP.HistoryItemData.EndDateTime = Utils.StringToBytes(""); | ||
985 | GVHIRP.HistoryItemData.VoteType = Utils.StringToBytes(""); | ||
986 | GVHIRP.HistoryItemData.VoteResult = Utils.StringToBytes(""); | ||
987 | GVHIRP.HistoryItemData.ProposalText = Utils.StringToBytes(""); | ||
988 | GroupVoteHistoryItemReplyPacket.VoteItemBlock VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock(); | ||
989 | GVHIRP.VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock[1]; | ||
990 | VoteItem.CandidateID = UUID.Zero; | ||
991 | VoteItem.NumVotes = 0; //TODO: FIX THIS!!! | ||
992 | VoteItem.VoteCast = Utils.StringToBytes("No"); | ||
993 | GVHIRP.VoteItem[0] = VoteItem; | ||
994 | OutPacket(GVHIRP, ThrottleOutPacketType.Task); | ||
995 | } | ||
996 | } | ||
997 | |||
998 | public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) | ||
999 | { | ||
1000 | GroupAccountDetailsReplyPacket GADRP = new GroupAccountDetailsReplyPacket(); | ||
1001 | GADRP.AgentData = new GroupAccountDetailsReplyPacket.AgentDataBlock(); | ||
1002 | GADRP.AgentData.AgentID = sender.AgentId; | ||
1003 | GADRP.AgentData.GroupID = groupID; | ||
1004 | GADRP.HistoryData = new GroupAccountDetailsReplyPacket.HistoryDataBlock[1]; | ||
1005 | GroupAccountDetailsReplyPacket.HistoryDataBlock History = new GroupAccountDetailsReplyPacket.HistoryDataBlock(); | ||
1006 | GADRP.MoneyData = new GroupAccountDetailsReplyPacket.MoneyDataBlock(); | ||
1007 | GADRP.MoneyData.CurrentInterval = 0; | ||
1008 | GADRP.MoneyData.IntervalDays = 7; | ||
1009 | GADRP.MoneyData.RequestID = transactionID; | ||
1010 | GADRP.MoneyData.StartDate = Utils.StringToBytes(DateTime.Today.ToString()); | ||
1011 | History.Amount = amt; | ||
1012 | History.Description = Utils.StringToBytes(""); | ||
1013 | GADRP.HistoryData[0] = History; | ||
1014 | OutPacket(GADRP, ThrottleOutPacketType.Task); | ||
1015 | } | ||
1016 | |||
1017 | public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier) | ||
1018 | { | ||
1019 | GroupAccountSummaryReplyPacket GASRP = | ||
1020 | (GroupAccountSummaryReplyPacket)PacketPool.Instance.GetPacket( | ||
1021 | PacketType.GroupAccountSummaryReply); | ||
1022 | |||
1023 | GASRP.AgentData = new GroupAccountSummaryReplyPacket.AgentDataBlock(); | ||
1024 | GASRP.AgentData.AgentID = sender.AgentId; | ||
1025 | GASRP.AgentData.GroupID = groupID; | ||
1026 | GASRP.MoneyData = new GroupAccountSummaryReplyPacket.MoneyDataBlock(); | ||
1027 | GASRP.MoneyData.Balance = (int)moneyAmt; | ||
1028 | GASRP.MoneyData.TotalCredits = totalTier; | ||
1029 | GASRP.MoneyData.TotalDebits = usedTier; | ||
1030 | GASRP.MoneyData.StartDate = new byte[1]; | ||
1031 | GASRP.MoneyData.CurrentInterval = 1; | ||
1032 | GASRP.MoneyData.GroupTaxCurrent = 0; | ||
1033 | GASRP.MoneyData.GroupTaxEstimate = 0; | ||
1034 | GASRP.MoneyData.IntervalDays = 0; | ||
1035 | GASRP.MoneyData.LandTaxCurrent = 0; | ||
1036 | GASRP.MoneyData.LandTaxEstimate = 0; | ||
1037 | GASRP.MoneyData.LastTaxDate = new byte[1]; | ||
1038 | GASRP.MoneyData.LightTaxCurrent = 0; | ||
1039 | GASRP.MoneyData.TaxDate = new byte[1]; | ||
1040 | GASRP.MoneyData.RequestID = sender.AgentId; | ||
1041 | GASRP.MoneyData.ParcelDirFeeEstimate = 0; | ||
1042 | GASRP.MoneyData.ParcelDirFeeCurrent = 0; | ||
1043 | GASRP.MoneyData.ObjectTaxEstimate = 0; | ||
1044 | GASRP.MoneyData.NonExemptMembers = 0; | ||
1045 | GASRP.MoneyData.ObjectTaxCurrent = 0; | ||
1046 | GASRP.MoneyData.LightTaxEstimate = 0; | ||
1047 | OutPacket(GASRP, ThrottleOutPacketType.Task); | ||
1048 | } | ||
1049 | |||
1050 | public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) | ||
1051 | { | ||
1052 | GroupAccountTransactionsReplyPacket GATRP = | ||
1053 | (GroupAccountTransactionsReplyPacket)PacketPool.Instance.GetPacket( | ||
1054 | PacketType.GroupAccountTransactionsReply); | ||
1055 | |||
1056 | GATRP.AgentData = new GroupAccountTransactionsReplyPacket.AgentDataBlock(); | ||
1057 | GATRP.AgentData.AgentID = sender.AgentId; | ||
1058 | GATRP.AgentData.GroupID = groupID; | ||
1059 | GATRP.MoneyData = new GroupAccountTransactionsReplyPacket.MoneyDataBlock(); | ||
1060 | GATRP.MoneyData.CurrentInterval = 0; | ||
1061 | GATRP.MoneyData.IntervalDays = 7; | ||
1062 | GATRP.MoneyData.RequestID = transactionID; | ||
1063 | GATRP.MoneyData.StartDate = Utils.StringToBytes(DateTime.Today.ToString()); | ||
1064 | GATRP.HistoryData = new GroupAccountTransactionsReplyPacket.HistoryDataBlock[1]; | ||
1065 | GroupAccountTransactionsReplyPacket.HistoryDataBlock History = new GroupAccountTransactionsReplyPacket.HistoryDataBlock(); | ||
1066 | History.Amount = 0; | ||
1067 | History.Item = Utils.StringToBytes(""); | ||
1068 | History.Time = Utils.StringToBytes(""); | ||
1069 | History.Type = 0; | ||
1070 | History.User = Utils.StringToBytes(""); | ||
1071 | GATRP.HistoryData[0] = History; | ||
1072 | OutPacket(GATRP, ThrottleOutPacketType.Task); | ||
1073 | } | ||
1074 | |||
1075 | /// <summary> | ||
1076 | /// Send the region heightmap to the client | ||
1077 | /// </summary> | ||
1078 | /// <param name="map">heightmap</param> | ||
1079 | public virtual void SendLayerData(float[] map) | ||
1080 | { | ||
1081 | Util.FireAndForget(DoSendLayerData, map); | ||
1082 | |||
1083 | // Send it sync, and async. It's not that much data | ||
1084 | // and it improves user experience just so much! | ||
1085 | DoSendLayerData(map); | ||
1086 | } | ||
1087 | |||
1088 | /// <summary> | ||
1089 | /// Send terrain layer information to the client. | ||
1090 | /// </summary> | ||
1091 | /// <param name="o"></param> | ||
1092 | private void DoSendLayerData(object o) | ||
1093 | { | ||
1094 | float[] map = LLHeightFieldMoronize((float[])o); | ||
1095 | |||
1096 | try | ||
1097 | { | ||
1098 | for (int y = 0; y < 16; y++) | ||
1099 | { | ||
1100 | for (int x = 0; x < 16; x+=4) | ||
1101 | { | ||
1102 | SendLayerPacket(x, y, map); | ||
1103 | } | ||
1104 | } | ||
1105 | } | ||
1106 | catch (Exception e) | ||
1107 | { | ||
1108 | m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e); | ||
1109 | } | ||
1110 | } | ||
1111 | |||
1112 | /// <summary> | ||
1113 | /// Sends a set of four patches (x, x+1, ..., x+3) to the client | ||
1114 | /// </summary> | ||
1115 | /// <param name="map">heightmap</param> | ||
1116 | /// <param name="px">X coordinate for patches 0..12</param> | ||
1117 | /// <param name="py">Y coordinate for patches 0..15</param> | ||
1118 | private void SendLayerPacket(int x, int y, float[] map) | ||
1119 | { | ||
1120 | int[] patches = new int[4]; | ||
1121 | patches[0] = x + 0 + y * 16; | ||
1122 | patches[1] = x + 1 + y * 16; | ||
1123 | patches[2] = x + 2 + y * 16; | ||
1124 | patches[3] = x + 3 + y * 16; | ||
1125 | |||
1126 | float[] heightmap = (map.Length == 65536) ? | ||
1127 | map : | ||
1128 | LLHeightFieldMoronize(map); | ||
1129 | |||
1130 | try | ||
1131 | { | ||
1132 | Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | ||
1133 | OutPacket(layerpack, ThrottleOutPacketType.Land); | ||
1134 | } | ||
1135 | catch | ||
1136 | { | ||
1137 | for (int px = x ; px < x + 4 ; px++) | ||
1138 | SendLayerData(px, y, map); | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | /// <summary> | ||
1143 | /// Sends a specified patch to a client | ||
1144 | /// </summary> | ||
1145 | /// <param name="px">Patch coordinate (x) 0..15</param> | ||
1146 | /// <param name="py">Patch coordinate (y) 0..15</param> | ||
1147 | /// <param name="map">heightmap</param> | ||
1148 | public void SendLayerData(int px, int py, float[] map) | ||
1149 | { | ||
1150 | try | ||
1151 | { | ||
1152 | int[] patches = new int[] { py * 16 + px }; | ||
1153 | float[] heightmap = (map.Length == 65536) ? | ||
1154 | map : | ||
1155 | LLHeightFieldMoronize(map); | ||
1156 | |||
1157 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | ||
1158 | layerpack.Header.Reliable = true; | ||
1159 | |||
1160 | OutPacket(layerpack, ThrottleOutPacketType.Task); | ||
1161 | } | ||
1162 | catch (Exception e) | ||
1163 | { | ||
1164 | m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e); | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | /// <summary> | ||
1169 | /// Munges heightfield into the LLUDP backed in restricted heightfield. | ||
1170 | /// </summary> | ||
1171 | /// <param name="map">float array in the base; Constants.RegionSize</param> | ||
1172 | /// <returns>float array in the base 256</returns> | ||
1173 | internal float[] LLHeightFieldMoronize(float[] map) | ||
1174 | { | ||
1175 | if (map.Length == 65536) | ||
1176 | return map; | ||
1177 | else | ||
1178 | { | ||
1179 | float[] returnmap = new float[65536]; | ||
1180 | |||
1181 | if (map.Length < 65535) | ||
1182 | { | ||
1183 | // rebase the vector stride to 256 | ||
1184 | for (int i = 0; i < Constants.RegionSize; i++) | ||
1185 | Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize); | ||
1186 | } | ||
1187 | else | ||
1188 | { | ||
1189 | for (int i = 0; i < 256; i++) | ||
1190 | Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256); | ||
1191 | } | ||
1192 | |||
1193 | //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536); | ||
1194 | |||
1195 | return returnmap; | ||
1196 | } | ||
1197 | |||
1198 | } | ||
1199 | |||
1200 | /// <summary> | ||
1201 | /// Send the wind matrix to the client | ||
1202 | /// </summary> | ||
1203 | /// <param name="windSpeeds">16x16 array of wind speeds</param> | ||
1204 | public virtual void SendWindData(Vector2[] windSpeeds) | ||
1205 | { | ||
1206 | Util.FireAndForget(DoSendWindData, windSpeeds); | ||
1207 | } | ||
1208 | |||
1209 | /// <summary> | ||
1210 | /// Send the cloud matrix to the client | ||
1211 | /// </summary> | ||
1212 | /// <param name="windSpeeds">16x16 array of cloud densities</param> | ||
1213 | public virtual void SendCloudData(float[] cloudDensity) | ||
1214 | { | ||
1215 | Util.FireAndForget(DoSendCloudData, cloudDensity); | ||
1216 | } | ||
1217 | |||
1218 | /// <summary> | ||
1219 | /// Send wind layer information to the client. | ||
1220 | /// </summary> | ||
1221 | /// <param name="o"></param> | ||
1222 | private void DoSendWindData(object o) | ||
1223 | { | ||
1224 | Vector2[] windSpeeds = (Vector2[])o; | ||
1225 | TerrainPatch[] patches = new TerrainPatch[2]; | ||
1226 | patches[0] = new TerrainPatch(); | ||
1227 | patches[0].Data = new float[16 * 16]; | ||
1228 | patches[1] = new TerrainPatch(); | ||
1229 | patches[1].Data = new float[16 * 16]; | ||
1230 | |||
1231 | for (int y = 0; y < 16; y++) | ||
1232 | { | ||
1233 | for (int x = 0; x < 16; x++) | ||
1234 | { | ||
1235 | patches[0].Data[y * 16 + x] = windSpeeds[y * 16 + x].X; | ||
1236 | patches[1].Data[y * 16 + x] = windSpeeds[y * 16 + x].Y; | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Wind); | ||
1241 | layerpack.Header.Zerocoded = true; | ||
1242 | OutPacket(layerpack, ThrottleOutPacketType.Wind); | ||
1243 | } | ||
1244 | |||
1245 | /// <summary> | ||
1246 | /// Send cloud layer information to the client. | ||
1247 | /// </summary> | ||
1248 | /// <param name="o"></param> | ||
1249 | private void DoSendCloudData(object o) | ||
1250 | { | ||
1251 | float[] cloudCover = (float[])o; | ||
1252 | TerrainPatch[] patches = new TerrainPatch[1]; | ||
1253 | patches[0] = new TerrainPatch(); | ||
1254 | patches[0].Data = new float[16 * 16]; | ||
1255 | |||
1256 | for (int y = 0; y < 16; y++) | ||
1257 | { | ||
1258 | for (int x = 0; x < 16; x++) | ||
1259 | { | ||
1260 | patches[0].Data[y * 16 + x] = cloudCover[y * 16 + x]; | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Cloud); | ||
1265 | layerpack.Header.Zerocoded = true; | ||
1266 | OutPacket(layerpack, ThrottleOutPacketType.Cloud); | ||
1267 | } | ||
1268 | |||
1269 | /// <summary> | ||
1270 | /// Tell the client that the given neighbour region is ready to receive a child agent. | ||
1271 | /// </summary> | ||
1272 | public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourEndPoint) | ||
1273 | { | ||
1274 | IPAddress neighbourIP = neighbourEndPoint.Address; | ||
1275 | ushort neighbourPort = (ushort)neighbourEndPoint.Port; | ||
1276 | |||
1277 | EnableSimulatorPacket enablesimpacket = (EnableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.EnableSimulator); | ||
1278 | // TODO: don't create new blocks if recycling an old packet | ||
1279 | enablesimpacket.SimulatorInfo = new EnableSimulatorPacket.SimulatorInfoBlock(); | ||
1280 | enablesimpacket.SimulatorInfo.Handle = neighbourHandle; | ||
1281 | |||
1282 | byte[] byteIP = neighbourIP.GetAddressBytes(); | ||
1283 | enablesimpacket.SimulatorInfo.IP = (uint)byteIP[3] << 24; | ||
1284 | enablesimpacket.SimulatorInfo.IP += (uint)byteIP[2] << 16; | ||
1285 | enablesimpacket.SimulatorInfo.IP += (uint)byteIP[1] << 8; | ||
1286 | enablesimpacket.SimulatorInfo.IP += (uint)byteIP[0]; | ||
1287 | enablesimpacket.SimulatorInfo.Port = neighbourPort; | ||
1288 | |||
1289 | enablesimpacket.Header.Reliable = true; // ESP's should be reliable. | ||
1290 | |||
1291 | OutPacket(enablesimpacket, ThrottleOutPacketType.Task); | ||
1292 | } | ||
1293 | |||
1294 | public AgentCircuitData RequestClientInfo() | ||
1295 | { | ||
1296 | AgentCircuitData agentData = new AgentCircuitData(); | ||
1297 | agentData.AgentID = AgentId; | ||
1298 | agentData.SessionID = m_sessionId; | ||
1299 | agentData.SecureSessionID = SecureSessionId; | ||
1300 | agentData.circuitcode = m_circuitCode; | ||
1301 | agentData.child = false; | ||
1302 | agentData.firstname = m_firstName; | ||
1303 | agentData.lastname = m_lastName; | ||
1304 | |||
1305 | ICapabilitiesModule capsModule = m_scene.RequestModuleInterface<ICapabilitiesModule>(); | ||
1306 | |||
1307 | if (capsModule == null) // can happen when shutting down. | ||
1308 | return agentData; | ||
1309 | |||
1310 | agentData.CapsPath = capsModule.GetCapsPath(m_agentId); | ||
1311 | agentData.ChildrenCapSeeds = new Dictionary<ulong, string>(capsModule.GetChildrenSeeds(m_agentId)); | ||
1312 | |||
1313 | return agentData; | ||
1314 | } | ||
1315 | |||
1316 | public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint, | ||
1317 | string capsURL) | ||
1318 | { | ||
1319 | Vector3 look = new Vector3(lookAt.X * 10, lookAt.Y * 10, lookAt.Z * 10); | ||
1320 | |||
1321 | //CrossedRegionPacket newSimPack = (CrossedRegionPacket)PacketPool.Instance.GetPacket(PacketType.CrossedRegion); | ||
1322 | CrossedRegionPacket newSimPack = new CrossedRegionPacket(); | ||
1323 | // TODO: don't create new blocks if recycling an old packet | ||
1324 | newSimPack.AgentData = new CrossedRegionPacket.AgentDataBlock(); | ||
1325 | newSimPack.AgentData.AgentID = AgentId; | ||
1326 | newSimPack.AgentData.SessionID = m_sessionId; | ||
1327 | newSimPack.Info = new CrossedRegionPacket.InfoBlock(); | ||
1328 | newSimPack.Info.Position = pos; | ||
1329 | newSimPack.Info.LookAt = look; | ||
1330 | newSimPack.RegionData = new CrossedRegionPacket.RegionDataBlock(); | ||
1331 | newSimPack.RegionData.RegionHandle = newRegionHandle; | ||
1332 | byte[] byteIP = externalIPEndPoint.Address.GetAddressBytes(); | ||
1333 | newSimPack.RegionData.SimIP = (uint)byteIP[3] << 24; | ||
1334 | newSimPack.RegionData.SimIP += (uint)byteIP[2] << 16; | ||
1335 | newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8; | ||
1336 | newSimPack.RegionData.SimIP += (uint)byteIP[0]; | ||
1337 | newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port; | ||
1338 | newSimPack.RegionData.SeedCapability = Util.StringToBytes256(capsURL); | ||
1339 | |||
1340 | // Hack to get this out immediately and skip throttles | ||
1341 | OutPacket(newSimPack, ThrottleOutPacketType.Unknown); | ||
1342 | } | ||
1343 | |||
1344 | internal void SendMapBlockSplit(List<MapBlockData> mapBlocks, uint flag) | ||
1345 | { | ||
1346 | MapBlockReplyPacket mapReply = (MapBlockReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapBlockReply); | ||
1347 | // TODO: don't create new blocks if recycling an old packet | ||
1348 | |||
1349 | MapBlockData[] mapBlocks2 = mapBlocks.ToArray(); | ||
1350 | |||
1351 | mapReply.AgentData.AgentID = AgentId; | ||
1352 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; | ||
1353 | mapReply.AgentData.Flags = flag; | ||
1354 | |||
1355 | for (int i = 0; i < mapBlocks2.Length; i++) | ||
1356 | { | ||
1357 | mapReply.Data[i] = new MapBlockReplyPacket.DataBlock(); | ||
1358 | mapReply.Data[i].MapImageID = mapBlocks2[i].MapImageId; | ||
1359 | //m_log.Warn(mapBlocks2[i].MapImageId.ToString()); | ||
1360 | mapReply.Data[i].X = mapBlocks2[i].X; | ||
1361 | mapReply.Data[i].Y = mapBlocks2[i].Y; | ||
1362 | mapReply.Data[i].WaterHeight = mapBlocks2[i].WaterHeight; | ||
1363 | mapReply.Data[i].Name = Utils.StringToBytes(mapBlocks2[i].Name); | ||
1364 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; | ||
1365 | mapReply.Data[i].Access = mapBlocks2[i].Access; | ||
1366 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; | ||
1367 | } | ||
1368 | OutPacket(mapReply, ThrottleOutPacketType.Land); | ||
1369 | } | ||
1370 | |||
1371 | public void SendMapBlock(List<MapBlockData> mapBlocks, uint flag) | ||
1372 | { | ||
1373 | |||
1374 | MapBlockData[] mapBlocks2 = mapBlocks.ToArray(); | ||
1375 | |||
1376 | int maxsend = 10; | ||
1377 | |||
1378 | //int packets = Math.Ceiling(mapBlocks2.Length / maxsend); | ||
1379 | |||
1380 | List<MapBlockData> sendingBlocks = new List<MapBlockData>(); | ||
1381 | |||
1382 | for (int i = 0; i < mapBlocks2.Length; i++) | ||
1383 | { | ||
1384 | sendingBlocks.Add(mapBlocks2[i]); | ||
1385 | if (((i + 1) == mapBlocks2.Length) || (((i + 1) % maxsend) == 0)) | ||
1386 | { | ||
1387 | SendMapBlockSplit(sendingBlocks, flag); | ||
1388 | sendingBlocks = new List<MapBlockData>(); | ||
1389 | } | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | public void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags) | ||
1394 | { | ||
1395 | TeleportLocalPacket tpLocal = (TeleportLocalPacket)PacketPool.Instance.GetPacket(PacketType.TeleportLocal); | ||
1396 | tpLocal.Info.AgentID = AgentId; | ||
1397 | tpLocal.Info.TeleportFlags = flags; | ||
1398 | tpLocal.Info.LocationID = 2; | ||
1399 | tpLocal.Info.LookAt = lookAt; | ||
1400 | tpLocal.Info.Position = position; | ||
1401 | |||
1402 | // Hack to get this out immediately and skip throttles | ||
1403 | OutPacket(tpLocal, ThrottleOutPacketType.Unknown); | ||
1404 | } | ||
1405 | |||
1406 | public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID, | ||
1407 | uint flags, string capsURL) | ||
1408 | { | ||
1409 | //TeleportFinishPacket teleport = (TeleportFinishPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFinish); | ||
1410 | |||
1411 | TeleportFinishPacket teleport = new TeleportFinishPacket(); | ||
1412 | teleport.Info.AgentID = AgentId; | ||
1413 | teleport.Info.RegionHandle = regionHandle; | ||
1414 | teleport.Info.SimAccess = simAccess; | ||
1415 | |||
1416 | teleport.Info.SeedCapability = Util.StringToBytes256(capsURL); | ||
1417 | |||
1418 | IPAddress oIP = newRegionEndPoint.Address; | ||
1419 | byte[] byteIP = oIP.GetAddressBytes(); | ||
1420 | uint ip = (uint)byteIP[3] << 24; | ||
1421 | ip += (uint)byteIP[2] << 16; | ||
1422 | ip += (uint)byteIP[1] << 8; | ||
1423 | ip += (uint)byteIP[0]; | ||
1424 | |||
1425 | teleport.Info.SimIP = ip; | ||
1426 | teleport.Info.SimPort = (ushort)newRegionEndPoint.Port; | ||
1427 | teleport.Info.LocationID = 4; | ||
1428 | teleport.Info.TeleportFlags = 1 << 4; | ||
1429 | |||
1430 | // Hack to get this out immediately and skip throttles. | ||
1431 | OutPacket(teleport, ThrottleOutPacketType.Unknown); | ||
1432 | } | ||
1433 | |||
1434 | /// <summary> | ||
1435 | /// Inform the client that a teleport attempt has failed | ||
1436 | /// </summary> | ||
1437 | public void SendTeleportFailed(string reason) | ||
1438 | { | ||
1439 | TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed); | ||
1440 | tpFailed.Info.AgentID = AgentId; | ||
1441 | tpFailed.Info.Reason = Util.StringToBytes256(reason); | ||
1442 | tpFailed.AlertInfo = new TeleportFailedPacket.AlertInfoBlock[0]; | ||
1443 | |||
1444 | // Hack to get this out immediately and skip throttles | ||
1445 | OutPacket(tpFailed, ThrottleOutPacketType.Unknown); | ||
1446 | } | ||
1447 | |||
1448 | /// <summary> | ||
1449 | /// | ||
1450 | /// </summary> | ||
1451 | public void SendTeleportStart(uint flags) | ||
1452 | { | ||
1453 | TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart); | ||
1454 | //TeleportStartPacket tpStart = new TeleportStartPacket(); | ||
1455 | tpStart.Info.TeleportFlags = flags; //16; // Teleport via location | ||
1456 | |||
1457 | // Hack to get this out immediately and skip throttles | ||
1458 | OutPacket(tpStart, ThrottleOutPacketType.Unknown); | ||
1459 | } | ||
1460 | |||
1461 | public void SendTeleportProgress(uint flags, string message) | ||
1462 | { | ||
1463 | TeleportProgressPacket tpProgress = (TeleportProgressPacket)PacketPool.Instance.GetPacket(PacketType.TeleportProgress); | ||
1464 | tpProgress.AgentData.AgentID = this.AgentId; | ||
1465 | tpProgress.Info.TeleportFlags = flags; | ||
1466 | tpProgress.Info.Message = Util.StringToBytes256(message); | ||
1467 | |||
1468 | // Hack to get this out immediately and skip throttles | ||
1469 | OutPacket(tpProgress, ThrottleOutPacketType.Unknown); | ||
1470 | } | ||
1471 | |||
1472 | public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) | ||
1473 | { | ||
1474 | MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply); | ||
1475 | money.MoneyData.AgentID = AgentId; | ||
1476 | money.MoneyData.TransactionID = transaction; | ||
1477 | money.MoneyData.TransactionSuccess = success; | ||
1478 | money.MoneyData.Description = description; | ||
1479 | money.MoneyData.MoneyBalance = balance; | ||
1480 | OutPacket(money, ThrottleOutPacketType.Task); | ||
1481 | } | ||
1482 | |||
1483 | public void SendPayPrice(UUID objectID, int[] payPrice) | ||
1484 | { | ||
1485 | if (payPrice[0] == 0 && | ||
1486 | payPrice[1] == 0 && | ||
1487 | payPrice[2] == 0 && | ||
1488 | payPrice[3] == 0 && | ||
1489 | payPrice[4] == 0) | ||
1490 | return; | ||
1491 | |||
1492 | PayPriceReplyPacket payPriceReply = (PayPriceReplyPacket)PacketPool.Instance.GetPacket(PacketType.PayPriceReply); | ||
1493 | payPriceReply.ObjectData.ObjectID = objectID; | ||
1494 | payPriceReply.ObjectData.DefaultPayPrice = payPrice[0]; | ||
1495 | |||
1496 | payPriceReply.ButtonData = new PayPriceReplyPacket.ButtonDataBlock[4]; | ||
1497 | payPriceReply.ButtonData[0] = new PayPriceReplyPacket.ButtonDataBlock(); | ||
1498 | payPriceReply.ButtonData[0].PayButton = payPrice[1]; | ||
1499 | payPriceReply.ButtonData[1] = new PayPriceReplyPacket.ButtonDataBlock(); | ||
1500 | payPriceReply.ButtonData[1].PayButton = payPrice[2]; | ||
1501 | payPriceReply.ButtonData[2] = new PayPriceReplyPacket.ButtonDataBlock(); | ||
1502 | payPriceReply.ButtonData[2].PayButton = payPrice[3]; | ||
1503 | payPriceReply.ButtonData[3] = new PayPriceReplyPacket.ButtonDataBlock(); | ||
1504 | payPriceReply.ButtonData[3].PayButton = payPrice[4]; | ||
1505 | |||
1506 | OutPacket(payPriceReply, ThrottleOutPacketType.Task); | ||
1507 | } | ||
1508 | |||
1509 | public void SendStartPingCheck(byte seq) | ||
1510 | { | ||
1511 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); | ||
1512 | pc.Header.Reliable = false; | ||
1513 | |||
1514 | pc.PingID.PingID = seq; | ||
1515 | // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit | ||
1516 | pc.PingID.OldestUnacked = 0; | ||
1517 | |||
1518 | OutPacket(pc, ThrottleOutPacketType.Unknown); | ||
1519 | } | ||
1520 | |||
1521 | public void SendKillObject(ulong regionHandle, List<uint> localIDs) | ||
1522 | { | ||
1523 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); | ||
1524 | |||
1525 | KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); | ||
1526 | // TODO: don't create new blocks if recycling an old packet | ||
1527 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; | ||
1528 | for (int i = 0 ; i < localIDs.Count ; i++ ) | ||
1529 | { | ||
1530 | kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock(); | ||
1531 | kill.ObjectData[i].ID = localIDs[i]; | ||
1532 | } | ||
1533 | kill.Header.Reliable = true; | ||
1534 | kill.Header.Zerocoded = true; | ||
1535 | |||
1536 | lock (m_killRecord) | ||
1537 | { | ||
1538 | if (localIDs.Count == 1) | ||
1539 | { | ||
1540 | if (m_scene.GetScenePresence(localIDs[0]) != null) | ||
1541 | { | ||
1542 | OutPacket(kill, ThrottleOutPacketType.State); | ||
1543 | return; | ||
1544 | } | ||
1545 | m_killRecord.Add(localIDs[0]); | ||
1546 | } | ||
1547 | else | ||
1548 | { | ||
1549 | lock (m_entityUpdates.SyncRoot) | ||
1550 | { | ||
1551 | foreach (uint localID in localIDs) | ||
1552 | m_killRecord.Add(localID); | ||
1553 | } | ||
1554 | } | ||
1555 | } | ||
1556 | |||
1557 | // The throttle queue used here must match that being used for | ||
1558 | // updates. Otherwise, there is a chance that a kill packet put | ||
1559 | // on a separate queue will be sent to the client before an | ||
1560 | // existing update packet on another queue. Receiving updates | ||
1561 | // after kills results in unowned and undeletable | ||
1562 | // scene objects in a viewer until that viewer is relogged in. | ||
1563 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1564 | } | ||
1565 | |||
1566 | /// <summary> | ||
1567 | /// Send information about the items contained in a folder to the client. | ||
1568 | /// | ||
1569 | /// XXX This method needs some refactoring loving | ||
1570 | /// </summary> | ||
1571 | /// <param name="ownerID">The owner of the folder</param> | ||
1572 | /// <param name="folderID">The id of the folder</param> | ||
1573 | /// <param name="items">The items contained in the folder identified by folderID</param> | ||
1574 | /// <param name="folders"></param> | ||
1575 | /// <param name="fetchFolders">Do we need to send folder information?</param> | ||
1576 | /// <param name="fetchItems">Do we need to send item information?</param> | ||
1577 | public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List<InventoryItemBase> items, | ||
1578 | List<InventoryFolderBase> folders, int version, | ||
1579 | bool fetchFolders, bool fetchItems) | ||
1580 | { | ||
1581 | // An inventory descendents packet consists of a single agent section and an inventory details | ||
1582 | // section for each inventory item. The size of each inventory item is approximately 550 bytes. | ||
1583 | // In theory, UDP has a maximum packet size of 64k, so it should be possible to send descendent | ||
1584 | // packets containing metadata for in excess of 100 items. But in practice, there may be other | ||
1585 | // factors (e.g. firewalls) restraining the maximum UDP packet size. See, | ||
1586 | // | ||
1587 | // http://opensimulator.org/mantis/view.php?id=226 | ||
1588 | // | ||
1589 | // for one example of this kind of thing. In fact, the Linden servers appear to only send about | ||
1590 | // 6 to 7 items at a time, so let's stick with 6 | ||
1591 | int MAX_ITEMS_PER_PACKET = 5; | ||
1592 | int MAX_FOLDERS_PER_PACKET = 6; | ||
1593 | |||
1594 | int totalItems = fetchItems ? items.Count : 0; | ||
1595 | int totalFolders = fetchFolders ? folders.Count : 0; | ||
1596 | int itemsSent = 0; | ||
1597 | int foldersSent = 0; | ||
1598 | int foldersToSend = 0; | ||
1599 | int itemsToSend = 0; | ||
1600 | |||
1601 | InventoryDescendentsPacket currentPacket = null; | ||
1602 | |||
1603 | // Handle empty folders | ||
1604 | // | ||
1605 | if (totalItems == 0 && totalFolders == 0) | ||
1606 | currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, 0, 0); | ||
1607 | |||
1608 | // To preserve SL compatibility, we will NOT combine folders and items in one packet | ||
1609 | // | ||
1610 | while (itemsSent < totalItems || foldersSent < totalFolders) | ||
1611 | { | ||
1612 | if (currentPacket == null) // Start a new packet | ||
1613 | { | ||
1614 | foldersToSend = totalFolders - foldersSent; | ||
1615 | if (foldersToSend > MAX_FOLDERS_PER_PACKET) | ||
1616 | foldersToSend = MAX_FOLDERS_PER_PACKET; | ||
1617 | |||
1618 | if (foldersToSend == 0) | ||
1619 | { | ||
1620 | itemsToSend = totalItems - itemsSent; | ||
1621 | if (itemsToSend > MAX_ITEMS_PER_PACKET) | ||
1622 | itemsToSend = MAX_ITEMS_PER_PACKET; | ||
1623 | } | ||
1624 | |||
1625 | currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, foldersToSend, itemsToSend); | ||
1626 | } | ||
1627 | |||
1628 | if (foldersToSend-- > 0) | ||
1629 | currentPacket.FolderData[foldersSent % MAX_FOLDERS_PER_PACKET] = CreateFolderDataBlock(folders[foldersSent++]); | ||
1630 | else if (itemsToSend-- > 0) | ||
1631 | currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]); | ||
1632 | else | ||
1633 | { | ||
1634 | OutPacket(currentPacket, ThrottleOutPacketType.Asset, false); | ||
1635 | currentPacket = null; | ||
1636 | } | ||
1637 | |||
1638 | } | ||
1639 | |||
1640 | if (currentPacket != null) | ||
1641 | OutPacket(currentPacket, ThrottleOutPacketType.Asset, false); | ||
1642 | } | ||
1643 | |||
1644 | private InventoryDescendentsPacket.FolderDataBlock CreateFolderDataBlock(InventoryFolderBase folder) | ||
1645 | { | ||
1646 | InventoryDescendentsPacket.FolderDataBlock newBlock = new InventoryDescendentsPacket.FolderDataBlock(); | ||
1647 | newBlock.FolderID = folder.ID; | ||
1648 | newBlock.Name = Util.StringToBytes256(folder.Name); | ||
1649 | newBlock.ParentID = folder.ParentID; | ||
1650 | newBlock.Type = (sbyte)folder.Type; | ||
1651 | |||
1652 | return newBlock; | ||
1653 | } | ||
1654 | |||
1655 | private InventoryDescendentsPacket.ItemDataBlock CreateItemDataBlock(InventoryItemBase item) | ||
1656 | { | ||
1657 | InventoryDescendentsPacket.ItemDataBlock newBlock = new InventoryDescendentsPacket.ItemDataBlock(); | ||
1658 | newBlock.ItemID = item.ID; | ||
1659 | newBlock.AssetID = item.AssetID; | ||
1660 | newBlock.CreatorID = item.CreatorIdAsUuid; | ||
1661 | newBlock.BaseMask = item.BasePermissions; | ||
1662 | newBlock.Description = Util.StringToBytes256(item.Description); | ||
1663 | newBlock.EveryoneMask = item.EveryOnePermissions; | ||
1664 | newBlock.OwnerMask = item.CurrentPermissions; | ||
1665 | newBlock.FolderID = item.Folder; | ||
1666 | newBlock.InvType = (sbyte)item.InvType; | ||
1667 | newBlock.Name = Util.StringToBytes256(item.Name); | ||
1668 | newBlock.NextOwnerMask = item.NextPermissions; | ||
1669 | newBlock.OwnerID = item.Owner; | ||
1670 | newBlock.Type = (sbyte)item.AssetType; | ||
1671 | |||
1672 | newBlock.GroupID = item.GroupID; | ||
1673 | newBlock.GroupOwned = item.GroupOwned; | ||
1674 | newBlock.GroupMask = item.GroupPermissions; | ||
1675 | newBlock.CreationDate = item.CreationDate; | ||
1676 | newBlock.SalePrice = item.SalePrice; | ||
1677 | newBlock.SaleType = item.SaleType; | ||
1678 | newBlock.Flags = item.Flags; | ||
1679 | |||
1680 | newBlock.CRC = | ||
1681 | Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, | ||
1682 | newBlock.InvType, newBlock.Type, | ||
1683 | newBlock.AssetID, newBlock.GroupID, | ||
1684 | newBlock.SalePrice, | ||
1685 | newBlock.OwnerID, newBlock.CreatorID, | ||
1686 | newBlock.ItemID, newBlock.FolderID, | ||
1687 | newBlock.EveryoneMask, | ||
1688 | newBlock.Flags, newBlock.OwnerMask, | ||
1689 | newBlock.GroupMask, newBlock.NextOwnerMask); | ||
1690 | |||
1691 | return newBlock; | ||
1692 | } | ||
1693 | |||
1694 | private void AddNullFolderBlockToDecendentsPacket(ref InventoryDescendentsPacket packet) | ||
1695 | { | ||
1696 | packet.FolderData = new InventoryDescendentsPacket.FolderDataBlock[1]; | ||
1697 | packet.FolderData[0] = new InventoryDescendentsPacket.FolderDataBlock(); | ||
1698 | packet.FolderData[0].FolderID = UUID.Zero; | ||
1699 | packet.FolderData[0].ParentID = UUID.Zero; | ||
1700 | packet.FolderData[0].Type = -1; | ||
1701 | packet.FolderData[0].Name = new byte[0]; | ||
1702 | } | ||
1703 | |||
1704 | private void AddNullItemBlockToDescendentsPacket(ref InventoryDescendentsPacket packet) | ||
1705 | { | ||
1706 | packet.ItemData = new InventoryDescendentsPacket.ItemDataBlock[1]; | ||
1707 | packet.ItemData[0] = new InventoryDescendentsPacket.ItemDataBlock(); | ||
1708 | packet.ItemData[0].ItemID = UUID.Zero; | ||
1709 | packet.ItemData[0].AssetID = UUID.Zero; | ||
1710 | packet.ItemData[0].CreatorID = UUID.Zero; | ||
1711 | packet.ItemData[0].BaseMask = 0; | ||
1712 | packet.ItemData[0].Description = new byte[0]; | ||
1713 | packet.ItemData[0].EveryoneMask = 0; | ||
1714 | packet.ItemData[0].OwnerMask = 0; | ||
1715 | packet.ItemData[0].FolderID = UUID.Zero; | ||
1716 | packet.ItemData[0].InvType = (sbyte)0; | ||
1717 | packet.ItemData[0].Name = new byte[0]; | ||
1718 | packet.ItemData[0].NextOwnerMask = 0; | ||
1719 | packet.ItemData[0].OwnerID = UUID.Zero; | ||
1720 | packet.ItemData[0].Type = -1; | ||
1721 | |||
1722 | packet.ItemData[0].GroupID = UUID.Zero; | ||
1723 | packet.ItemData[0].GroupOwned = false; | ||
1724 | packet.ItemData[0].GroupMask = 0; | ||
1725 | packet.ItemData[0].CreationDate = 0; | ||
1726 | packet.ItemData[0].SalePrice = 0; | ||
1727 | packet.ItemData[0].SaleType = 0; | ||
1728 | packet.ItemData[0].Flags = 0; | ||
1729 | |||
1730 | // No need to add CRC | ||
1731 | } | ||
1732 | |||
1733 | private InventoryDescendentsPacket CreateInventoryDescendentsPacket(UUID ownerID, UUID folderID, int version, int descendents, int folders, int items) | ||
1734 | { | ||
1735 | InventoryDescendentsPacket descend = (InventoryDescendentsPacket)PacketPool.Instance.GetPacket(PacketType.InventoryDescendents); | ||
1736 | descend.Header.Zerocoded = true; | ||
1737 | descend.AgentData.AgentID = AgentId; | ||
1738 | descend.AgentData.OwnerID = ownerID; | ||
1739 | descend.AgentData.FolderID = folderID; | ||
1740 | descend.AgentData.Version = version; | ||
1741 | descend.AgentData.Descendents = descendents; | ||
1742 | |||
1743 | if (folders > 0) | ||
1744 | descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders]; | ||
1745 | else | ||
1746 | AddNullFolderBlockToDecendentsPacket(ref descend); | ||
1747 | |||
1748 | if (items > 0) | ||
1749 | descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items]; | ||
1750 | else | ||
1751 | AddNullItemBlockToDescendentsPacket(ref descend); | ||
1752 | |||
1753 | return descend; | ||
1754 | } | ||
1755 | |||
1756 | public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item) | ||
1757 | { | ||
1758 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | ||
1759 | |||
1760 | FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply); | ||
1761 | // TODO: don't create new blocks if recycling an old packet | ||
1762 | inventoryReply.AgentData.AgentID = AgentId; | ||
1763 | inventoryReply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[1]; | ||
1764 | inventoryReply.InventoryData[0] = new FetchInventoryReplyPacket.InventoryDataBlock(); | ||
1765 | inventoryReply.InventoryData[0].ItemID = item.ID; | ||
1766 | inventoryReply.InventoryData[0].AssetID = item.AssetID; | ||
1767 | inventoryReply.InventoryData[0].CreatorID = item.CreatorIdAsUuid; | ||
1768 | inventoryReply.InventoryData[0].BaseMask = item.BasePermissions; | ||
1769 | inventoryReply.InventoryData[0].CreationDate = item.CreationDate; | ||
1770 | |||
1771 | inventoryReply.InventoryData[0].Description = Util.StringToBytes256(item.Description); | ||
1772 | inventoryReply.InventoryData[0].EveryoneMask = item.EveryOnePermissions; | ||
1773 | inventoryReply.InventoryData[0].FolderID = item.Folder; | ||
1774 | inventoryReply.InventoryData[0].InvType = (sbyte)item.InvType; | ||
1775 | inventoryReply.InventoryData[0].Name = Util.StringToBytes256(item.Name); | ||
1776 | inventoryReply.InventoryData[0].NextOwnerMask = item.NextPermissions; | ||
1777 | inventoryReply.InventoryData[0].OwnerID = item.Owner; | ||
1778 | inventoryReply.InventoryData[0].OwnerMask = item.CurrentPermissions; | ||
1779 | inventoryReply.InventoryData[0].Type = (sbyte)item.AssetType; | ||
1780 | |||
1781 | inventoryReply.InventoryData[0].GroupID = item.GroupID; | ||
1782 | inventoryReply.InventoryData[0].GroupOwned = item.GroupOwned; | ||
1783 | inventoryReply.InventoryData[0].GroupMask = item.GroupPermissions; | ||
1784 | inventoryReply.InventoryData[0].Flags = item.Flags; | ||
1785 | inventoryReply.InventoryData[0].SalePrice = item.SalePrice; | ||
1786 | inventoryReply.InventoryData[0].SaleType = item.SaleType; | ||
1787 | |||
1788 | inventoryReply.InventoryData[0].CRC = | ||
1789 | Helpers.InventoryCRC( | ||
1790 | 1000, 0, inventoryReply.InventoryData[0].InvType, | ||
1791 | inventoryReply.InventoryData[0].Type, inventoryReply.InventoryData[0].AssetID, | ||
1792 | inventoryReply.InventoryData[0].GroupID, 100, | ||
1793 | inventoryReply.InventoryData[0].OwnerID, inventoryReply.InventoryData[0].CreatorID, | ||
1794 | inventoryReply.InventoryData[0].ItemID, inventoryReply.InventoryData[0].FolderID, | ||
1795 | FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, | ||
1796 | FULL_MASK_PERMISSIONS); | ||
1797 | inventoryReply.Header.Zerocoded = true; | ||
1798 | OutPacket(inventoryReply, ThrottleOutPacketType.Asset); | ||
1799 | } | ||
1800 | |||
1801 | protected void SendBulkUpdateInventoryFolder(InventoryFolderBase folderBase) | ||
1802 | { | ||
1803 | // We will use the same transaction id for all the separate packets to be sent out in this update. | ||
1804 | UUID transactionId = UUID.Random(); | ||
1805 | |||
1806 | List<BulkUpdateInventoryPacket.FolderDataBlock> folderDataBlocks | ||
1807 | = new List<BulkUpdateInventoryPacket.FolderDataBlock>(); | ||
1808 | |||
1809 | SendBulkUpdateInventoryFolderRecursive(folderBase, ref folderDataBlocks, transactionId); | ||
1810 | |||
1811 | if (folderDataBlocks.Count > 0) | ||
1812 | { | ||
1813 | // We'll end up with some unsent folder blocks if there were some empty folders at the end of the list | ||
1814 | // Send these now | ||
1815 | BulkUpdateInventoryPacket bulkUpdate | ||
1816 | = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); | ||
1817 | bulkUpdate.Header.Zerocoded = true; | ||
1818 | |||
1819 | bulkUpdate.AgentData.AgentID = AgentId; | ||
1820 | bulkUpdate.AgentData.TransactionID = transactionId; | ||
1821 | bulkUpdate.FolderData = folderDataBlocks.ToArray(); | ||
1822 | List<BulkUpdateInventoryPacket.ItemDataBlock> foo = new List<BulkUpdateInventoryPacket.ItemDataBlock>(); | ||
1823 | bulkUpdate.ItemData = foo.ToArray(); | ||
1824 | |||
1825 | //m_log.Debug("SendBulkUpdateInventory :" + bulkUpdate); | ||
1826 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); | ||
1827 | } | ||
1828 | } | ||
1829 | |||
1830 | /// <summary> | ||
1831 | /// Recursively construct bulk update packets to send folders and items | ||
1832 | /// </summary> | ||
1833 | /// <param name="folder"></param> | ||
1834 | /// <param name="folderDataBlocks"></param> | ||
1835 | /// <param name="transactionId"></param> | ||
1836 | private void SendBulkUpdateInventoryFolderRecursive( | ||
1837 | InventoryFolderBase folder, ref List<BulkUpdateInventoryPacket.FolderDataBlock> folderDataBlocks, | ||
1838 | UUID transactionId) | ||
1839 | { | ||
1840 | folderDataBlocks.Add(GenerateBulkUpdateFolderDataBlock(folder)); | ||
1841 | |||
1842 | const int MAX_ITEMS_PER_PACKET = 5; | ||
1843 | |||
1844 | IInventoryService invService = m_scene.RequestModuleInterface<IInventoryService>(); | ||
1845 | // If there are any items then we have to start sending them off in this packet - the next folder will have | ||
1846 | // to be in its own bulk update packet. Also, we can only fit 5 items in a packet (at least this was the limit | ||
1847 | // being used on the Linden grid at 20081203). | ||
1848 | InventoryCollection contents = invService.GetFolderContent(AgentId, folder.ID); // folder.RequestListOfItems(); | ||
1849 | List<InventoryItemBase> items = contents.Items; | ||
1850 | while (items.Count > 0) | ||
1851 | { | ||
1852 | BulkUpdateInventoryPacket bulkUpdate | ||
1853 | = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); | ||
1854 | bulkUpdate.Header.Zerocoded = true; | ||
1855 | |||
1856 | bulkUpdate.AgentData.AgentID = AgentId; | ||
1857 | bulkUpdate.AgentData.TransactionID = transactionId; | ||
1858 | bulkUpdate.FolderData = folderDataBlocks.ToArray(); | ||
1859 | |||
1860 | int itemsToSend = (items.Count > MAX_ITEMS_PER_PACKET ? MAX_ITEMS_PER_PACKET : items.Count); | ||
1861 | bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[itemsToSend]; | ||
1862 | |||
1863 | for (int i = 0; i < itemsToSend; i++) | ||
1864 | { | ||
1865 | // Remove from the end of the list so that we don't incur a performance penalty | ||
1866 | bulkUpdate.ItemData[i] = GenerateBulkUpdateItemDataBlock(items[items.Count - 1]); | ||
1867 | items.RemoveAt(items.Count - 1); | ||
1868 | } | ||
1869 | |||
1870 | //m_log.Debug("SendBulkUpdateInventoryRecursive :" + bulkUpdate); | ||
1871 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); | ||
1872 | |||
1873 | folderDataBlocks = new List<BulkUpdateInventoryPacket.FolderDataBlock>(); | ||
1874 | |||
1875 | // If we're going to be sending another items packet then it needs to contain just the folder to which those | ||
1876 | // items belong. | ||
1877 | if (items.Count > 0) | ||
1878 | folderDataBlocks.Add(GenerateBulkUpdateFolderDataBlock(folder)); | ||
1879 | } | ||
1880 | |||
1881 | List<InventoryFolderBase> subFolders = contents.Folders; | ||
1882 | foreach (InventoryFolderBase subFolder in subFolders) | ||
1883 | { | ||
1884 | SendBulkUpdateInventoryFolderRecursive(subFolder, ref folderDataBlocks, transactionId); | ||
1885 | } | ||
1886 | } | ||
1887 | |||
1888 | /// <summary> | ||
1889 | /// Generate a bulk update inventory data block for the given folder | ||
1890 | /// </summary> | ||
1891 | /// <param name="folder"></param> | ||
1892 | /// <returns></returns> | ||
1893 | private BulkUpdateInventoryPacket.FolderDataBlock GenerateBulkUpdateFolderDataBlock(InventoryFolderBase folder) | ||
1894 | { | ||
1895 | BulkUpdateInventoryPacket.FolderDataBlock folderBlock = new BulkUpdateInventoryPacket.FolderDataBlock(); | ||
1896 | |||
1897 | folderBlock.FolderID = folder.ID; | ||
1898 | folderBlock.ParentID = folder.ParentID; | ||
1899 | folderBlock.Type = -1; | ||
1900 | folderBlock.Name = Util.StringToBytes256(folder.Name); | ||
1901 | |||
1902 | return folderBlock; | ||
1903 | } | ||
1904 | |||
1905 | /// <summary> | ||
1906 | /// Generate a bulk update inventory data block for the given item | ||
1907 | /// </summary> | ||
1908 | /// <param name="item"></param> | ||
1909 | /// <returns></returns> | ||
1910 | private BulkUpdateInventoryPacket.ItemDataBlock GenerateBulkUpdateItemDataBlock(InventoryItemBase item) | ||
1911 | { | ||
1912 | BulkUpdateInventoryPacket.ItemDataBlock itemBlock = new BulkUpdateInventoryPacket.ItemDataBlock(); | ||
1913 | |||
1914 | itemBlock.ItemID = item.ID; | ||
1915 | itemBlock.AssetID = item.AssetID; | ||
1916 | itemBlock.CreatorID = item.CreatorIdAsUuid; | ||
1917 | itemBlock.BaseMask = item.BasePermissions; | ||
1918 | itemBlock.Description = Util.StringToBytes256(item.Description); | ||
1919 | itemBlock.EveryoneMask = item.EveryOnePermissions; | ||
1920 | itemBlock.FolderID = item.Folder; | ||
1921 | itemBlock.InvType = (sbyte)item.InvType; | ||
1922 | itemBlock.Name = Util.StringToBytes256(item.Name); | ||
1923 | itemBlock.NextOwnerMask = item.NextPermissions; | ||
1924 | itemBlock.OwnerID = item.Owner; | ||
1925 | itemBlock.OwnerMask = item.CurrentPermissions; | ||
1926 | itemBlock.Type = (sbyte)item.AssetType; | ||
1927 | itemBlock.GroupID = item.GroupID; | ||
1928 | itemBlock.GroupOwned = item.GroupOwned; | ||
1929 | itemBlock.GroupMask = item.GroupPermissions; | ||
1930 | itemBlock.Flags = item.Flags; | ||
1931 | itemBlock.SalePrice = item.SalePrice; | ||
1932 | itemBlock.SaleType = item.SaleType; | ||
1933 | itemBlock.CreationDate = item.CreationDate; | ||
1934 | |||
1935 | itemBlock.CRC = | ||
1936 | Helpers.InventoryCRC( | ||
1937 | 1000, 0, itemBlock.InvType, | ||
1938 | itemBlock.Type, itemBlock.AssetID, | ||
1939 | itemBlock.GroupID, 100, | ||
1940 | itemBlock.OwnerID, itemBlock.CreatorID, | ||
1941 | itemBlock.ItemID, itemBlock.FolderID, | ||
1942 | (uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All, | ||
1943 | (uint)PermissionMask.All); | ||
1944 | |||
1945 | return itemBlock; | ||
1946 | } | ||
1947 | |||
1948 | public void SendBulkUpdateInventory(InventoryNodeBase node) | ||
1949 | { | ||
1950 | if (node is InventoryItemBase) | ||
1951 | SendBulkUpdateInventoryItem((InventoryItemBase)node); | ||
1952 | else if (node is InventoryFolderBase) | ||
1953 | SendBulkUpdateInventoryFolder((InventoryFolderBase)node); | ||
1954 | else | ||
1955 | m_log.ErrorFormat("[CLIENT]: Client for {0} sent unknown inventory node named {1}", Name, node.Name); | ||
1956 | } | ||
1957 | |||
1958 | protected void SendBulkUpdateInventoryItem(InventoryItemBase item) | ||
1959 | { | ||
1960 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | ||
1961 | |||
1962 | BulkUpdateInventoryPacket bulkUpdate | ||
1963 | = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); | ||
1964 | |||
1965 | bulkUpdate.AgentData.AgentID = AgentId; | ||
1966 | bulkUpdate.AgentData.TransactionID = UUID.Random(); | ||
1967 | |||
1968 | bulkUpdate.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1]; | ||
1969 | bulkUpdate.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock(); | ||
1970 | bulkUpdate.FolderData[0].FolderID = UUID.Zero; | ||
1971 | bulkUpdate.FolderData[0].ParentID = UUID.Zero; | ||
1972 | bulkUpdate.FolderData[0].Type = -1; | ||
1973 | bulkUpdate.FolderData[0].Name = new byte[0]; | ||
1974 | |||
1975 | bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1]; | ||
1976 | bulkUpdate.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock(); | ||
1977 | bulkUpdate.ItemData[0].ItemID = item.ID; | ||
1978 | bulkUpdate.ItemData[0].AssetID = item.AssetID; | ||
1979 | bulkUpdate.ItemData[0].CreatorID = item.CreatorIdAsUuid; | ||
1980 | bulkUpdate.ItemData[0].BaseMask = item.BasePermissions; | ||
1981 | bulkUpdate.ItemData[0].CreationDate = item.CreationDate; | ||
1982 | bulkUpdate.ItemData[0].Description = Util.StringToBytes256(item.Description); | ||
1983 | bulkUpdate.ItemData[0].EveryoneMask = item.EveryOnePermissions; | ||
1984 | bulkUpdate.ItemData[0].FolderID = item.Folder; | ||
1985 | bulkUpdate.ItemData[0].InvType = (sbyte)item.InvType; | ||
1986 | bulkUpdate.ItemData[0].Name = Util.StringToBytes256(item.Name); | ||
1987 | bulkUpdate.ItemData[0].NextOwnerMask = item.NextPermissions; | ||
1988 | bulkUpdate.ItemData[0].OwnerID = item.Owner; | ||
1989 | bulkUpdate.ItemData[0].OwnerMask = item.CurrentPermissions; | ||
1990 | bulkUpdate.ItemData[0].Type = (sbyte)item.AssetType; | ||
1991 | |||
1992 | bulkUpdate.ItemData[0].GroupID = item.GroupID; | ||
1993 | bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; | ||
1994 | bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; | ||
1995 | bulkUpdate.ItemData[0].Flags = item.Flags; | ||
1996 | bulkUpdate.ItemData[0].SalePrice = item.SalePrice; | ||
1997 | bulkUpdate.ItemData[0].SaleType = item.SaleType; | ||
1998 | |||
1999 | bulkUpdate.ItemData[0].CRC = | ||
2000 | Helpers.InventoryCRC(1000, 0, bulkUpdate.ItemData[0].InvType, | ||
2001 | bulkUpdate.ItemData[0].Type, bulkUpdate.ItemData[0].AssetID, | ||
2002 | bulkUpdate.ItemData[0].GroupID, 100, | ||
2003 | bulkUpdate.ItemData[0].OwnerID, bulkUpdate.ItemData[0].CreatorID, | ||
2004 | bulkUpdate.ItemData[0].ItemID, bulkUpdate.ItemData[0].FolderID, | ||
2005 | FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, | ||
2006 | FULL_MASK_PERMISSIONS); | ||
2007 | bulkUpdate.Header.Zerocoded = true; | ||
2008 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); | ||
2009 | } | ||
2010 | |||
2011 | /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> | ||
2012 | public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) | ||
2013 | { | ||
2014 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | ||
2015 | |||
2016 | UpdateCreateInventoryItemPacket InventoryReply | ||
2017 | = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket( | ||
2018 | PacketType.UpdateCreateInventoryItem); | ||
2019 | |||
2020 | // TODO: don't create new blocks if recycling an old packet | ||
2021 | InventoryReply.AgentData.AgentID = AgentId; | ||
2022 | InventoryReply.AgentData.SimApproved = true; | ||
2023 | InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; | ||
2024 | InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); | ||
2025 | InventoryReply.InventoryData[0].ItemID = Item.ID; | ||
2026 | InventoryReply.InventoryData[0].AssetID = Item.AssetID; | ||
2027 | InventoryReply.InventoryData[0].CreatorID = Item.CreatorIdAsUuid; | ||
2028 | InventoryReply.InventoryData[0].BaseMask = Item.BasePermissions; | ||
2029 | InventoryReply.InventoryData[0].Description = Util.StringToBytes256(Item.Description); | ||
2030 | InventoryReply.InventoryData[0].EveryoneMask = Item.EveryOnePermissions; | ||
2031 | InventoryReply.InventoryData[0].FolderID = Item.Folder; | ||
2032 | InventoryReply.InventoryData[0].InvType = (sbyte)Item.InvType; | ||
2033 | InventoryReply.InventoryData[0].Name = Util.StringToBytes256(Item.Name); | ||
2034 | InventoryReply.InventoryData[0].NextOwnerMask = Item.NextPermissions; | ||
2035 | InventoryReply.InventoryData[0].OwnerID = Item.Owner; | ||
2036 | InventoryReply.InventoryData[0].OwnerMask = Item.CurrentPermissions; | ||
2037 | InventoryReply.InventoryData[0].Type = (sbyte)Item.AssetType; | ||
2038 | InventoryReply.InventoryData[0].CallbackID = callbackId; | ||
2039 | |||
2040 | InventoryReply.InventoryData[0].GroupID = Item.GroupID; | ||
2041 | InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; | ||
2042 | InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; | ||
2043 | InventoryReply.InventoryData[0].Flags = Item.Flags; | ||
2044 | InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; | ||
2045 | InventoryReply.InventoryData[0].SaleType = Item.SaleType; | ||
2046 | InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; | ||
2047 | |||
2048 | InventoryReply.InventoryData[0].CRC = | ||
2049 | Helpers.InventoryCRC(1000, 0, InventoryReply.InventoryData[0].InvType, | ||
2050 | InventoryReply.InventoryData[0].Type, InventoryReply.InventoryData[0].AssetID, | ||
2051 | InventoryReply.InventoryData[0].GroupID, 100, | ||
2052 | InventoryReply.InventoryData[0].OwnerID, InventoryReply.InventoryData[0].CreatorID, | ||
2053 | InventoryReply.InventoryData[0].ItemID, InventoryReply.InventoryData[0].FolderID, | ||
2054 | FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, | ||
2055 | FULL_MASK_PERMISSIONS); | ||
2056 | InventoryReply.Header.Zerocoded = true; | ||
2057 | OutPacket(InventoryReply, ThrottleOutPacketType.Asset); | ||
2058 | } | ||
2059 | |||
2060 | public void SendRemoveInventoryItem(UUID itemID) | ||
2061 | { | ||
2062 | RemoveInventoryItemPacket remove = (RemoveInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.RemoveInventoryItem); | ||
2063 | // TODO: don't create new blocks if recycling an old packet | ||
2064 | remove.AgentData.AgentID = AgentId; | ||
2065 | remove.AgentData.SessionID = m_sessionId; | ||
2066 | remove.InventoryData = new RemoveInventoryItemPacket.InventoryDataBlock[1]; | ||
2067 | remove.InventoryData[0] = new RemoveInventoryItemPacket.InventoryDataBlock(); | ||
2068 | remove.InventoryData[0].ItemID = itemID; | ||
2069 | remove.Header.Zerocoded = true; | ||
2070 | OutPacket(remove, ThrottleOutPacketType.Asset); | ||
2071 | } | ||
2072 | |||
2073 | public void SendTakeControls(int controls, bool passToAgent, bool TakeControls) | ||
2074 | { | ||
2075 | ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange); | ||
2076 | ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1]; | ||
2077 | ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock(); | ||
2078 | ddata.Controls = (uint)controls; | ||
2079 | ddata.PassToAgent = passToAgent; | ||
2080 | ddata.TakeControls = TakeControls; | ||
2081 | data[0] = ddata; | ||
2082 | scriptcontrol.Data = data; | ||
2083 | OutPacket(scriptcontrol, ThrottleOutPacketType.Task); | ||
2084 | } | ||
2085 | |||
2086 | public void SendTaskInventory(UUID taskID, short serial, byte[] fileName) | ||
2087 | { | ||
2088 | ReplyTaskInventoryPacket replytask = (ReplyTaskInventoryPacket)PacketPool.Instance.GetPacket(PacketType.ReplyTaskInventory); | ||
2089 | replytask.InventoryData.TaskID = taskID; | ||
2090 | replytask.InventoryData.Serial = serial; | ||
2091 | replytask.InventoryData.Filename = fileName; | ||
2092 | OutPacket(replytask, ThrottleOutPacketType.Asset); | ||
2093 | } | ||
2094 | |||
2095 | public void SendXferPacket(ulong xferID, uint packet, byte[] data) | ||
2096 | { | ||
2097 | SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); | ||
2098 | sendXfer.XferID.ID = xferID; | ||
2099 | sendXfer.XferID.Packet = packet; | ||
2100 | sendXfer.DataPacket.Data = data; | ||
2101 | OutPacket(sendXfer, ThrottleOutPacketType.Asset); | ||
2102 | } | ||
2103 | |||
2104 | public void SendAbortXferPacket(ulong xferID) | ||
2105 | { | ||
2106 | AbortXferPacket xferItem = (AbortXferPacket)PacketPool.Instance.GetPacket(PacketType.AbortXfer); | ||
2107 | xferItem.XferID.ID = xferID; | ||
2108 | OutPacket(xferItem, ThrottleOutPacketType.Asset); | ||
2109 | } | ||
2110 | |||
2111 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, | ||
2112 | int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor, | ||
2113 | int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay, | ||
2114 | int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent) | ||
2115 | { | ||
2116 | EconomyDataPacket economyData = (EconomyDataPacket)PacketPool.Instance.GetPacket(PacketType.EconomyData); | ||
2117 | economyData.Info.EnergyEfficiency = EnergyEfficiency; | ||
2118 | economyData.Info.ObjectCapacity = ObjectCapacity; | ||
2119 | economyData.Info.ObjectCount = ObjectCount; | ||
2120 | economyData.Info.PriceEnergyUnit = PriceEnergyUnit; | ||
2121 | economyData.Info.PriceGroupCreate = PriceGroupCreate; | ||
2122 | economyData.Info.PriceObjectClaim = PriceObjectClaim; | ||
2123 | economyData.Info.PriceObjectRent = PriceObjectRent; | ||
2124 | economyData.Info.PriceObjectScaleFactor = PriceObjectScaleFactor; | ||
2125 | economyData.Info.PriceParcelClaim = PriceParcelClaim; | ||
2126 | economyData.Info.PriceParcelClaimFactor = PriceParcelClaimFactor; | ||
2127 | economyData.Info.PriceParcelRent = PriceParcelRent; | ||
2128 | economyData.Info.PricePublicObjectDecay = PricePublicObjectDecay; | ||
2129 | economyData.Info.PricePublicObjectDelete = PricePublicObjectDelete; | ||
2130 | economyData.Info.PriceRentLight = PriceRentLight; | ||
2131 | economyData.Info.PriceUpload = PriceUpload; | ||
2132 | economyData.Info.TeleportMinPrice = TeleportMinPrice; | ||
2133 | economyData.Info.TeleportPriceExponent = TeleportPriceExponent; | ||
2134 | economyData.Header.Reliable = true; | ||
2135 | OutPacket(economyData, ThrottleOutPacketType.Task); | ||
2136 | } | ||
2137 | |||
2138 | public void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List<AvatarPickerReplyDataArgs> Data) | ||
2139 | { | ||
2140 | //construct the AvatarPickerReply packet. | ||
2141 | AvatarPickerReplyPacket replyPacket = new AvatarPickerReplyPacket(); | ||
2142 | replyPacket.AgentData.AgentID = AgentData.AgentID; | ||
2143 | replyPacket.AgentData.QueryID = AgentData.QueryID; | ||
2144 | //int i = 0; | ||
2145 | List<AvatarPickerReplyPacket.DataBlock> data_block = new List<AvatarPickerReplyPacket.DataBlock>(); | ||
2146 | foreach (AvatarPickerReplyDataArgs arg in Data) | ||
2147 | { | ||
2148 | AvatarPickerReplyPacket.DataBlock db = new AvatarPickerReplyPacket.DataBlock(); | ||
2149 | db.AvatarID = arg.AvatarID; | ||
2150 | db.FirstName = arg.FirstName; | ||
2151 | db.LastName = arg.LastName; | ||
2152 | data_block.Add(db); | ||
2153 | } | ||
2154 | replyPacket.Data = data_block.ToArray(); | ||
2155 | OutPacket(replyPacket, ThrottleOutPacketType.Task); | ||
2156 | } | ||
2157 | |||
2158 | public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) | ||
2159 | { | ||
2160 | m_activeGroupID = activegroupid; | ||
2161 | m_activeGroupName = groupname; | ||
2162 | m_activeGroupPowers = grouppowers; | ||
2163 | |||
2164 | AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); | ||
2165 | sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; | ||
2166 | sendAgentDataUpdate.AgentData.AgentID = agentid; | ||
2167 | sendAgentDataUpdate.AgentData.FirstName = Util.StringToBytes256(firstname); | ||
2168 | sendAgentDataUpdate.AgentData.GroupName = Util.StringToBytes256(groupname); | ||
2169 | sendAgentDataUpdate.AgentData.GroupPowers = grouppowers; | ||
2170 | sendAgentDataUpdate.AgentData.GroupTitle = Util.StringToBytes256(grouptitle); | ||
2171 | sendAgentDataUpdate.AgentData.LastName = Util.StringToBytes256(lastname); | ||
2172 | OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task); | ||
2173 | } | ||
2174 | |||
2175 | /// <summary> | ||
2176 | /// Send an alert message to the client. On the Linden client (tested 1.19.1.4), this pops up a brief duration | ||
2177 | /// blue information box in the bottom right hand corner. | ||
2178 | /// </summary> | ||
2179 | /// <param name="message"></param> | ||
2180 | public void SendAlertMessage(string message) | ||
2181 | { | ||
2182 | AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); | ||
2183 | alertPack.AlertData = new AlertMessagePacket.AlertDataBlock(); | ||
2184 | alertPack.AlertData.Message = Util.StringToBytes256(message); | ||
2185 | alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[0]; | ||
2186 | OutPacket(alertPack, ThrottleOutPacketType.Task); | ||
2187 | } | ||
2188 | |||
2189 | /// <summary> | ||
2190 | /// Send an agent alert message to the client. | ||
2191 | /// </summary> | ||
2192 | /// <param name="message"></param> | ||
2193 | /// <param name="modal">On the linden client, if this true then it displays a one button text box placed in the | ||
2194 | /// middle of the window. If false, the message is displayed in a brief duration blue information box (as for | ||
2195 | /// the AlertMessage packet).</param> | ||
2196 | public void SendAgentAlertMessage(string message, bool modal) | ||
2197 | { | ||
2198 | OutPacket(BuildAgentAlertPacket(message, modal), ThrottleOutPacketType.Task); | ||
2199 | } | ||
2200 | |||
2201 | /// <summary> | ||
2202 | /// Construct an agent alert packet | ||
2203 | /// </summary> | ||
2204 | /// <param name="message"></param> | ||
2205 | /// <param name="modal"></param> | ||
2206 | /// <returns></returns> | ||
2207 | public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal) | ||
2208 | { | ||
2209 | AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); | ||
2210 | alertPack.AgentData.AgentID = AgentId; | ||
2211 | alertPack.AlertData.Message = Util.StringToBytes256(message); | ||
2212 | alertPack.AlertData.Modal = modal; | ||
2213 | |||
2214 | return alertPack; | ||
2215 | } | ||
2216 | |||
2217 | public void SendLoadURL(string objectname, UUID objectID, UUID ownerID, bool groupOwned, string message, | ||
2218 | string url) | ||
2219 | { | ||
2220 | LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL); | ||
2221 | loadURL.Data.ObjectName = Util.StringToBytes256(objectname); | ||
2222 | loadURL.Data.ObjectID = objectID; | ||
2223 | loadURL.Data.OwnerID = ownerID; | ||
2224 | loadURL.Data.OwnerIsGroup = groupOwned; | ||
2225 | loadURL.Data.Message = Util.StringToBytes256(message); | ||
2226 | loadURL.Data.URL = Util.StringToBytes256(url); | ||
2227 | OutPacket(loadURL, ThrottleOutPacketType.Task); | ||
2228 | } | ||
2229 | |||
2230 | public void SendDialog(string objectname, UUID objectID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, string[] buttonlabels) | ||
2231 | { | ||
2232 | ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); | ||
2233 | dialog.Data.ObjectID = objectID; | ||
2234 | dialog.Data.ObjectName = Util.StringToBytes256(objectname); | ||
2235 | // this is the username of the *owner* | ||
2236 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); | ||
2237 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); | ||
2238 | dialog.Data.Message = Util.StringToBytes1024(msg); | ||
2239 | dialog.Data.ImageID = textureID; | ||
2240 | dialog.Data.ChatChannel = ch; | ||
2241 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; | ||
2242 | for (int i = 0; i < buttonlabels.Length; i++) | ||
2243 | { | ||
2244 | buttons[i] = new ScriptDialogPacket.ButtonsBlock(); | ||
2245 | buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]); | ||
2246 | } | ||
2247 | dialog.Buttons = buttons; | ||
2248 | OutPacket(dialog, ThrottleOutPacketType.Task); | ||
2249 | } | ||
2250 | |||
2251 | public void SendPreLoadSound(UUID objectID, UUID ownerID, UUID soundID) | ||
2252 | { | ||
2253 | PreloadSoundPacket preSound = (PreloadSoundPacket)PacketPool.Instance.GetPacket(PacketType.PreloadSound); | ||
2254 | // TODO: don't create new blocks if recycling an old packet | ||
2255 | preSound.DataBlock = new PreloadSoundPacket.DataBlockBlock[1]; | ||
2256 | preSound.DataBlock[0] = new PreloadSoundPacket.DataBlockBlock(); | ||
2257 | preSound.DataBlock[0].ObjectID = objectID; | ||
2258 | preSound.DataBlock[0].OwnerID = ownerID; | ||
2259 | preSound.DataBlock[0].SoundID = soundID; | ||
2260 | preSound.Header.Zerocoded = true; | ||
2261 | OutPacket(preSound, ThrottleOutPacketType.Task); | ||
2262 | } | ||
2263 | |||
2264 | public void SendPlayAttachedSound(UUID soundID, UUID objectID, UUID ownerID, float gain, byte flags) | ||
2265 | { | ||
2266 | AttachedSoundPacket sound = (AttachedSoundPacket)PacketPool.Instance.GetPacket(PacketType.AttachedSound); | ||
2267 | sound.DataBlock.SoundID = soundID; | ||
2268 | sound.DataBlock.ObjectID = objectID; | ||
2269 | sound.DataBlock.OwnerID = ownerID; | ||
2270 | sound.DataBlock.Gain = gain; | ||
2271 | sound.DataBlock.Flags = flags; | ||
2272 | |||
2273 | OutPacket(sound, ThrottleOutPacketType.Task); | ||
2274 | } | ||
2275 | |||
2276 | public void SendTransferAbort(TransferRequestPacket transferRequest) | ||
2277 | { | ||
2278 | TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort); | ||
2279 | abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID; | ||
2280 | abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType; | ||
2281 | m_log.Debug("[Assets] Aborting transfer; asset request failed"); | ||
2282 | OutPacket(abort, ThrottleOutPacketType.Task); | ||
2283 | } | ||
2284 | |||
2285 | public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) | ||
2286 | { | ||
2287 | SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); | ||
2288 | sound.SoundData.SoundID = soundID; | ||
2289 | sound.SoundData.OwnerID = ownerID; | ||
2290 | sound.SoundData.ObjectID = objectID; | ||
2291 | sound.SoundData.ParentID = parentID; | ||
2292 | sound.SoundData.Handle = handle; | ||
2293 | sound.SoundData.Position = position; | ||
2294 | sound.SoundData.Gain = gain; | ||
2295 | |||
2296 | OutPacket(sound, ThrottleOutPacketType.Task); | ||
2297 | } | ||
2298 | |||
2299 | public void SendAttachedSoundGainChange(UUID objectID, float gain) | ||
2300 | { | ||
2301 | AttachedSoundGainChangePacket sound = (AttachedSoundGainChangePacket)PacketPool.Instance.GetPacket(PacketType.AttachedSoundGainChange); | ||
2302 | sound.DataBlock.ObjectID = objectID; | ||
2303 | sound.DataBlock.Gain = gain; | ||
2304 | |||
2305 | OutPacket(sound, ThrottleOutPacketType.Task); | ||
2306 | } | ||
2307 | |||
2308 | public void SendSunPos(Vector3 Position, Vector3 Velocity, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition) | ||
2309 | { | ||
2310 | // Viewers based on the Linden viwer code, do wacky things for oribital positions from Midnight to Sunrise | ||
2311 | // So adjust for that | ||
2312 | // Contributed by: Godfrey | ||
2313 | |||
2314 | if (OrbitalPosition > m_sunPainDaHalfOrbitalCutoff) // things get weird from midnight to sunrise | ||
2315 | { | ||
2316 | OrbitalPosition = (OrbitalPosition - m_sunPainDaHalfOrbitalCutoff) * 0.6666666667f + m_sunPainDaHalfOrbitalCutoff; | ||
2317 | } | ||
2318 | |||
2319 | |||
2320 | |||
2321 | SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage); | ||
2322 | viewertime.TimeInfo.SunDirection = Position; | ||
2323 | viewertime.TimeInfo.SunAngVelocity = Velocity; | ||
2324 | |||
2325 | // Sun module used to add 6 hours to adjust for linden sun hour, adding here | ||
2326 | // to prevent existing code from breaking if it assumed that 6 hours were included. | ||
2327 | // 21600 == 6 hours * 60 minutes * 60 Seconds | ||
2328 | viewertime.TimeInfo.UsecSinceStart = CurrentTime + 21600; | ||
2329 | |||
2330 | viewertime.TimeInfo.SecPerDay = SecondsPerSunCycle; | ||
2331 | viewertime.TimeInfo.SecPerYear = SecondsPerYear; | ||
2332 | viewertime.TimeInfo.SunPhase = OrbitalPosition; | ||
2333 | viewertime.Header.Reliable = false; | ||
2334 | viewertime.Header.Zerocoded = true; | ||
2335 | OutPacket(viewertime, ThrottleOutPacketType.Task); | ||
2336 | } | ||
2337 | |||
2338 | // Currently Deprecated | ||
2339 | public void SendViewerTime(int phase) | ||
2340 | { | ||
2341 | /* | ||
2342 | Console.WriteLine("SunPhase: {0}", phase); | ||
2343 | SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage); | ||
2344 | //viewertime.TimeInfo.SecPerDay = 86400; | ||
2345 | //viewertime.TimeInfo.SecPerYear = 31536000; | ||
2346 | viewertime.TimeInfo.SecPerDay = 1000; | ||
2347 | viewertime.TimeInfo.SecPerYear = 365000; | ||
2348 | viewertime.TimeInfo.SunPhase = 1; | ||
2349 | int sunPhase = (phase + 2) / 2; | ||
2350 | if ((sunPhase < 6) || (sunPhase > 36)) | ||
2351 | { | ||
2352 | viewertime.TimeInfo.SunDirection = new Vector3(0f, 0.8f, -0.8f); | ||
2353 | Console.WriteLine("sending night"); | ||
2354 | } | ||
2355 | else | ||
2356 | { | ||
2357 | if (sunPhase < 12) | ||
2358 | { | ||
2359 | sunPhase = 12; | ||
2360 | } | ||
2361 | sunPhase = sunPhase - 12; | ||
2362 | |||
2363 | float yValue = 0.1f * (sunPhase); | ||
2364 | Console.WriteLine("Computed SunPhase: {0}, yValue: {1}", sunPhase, yValue); | ||
2365 | if (yValue > 1.2f) | ||
2366 | { | ||
2367 | yValue = yValue - 1.2f; | ||
2368 | } | ||
2369 | |||
2370 | yValue = Util.Clip(yValue, 0, 1); | ||
2371 | |||
2372 | if (sunPhase < 14) | ||
2373 | { | ||
2374 | yValue = 1 - yValue; | ||
2375 | } | ||
2376 | if (sunPhase < 12) | ||
2377 | { | ||
2378 | yValue *= -1; | ||
2379 | } | ||
2380 | viewertime.TimeInfo.SunDirection = new Vector3(0f, yValue, 0.3f); | ||
2381 | Console.WriteLine("sending sun update " + yValue); | ||
2382 | } | ||
2383 | viewertime.TimeInfo.SunAngVelocity = new Vector3(0, 0.0f, 10.0f); | ||
2384 | viewertime.TimeInfo.UsecSinceStart = (ulong)Util.UnixTimeSinceEpoch(); | ||
2385 | viewertime.Header.Reliable = false; | ||
2386 | OutPacket(viewertime, ThrottleOutPacketType.Task); | ||
2387 | */ | ||
2388 | } | ||
2389 | |||
2390 | public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks) | ||
2391 | { | ||
2392 | ViewerEffectPacket packet = (ViewerEffectPacket)PacketPool.Instance.GetPacket(PacketType.ViewerEffect); | ||
2393 | packet.Header.Reliable = false; | ||
2394 | packet.Header.Zerocoded = true; | ||
2395 | |||
2396 | packet.AgentData.AgentID = AgentId; | ||
2397 | packet.AgentData.SessionID = SessionId; | ||
2398 | |||
2399 | packet.Effect = effectBlocks; | ||
2400 | |||
2401 | // OutPacket(packet, ThrottleOutPacketType.State); | ||
2402 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2403 | } | ||
2404 | |||
2405 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | ||
2406 | string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, | ||
2407 | UUID partnerID) | ||
2408 | { | ||
2409 | AvatarPropertiesReplyPacket avatarReply = (AvatarPropertiesReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPropertiesReply); | ||
2410 | avatarReply.AgentData.AgentID = AgentId; | ||
2411 | avatarReply.AgentData.AvatarID = avatarID; | ||
2412 | if (aboutText != null) | ||
2413 | avatarReply.PropertiesData.AboutText = Util.StringToBytes1024(aboutText); | ||
2414 | else | ||
2415 | avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; | ||
2416 | avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); | ||
2417 | avatarReply.PropertiesData.CharterMember = charterMember; | ||
2418 | if (flAbout != null) | ||
2419 | avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); | ||
2420 | else | ||
2421 | avatarReply.PropertiesData.FLAboutText = Utils.EmptyBytes; | ||
2422 | avatarReply.PropertiesData.Flags = flags; | ||
2423 | avatarReply.PropertiesData.FLImageID = flImageID; | ||
2424 | avatarReply.PropertiesData.ImageID = imageID; | ||
2425 | avatarReply.PropertiesData.ProfileURL = Util.StringToBytes256(profileURL); | ||
2426 | avatarReply.PropertiesData.PartnerID = partnerID; | ||
2427 | OutPacket(avatarReply, ThrottleOutPacketType.Task); | ||
2428 | } | ||
2429 | |||
2430 | /// <summary> | ||
2431 | /// Send the client an Estate message blue box pop-down with a single OK button | ||
2432 | /// </summary> | ||
2433 | /// <param name="FromAvatarID"></param> | ||
2434 | /// <param name="fromSessionID"></param> | ||
2435 | /// <param name="FromAvatarName"></param> | ||
2436 | /// <param name="Message"></param> | ||
2437 | public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) | ||
2438 | { | ||
2439 | if (!ChildAgentStatus()) | ||
2440 | SendInstantMessage(new GridInstantMessage(null, FromAvatarID, FromAvatarName, AgentId, 1, Message, false, new Vector3())); | ||
2441 | |||
2442 | //SendInstantMessage(FromAvatarID, fromSessionID, Message, AgentId, SessionId, FromAvatarName, (byte)21,(uint) Util.UnixTimeSinceEpoch()); | ||
2443 | } | ||
2444 | |||
2445 | public void SendLogoutPacket() | ||
2446 | { | ||
2447 | // I know this is a bit of a hack, however there are times when you don't | ||
2448 | // want to send this, but still need to do the rest of the shutdown process | ||
2449 | // this method gets called from the packet server.. which makes it practically | ||
2450 | // impossible to do any other way. | ||
2451 | |||
2452 | if (m_SendLogoutPacketWhenClosing) | ||
2453 | { | ||
2454 | LogoutReplyPacket logReply = (LogoutReplyPacket)PacketPool.Instance.GetPacket(PacketType.LogoutReply); | ||
2455 | // TODO: don't create new blocks if recycling an old packet | ||
2456 | logReply.AgentData.AgentID = AgentId; | ||
2457 | logReply.AgentData.SessionID = SessionId; | ||
2458 | logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1]; | ||
2459 | logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock(); | ||
2460 | logReply.InventoryData[0].ItemID = UUID.Zero; | ||
2461 | |||
2462 | OutPacket(logReply, ThrottleOutPacketType.Task); | ||
2463 | } | ||
2464 | } | ||
2465 | |||
2466 | public void SendHealth(float health) | ||
2467 | { | ||
2468 | HealthMessagePacket healthpacket = (HealthMessagePacket)PacketPool.Instance.GetPacket(PacketType.HealthMessage); | ||
2469 | healthpacket.HealthData.Health = health; | ||
2470 | OutPacket(healthpacket, ThrottleOutPacketType.Task); | ||
2471 | } | ||
2472 | |||
2473 | public void SendAgentOnline(UUID[] agentIDs) | ||
2474 | { | ||
2475 | OnlineNotificationPacket onp = new OnlineNotificationPacket(); | ||
2476 | OnlineNotificationPacket.AgentBlockBlock[] onpb = new OnlineNotificationPacket.AgentBlockBlock[agentIDs.Length]; | ||
2477 | for (int i = 0; i < agentIDs.Length; i++) | ||
2478 | { | ||
2479 | OnlineNotificationPacket.AgentBlockBlock onpbl = new OnlineNotificationPacket.AgentBlockBlock(); | ||
2480 | onpbl.AgentID = agentIDs[i]; | ||
2481 | onpb[i] = onpbl; | ||
2482 | } | ||
2483 | onp.AgentBlock = onpb; | ||
2484 | onp.Header.Reliable = true; | ||
2485 | OutPacket(onp, ThrottleOutPacketType.Task); | ||
2486 | } | ||
2487 | |||
2488 | public void SendAgentOffline(UUID[] agentIDs) | ||
2489 | { | ||
2490 | OfflineNotificationPacket offp = new OfflineNotificationPacket(); | ||
2491 | OfflineNotificationPacket.AgentBlockBlock[] offpb = new OfflineNotificationPacket.AgentBlockBlock[agentIDs.Length]; | ||
2492 | for (int i = 0; i < agentIDs.Length; i++) | ||
2493 | { | ||
2494 | OfflineNotificationPacket.AgentBlockBlock onpbl = new OfflineNotificationPacket.AgentBlockBlock(); | ||
2495 | onpbl.AgentID = agentIDs[i]; | ||
2496 | offpb[i] = onpbl; | ||
2497 | } | ||
2498 | offp.AgentBlock = offpb; | ||
2499 | offp.Header.Reliable = true; | ||
2500 | OutPacket(offp, ThrottleOutPacketType.Task); | ||
2501 | } | ||
2502 | |||
2503 | public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, | ||
2504 | Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) | ||
2505 | { | ||
2506 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); | ||
2507 | avatarSitResponse.SitObject.ID = TargetID; | ||
2508 | if (CameraAtOffset != Vector3.Zero) | ||
2509 | { | ||
2510 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; | ||
2511 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; | ||
2512 | } | ||
2513 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; | ||
2514 | avatarSitResponse.SitTransform.AutoPilot = autopilot; | ||
2515 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; | ||
2516 | avatarSitResponse.SitTransform.SitRotation = SitOrientation; | ||
2517 | |||
2518 | OutPacket(avatarSitResponse, ThrottleOutPacketType.Task); | ||
2519 | } | ||
2520 | |||
2521 | public void SendAdminResponse(UUID Token, uint AdminLevel) | ||
2522 | { | ||
2523 | GrantGodlikePowersPacket respondPacket = new GrantGodlikePowersPacket(); | ||
2524 | GrantGodlikePowersPacket.GrantDataBlock gdb = new GrantGodlikePowersPacket.GrantDataBlock(); | ||
2525 | GrantGodlikePowersPacket.AgentDataBlock adb = new GrantGodlikePowersPacket.AgentDataBlock(); | ||
2526 | |||
2527 | adb.AgentID = AgentId; | ||
2528 | adb.SessionID = SessionId; // More security | ||
2529 | gdb.GodLevel = (byte)AdminLevel; | ||
2530 | gdb.Token = Token; | ||
2531 | //respondPacket.AgentData = (GrantGodlikePowersPacket.AgentDataBlock)ablock; | ||
2532 | respondPacket.GrantData = gdb; | ||
2533 | respondPacket.AgentData = adb; | ||
2534 | OutPacket(respondPacket, ThrottleOutPacketType.Task); | ||
2535 | } | ||
2536 | |||
2537 | public void SendGroupMembership(GroupMembershipData[] GroupMembership) | ||
2538 | { | ||
2539 | m_groupPowers.Clear(); | ||
2540 | |||
2541 | AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket(); | ||
2542 | AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[GroupMembership.Length]; | ||
2543 | for (int i = 0; i < GroupMembership.Length; i++) | ||
2544 | { | ||
2545 | m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers; | ||
2546 | |||
2547 | AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock(); | ||
2548 | Group.AcceptNotices = GroupMembership[i].AcceptNotices; | ||
2549 | Group.Contribution = GroupMembership[i].Contribution; | ||
2550 | Group.GroupID = GroupMembership[i].GroupID; | ||
2551 | Group.GroupInsigniaID = GroupMembership[i].GroupPicture; | ||
2552 | Group.GroupName = Util.StringToBytes256(GroupMembership[i].GroupName); | ||
2553 | Group.GroupPowers = GroupMembership[i].GroupPowers; | ||
2554 | Groups[i] = Group; | ||
2555 | |||
2556 | |||
2557 | } | ||
2558 | Groupupdate.GroupData = Groups; | ||
2559 | Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock(); | ||
2560 | Groupupdate.AgentData.AgentID = AgentId; | ||
2561 | OutPacket(Groupupdate, ThrottleOutPacketType.Task); | ||
2562 | |||
2563 | try | ||
2564 | { | ||
2565 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | ||
2566 | if (eq != null) | ||
2567 | { | ||
2568 | eq.GroupMembership(Groupupdate, this.AgentId); | ||
2569 | } | ||
2570 | } | ||
2571 | catch (Exception ex) | ||
2572 | { | ||
2573 | m_log.Error("Unable to send group membership data via eventqueue - exception: " + ex.ToString()); | ||
2574 | m_log.Warn("sending group membership data via UDP"); | ||
2575 | OutPacket(Groupupdate, ThrottleOutPacketType.Task); | ||
2576 | } | ||
2577 | } | ||
2578 | |||
2579 | |||
2580 | public void SendGroupNameReply(UUID groupLLUID, string GroupName) | ||
2581 | { | ||
2582 | UUIDGroupNameReplyPacket pack = new UUIDGroupNameReplyPacket(); | ||
2583 | UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] uidnameblock = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock[1]; | ||
2584 | UUIDGroupNameReplyPacket.UUIDNameBlockBlock uidnamebloc = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock(); | ||
2585 | uidnamebloc.ID = groupLLUID; | ||
2586 | uidnamebloc.GroupName = Util.StringToBytes256(GroupName); | ||
2587 | uidnameblock[0] = uidnamebloc; | ||
2588 | pack.UUIDNameBlock = uidnameblock; | ||
2589 | OutPacket(pack, ThrottleOutPacketType.Task); | ||
2590 | } | ||
2591 | |||
2592 | public void SendLandStatReply(uint reportType, uint requestFlags, uint resultCount, LandStatReportItem[] lsrpia) | ||
2593 | { | ||
2594 | LandStatReplyPacket lsrp = new LandStatReplyPacket(); | ||
2595 | // LandStatReplyPacket.RequestDataBlock lsreqdpb = new LandStatReplyPacket.RequestDataBlock(); | ||
2596 | LandStatReplyPacket.ReportDataBlock[] lsrepdba = new LandStatReplyPacket.ReportDataBlock[lsrpia.Length]; | ||
2597 | //LandStatReplyPacket.ReportDataBlock lsrepdb = new LandStatReplyPacket.ReportDataBlock(); | ||
2598 | // lsrepdb. | ||
2599 | lsrp.RequestData.ReportType = reportType; | ||
2600 | lsrp.RequestData.RequestFlags = requestFlags; | ||
2601 | lsrp.RequestData.TotalObjectCount = resultCount; | ||
2602 | for (int i = 0; i < lsrpia.Length; i++) | ||
2603 | { | ||
2604 | LandStatReplyPacket.ReportDataBlock lsrepdb = new LandStatReplyPacket.ReportDataBlock(); | ||
2605 | lsrepdb.LocationX = lsrpia[i].LocationX; | ||
2606 | lsrepdb.LocationY = lsrpia[i].LocationY; | ||
2607 | lsrepdb.LocationZ = lsrpia[i].LocationZ; | ||
2608 | lsrepdb.Score = lsrpia[i].Score; | ||
2609 | lsrepdb.TaskID = lsrpia[i].TaskID; | ||
2610 | lsrepdb.TaskLocalID = lsrpia[i].TaskLocalID; | ||
2611 | lsrepdb.TaskName = Util.StringToBytes256(lsrpia[i].TaskName); | ||
2612 | lsrepdb.OwnerName = Util.StringToBytes256(lsrpia[i].OwnerName); | ||
2613 | lsrepdba[i] = lsrepdb; | ||
2614 | } | ||
2615 | lsrp.ReportData = lsrepdba; | ||
2616 | OutPacket(lsrp, ThrottleOutPacketType.Task); | ||
2617 | } | ||
2618 | |||
2619 | public void SendScriptRunningReply(UUID objectID, UUID itemID, bool running) | ||
2620 | { | ||
2621 | ScriptRunningReplyPacket scriptRunningReply = new ScriptRunningReplyPacket(); | ||
2622 | scriptRunningReply.Script.ObjectID = objectID; | ||
2623 | scriptRunningReply.Script.ItemID = itemID; | ||
2624 | scriptRunningReply.Script.Running = running; | ||
2625 | |||
2626 | OutPacket(scriptRunningReply, ThrottleOutPacketType.Task); | ||
2627 | } | ||
2628 | |||
2629 | public void SendAsset(AssetRequestToClient req) | ||
2630 | { | ||
2631 | if (req.AssetInf.Data == null) | ||
2632 | { | ||
2633 | m_log.ErrorFormat("Cannot send asset {0} ({1}), asset data is null", | ||
2634 | req.AssetInf.ID, req.AssetInf.Metadata.ContentType); | ||
2635 | return; | ||
2636 | } | ||
2637 | |||
2638 | //m_log.Debug("sending asset " + req.RequestAssetID); | ||
2639 | TransferInfoPacket Transfer = new TransferInfoPacket(); | ||
2640 | Transfer.TransferInfo.ChannelType = 2; | ||
2641 | Transfer.TransferInfo.Status = 0; | ||
2642 | Transfer.TransferInfo.TargetType = 0; | ||
2643 | if (req.AssetRequestSource == 2) | ||
2644 | { | ||
2645 | Transfer.TransferInfo.Params = new byte[20]; | ||
2646 | Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); | ||
2647 | int assType = req.AssetInf.Type; | ||
2648 | Array.Copy(Utils.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4); | ||
2649 | } | ||
2650 | else if (req.AssetRequestSource == 3) | ||
2651 | { | ||
2652 | Transfer.TransferInfo.Params = req.Params; | ||
2653 | // Transfer.TransferInfo.Params = new byte[100]; | ||
2654 | //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); | ||
2655 | //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16); | ||
2656 | } | ||
2657 | Transfer.TransferInfo.Size = req.AssetInf.Data.Length; | ||
2658 | Transfer.TransferInfo.TransferID = req.TransferRequestID; | ||
2659 | Transfer.Header.Zerocoded = true; | ||
2660 | OutPacket(Transfer, ThrottleOutPacketType.Asset); | ||
2661 | |||
2662 | if (req.NumPackets == 1) | ||
2663 | { | ||
2664 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | ||
2665 | TransferPacket.TransferData.Packet = 0; | ||
2666 | TransferPacket.TransferData.ChannelType = 2; | ||
2667 | TransferPacket.TransferData.TransferID = req.TransferRequestID; | ||
2668 | TransferPacket.TransferData.Data = req.AssetInf.Data; | ||
2669 | TransferPacket.TransferData.Status = 1; | ||
2670 | TransferPacket.Header.Zerocoded = true; | ||
2671 | OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | ||
2672 | } | ||
2673 | else | ||
2674 | { | ||
2675 | int processedLength = 0; | ||
2676 | int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; | ||
2677 | int packetNumber = 0; | ||
2678 | |||
2679 | while (processedLength < req.AssetInf.Data.Length) | ||
2680 | { | ||
2681 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | ||
2682 | TransferPacket.TransferData.Packet = packetNumber; | ||
2683 | TransferPacket.TransferData.ChannelType = 2; | ||
2684 | TransferPacket.TransferData.TransferID = req.TransferRequestID; | ||
2685 | |||
2686 | int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize); | ||
2687 | byte[] chunk = new byte[chunkSize]; | ||
2688 | Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length); | ||
2689 | |||
2690 | TransferPacket.TransferData.Data = chunk; | ||
2691 | |||
2692 | // 0 indicates more packets to come, 1 indicates last packet | ||
2693 | if (req.AssetInf.Data.Length - processedLength > maxChunkSize) | ||
2694 | { | ||
2695 | TransferPacket.TransferData.Status = 0; | ||
2696 | } | ||
2697 | else | ||
2698 | { | ||
2699 | TransferPacket.TransferData.Status = 1; | ||
2700 | } | ||
2701 | TransferPacket.Header.Zerocoded = true; | ||
2702 | OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | ||
2703 | |||
2704 | processedLength += chunkSize; | ||
2705 | packetNumber++; | ||
2706 | } | ||
2707 | } | ||
2708 | } | ||
2709 | |||
2710 | public void SendTexture(AssetBase TextureAsset) | ||
2711 | { | ||
2712 | |||
2713 | } | ||
2714 | |||
2715 | public void SendRegionHandle(UUID regionID, ulong handle) | ||
2716 | { | ||
2717 | RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)PacketPool.Instance.GetPacket(PacketType.RegionIDAndHandleReply); | ||
2718 | reply.ReplyBlock.RegionID = regionID; | ||
2719 | reply.ReplyBlock.RegionHandle = handle; | ||
2720 | OutPacket(reply, ThrottleOutPacketType.Land); | ||
2721 | } | ||
2722 | |||
2723 | public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y) | ||
2724 | { | ||
2725 | float dwell = 0.0f; | ||
2726 | IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>(); | ||
2727 | if (dwellModule != null) | ||
2728 | dwell = dwellModule.GetDwell(land.GlobalID); | ||
2729 | ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply); | ||
2730 | reply.AgentData.AgentID = m_agentId; | ||
2731 | reply.Data.ParcelID = parcelID; | ||
2732 | reply.Data.OwnerID = land.OwnerID; | ||
2733 | reply.Data.Name = Utils.StringToBytes(land.Name); | ||
2734 | reply.Data.Desc = Utils.StringToBytes(land.Description); | ||
2735 | reply.Data.ActualArea = land.Area; | ||
2736 | reply.Data.BillableArea = land.Area; // TODO: what is this? | ||
2737 | |||
2738 | // Bit 0: Mature, bit 7: on sale, other bits: no idea | ||
2739 | reply.Data.Flags = (byte)( | ||
2740 | (info.AccessLevel > 13 ? (1 << 0) : 0) + | ||
2741 | ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0)); | ||
2742 | |||
2743 | Vector3 pos = land.UserLocation; | ||
2744 | if (pos.Equals(Vector3.Zero)) | ||
2745 | { | ||
2746 | pos = (land.AABBMax + land.AABBMin) * 0.5f; | ||
2747 | } | ||
2748 | reply.Data.GlobalX = info.RegionLocX + x; | ||
2749 | reply.Data.GlobalY = info.RegionLocY + y; | ||
2750 | reply.Data.GlobalZ = pos.Z; | ||
2751 | reply.Data.SimName = Utils.StringToBytes(info.RegionName); | ||
2752 | reply.Data.SnapshotID = land.SnapshotID; | ||
2753 | reply.Data.Dwell = dwell; | ||
2754 | reply.Data.SalePrice = land.SalePrice; | ||
2755 | reply.Data.AuctionID = (int)land.AuctionID; | ||
2756 | |||
2757 | OutPacket(reply, ThrottleOutPacketType.Land); | ||
2758 | } | ||
2759 | |||
2760 | public void SendScriptTeleportRequest(string objName, string simName, Vector3 pos, Vector3 lookAt) | ||
2761 | { | ||
2762 | ScriptTeleportRequestPacket packet = (ScriptTeleportRequestPacket)PacketPool.Instance.GetPacket(PacketType.ScriptTeleportRequest); | ||
2763 | |||
2764 | packet.Data.ObjectName = Utils.StringToBytes(objName); | ||
2765 | packet.Data.SimName = Utils.StringToBytes(simName); | ||
2766 | packet.Data.SimPosition = pos; | ||
2767 | packet.Data.LookAt = lookAt; | ||
2768 | |||
2769 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2770 | } | ||
2771 | |||
2772 | public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data) | ||
2773 | { | ||
2774 | DirPlacesReplyPacket packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply); | ||
2775 | |||
2776 | packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock(); | ||
2777 | |||
2778 | packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1]; | ||
2779 | packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock(); | ||
2780 | |||
2781 | packet.AgentData.AgentID = AgentId; | ||
2782 | |||
2783 | packet.QueryData[0].QueryID = queryID; | ||
2784 | |||
2785 | DirPlacesReplyPacket.QueryRepliesBlock[] replies = | ||
2786 | new DirPlacesReplyPacket.QueryRepliesBlock[0]; | ||
2787 | DirPlacesReplyPacket.StatusDataBlock[] status = | ||
2788 | new DirPlacesReplyPacket.StatusDataBlock[0]; | ||
2789 | |||
2790 | packet.QueryReplies = replies; | ||
2791 | packet.StatusData = status; | ||
2792 | |||
2793 | foreach (DirPlacesReplyData d in data) | ||
2794 | { | ||
2795 | int idx = replies.Length; | ||
2796 | Array.Resize(ref replies, idx + 1); | ||
2797 | Array.Resize(ref status, idx + 1); | ||
2798 | |||
2799 | replies[idx] = new DirPlacesReplyPacket.QueryRepliesBlock(); | ||
2800 | status[idx] = new DirPlacesReplyPacket.StatusDataBlock(); | ||
2801 | replies[idx].ParcelID = d.parcelID; | ||
2802 | replies[idx].Name = Utils.StringToBytes(d.name); | ||
2803 | replies[idx].ForSale = d.forSale; | ||
2804 | replies[idx].Auction = d.auction; | ||
2805 | replies[idx].Dwell = d.dwell; | ||
2806 | status[idx].Status = d.Status; | ||
2807 | |||
2808 | packet.QueryReplies = replies; | ||
2809 | packet.StatusData = status; | ||
2810 | |||
2811 | if (packet.Length >= 1000) | ||
2812 | { | ||
2813 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2814 | |||
2815 | packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply); | ||
2816 | |||
2817 | packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock(); | ||
2818 | |||
2819 | packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1]; | ||
2820 | packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock(); | ||
2821 | |||
2822 | packet.AgentData.AgentID = AgentId; | ||
2823 | |||
2824 | packet.QueryData[0].QueryID = queryID; | ||
2825 | |||
2826 | replies = new DirPlacesReplyPacket.QueryRepliesBlock[0]; | ||
2827 | status = new DirPlacesReplyPacket.StatusDataBlock[0]; | ||
2828 | } | ||
2829 | } | ||
2830 | |||
2831 | if (replies.Length > 0 || data.Length == 0) | ||
2832 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2833 | } | ||
2834 | |||
2835 | public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data) | ||
2836 | { | ||
2837 | DirPeopleReplyPacket packet = (DirPeopleReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPeopleReply); | ||
2838 | |||
2839 | packet.AgentData = new DirPeopleReplyPacket.AgentDataBlock(); | ||
2840 | packet.AgentData.AgentID = AgentId; | ||
2841 | |||
2842 | packet.QueryData = new DirPeopleReplyPacket.QueryDataBlock(); | ||
2843 | packet.QueryData.QueryID = queryID; | ||
2844 | |||
2845 | packet.QueryReplies = new DirPeopleReplyPacket.QueryRepliesBlock[ | ||
2846 | data.Length]; | ||
2847 | |||
2848 | int i = 0; | ||
2849 | foreach (DirPeopleReplyData d in data) | ||
2850 | { | ||
2851 | packet.QueryReplies[i] = new DirPeopleReplyPacket.QueryRepliesBlock(); | ||
2852 | packet.QueryReplies[i].AgentID = d.agentID; | ||
2853 | packet.QueryReplies[i].FirstName = | ||
2854 | Utils.StringToBytes(d.firstName); | ||
2855 | packet.QueryReplies[i].LastName = | ||
2856 | Utils.StringToBytes(d.lastName); | ||
2857 | packet.QueryReplies[i].Group = | ||
2858 | Utils.StringToBytes(d.group); | ||
2859 | packet.QueryReplies[i].Online = d.online; | ||
2860 | packet.QueryReplies[i].Reputation = d.reputation; | ||
2861 | i++; | ||
2862 | } | ||
2863 | |||
2864 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2865 | } | ||
2866 | |||
2867 | public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data) | ||
2868 | { | ||
2869 | DirEventsReplyPacket packet = (DirEventsReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirEventsReply); | ||
2870 | |||
2871 | packet.AgentData = new DirEventsReplyPacket.AgentDataBlock(); | ||
2872 | packet.AgentData.AgentID = AgentId; | ||
2873 | |||
2874 | packet.QueryData = new DirEventsReplyPacket.QueryDataBlock(); | ||
2875 | packet.QueryData.QueryID = queryID; | ||
2876 | |||
2877 | packet.QueryReplies = new DirEventsReplyPacket.QueryRepliesBlock[ | ||
2878 | data.Length]; | ||
2879 | |||
2880 | packet.StatusData = new DirEventsReplyPacket.StatusDataBlock[ | ||
2881 | data.Length]; | ||
2882 | |||
2883 | int i = 0; | ||
2884 | foreach (DirEventsReplyData d in data) | ||
2885 | { | ||
2886 | packet.QueryReplies[i] = new DirEventsReplyPacket.QueryRepliesBlock(); | ||
2887 | packet.StatusData[i] = new DirEventsReplyPacket.StatusDataBlock(); | ||
2888 | packet.QueryReplies[i].OwnerID = d.ownerID; | ||
2889 | packet.QueryReplies[i].Name = | ||
2890 | Utils.StringToBytes(d.name); | ||
2891 | packet.QueryReplies[i].EventID = d.eventID; | ||
2892 | packet.QueryReplies[i].Date = | ||
2893 | Utils.StringToBytes(d.date); | ||
2894 | packet.QueryReplies[i].UnixTime = d.unixTime; | ||
2895 | packet.QueryReplies[i].EventFlags = d.eventFlags; | ||
2896 | packet.StatusData[i].Status = d.Status; | ||
2897 | i++; | ||
2898 | } | ||
2899 | |||
2900 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2901 | } | ||
2902 | |||
2903 | public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data) | ||
2904 | { | ||
2905 | DirGroupsReplyPacket packet = (DirGroupsReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirGroupsReply); | ||
2906 | |||
2907 | packet.AgentData = new DirGroupsReplyPacket.AgentDataBlock(); | ||
2908 | packet.AgentData.AgentID = AgentId; | ||
2909 | |||
2910 | packet.QueryData = new DirGroupsReplyPacket.QueryDataBlock(); | ||
2911 | packet.QueryData.QueryID = queryID; | ||
2912 | |||
2913 | packet.QueryReplies = new DirGroupsReplyPacket.QueryRepliesBlock[ | ||
2914 | data.Length]; | ||
2915 | |||
2916 | int i = 0; | ||
2917 | foreach (DirGroupsReplyData d in data) | ||
2918 | { | ||
2919 | packet.QueryReplies[i] = new DirGroupsReplyPacket.QueryRepliesBlock(); | ||
2920 | packet.QueryReplies[i].GroupID = d.groupID; | ||
2921 | packet.QueryReplies[i].GroupName = | ||
2922 | Utils.StringToBytes(d.groupName); | ||
2923 | packet.QueryReplies[i].Members = d.members; | ||
2924 | packet.QueryReplies[i].SearchOrder = d.searchOrder; | ||
2925 | i++; | ||
2926 | } | ||
2927 | |||
2928 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2929 | } | ||
2930 | |||
2931 | public void SendDirClassifiedReply(UUID queryID, DirClassifiedReplyData[] data) | ||
2932 | { | ||
2933 | DirClassifiedReplyPacket packet = (DirClassifiedReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirClassifiedReply); | ||
2934 | |||
2935 | packet.AgentData = new DirClassifiedReplyPacket.AgentDataBlock(); | ||
2936 | packet.AgentData.AgentID = AgentId; | ||
2937 | |||
2938 | packet.QueryData = new DirClassifiedReplyPacket.QueryDataBlock(); | ||
2939 | packet.QueryData.QueryID = queryID; | ||
2940 | |||
2941 | packet.QueryReplies = new DirClassifiedReplyPacket.QueryRepliesBlock[ | ||
2942 | data.Length]; | ||
2943 | packet.StatusData = new DirClassifiedReplyPacket.StatusDataBlock[ | ||
2944 | data.Length]; | ||
2945 | |||
2946 | int i = 0; | ||
2947 | foreach (DirClassifiedReplyData d in data) | ||
2948 | { | ||
2949 | packet.QueryReplies[i] = new DirClassifiedReplyPacket.QueryRepliesBlock(); | ||
2950 | packet.StatusData[i] = new DirClassifiedReplyPacket.StatusDataBlock(); | ||
2951 | packet.QueryReplies[i].ClassifiedID = d.classifiedID; | ||
2952 | packet.QueryReplies[i].Name = | ||
2953 | Utils.StringToBytes(d.name); | ||
2954 | packet.QueryReplies[i].ClassifiedFlags = d.classifiedFlags; | ||
2955 | packet.QueryReplies[i].CreationDate = d.creationDate; | ||
2956 | packet.QueryReplies[i].ExpirationDate = d.expirationDate; | ||
2957 | packet.QueryReplies[i].PriceForListing = d.price; | ||
2958 | packet.StatusData[i].Status = d.Status; | ||
2959 | i++; | ||
2960 | } | ||
2961 | |||
2962 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2963 | } | ||
2964 | |||
2965 | public void SendDirLandReply(UUID queryID, DirLandReplyData[] data) | ||
2966 | { | ||
2967 | DirLandReplyPacket packet = (DirLandReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirLandReply); | ||
2968 | |||
2969 | packet.AgentData = new DirLandReplyPacket.AgentDataBlock(); | ||
2970 | packet.AgentData.AgentID = AgentId; | ||
2971 | |||
2972 | packet.QueryData = new DirLandReplyPacket.QueryDataBlock(); | ||
2973 | packet.QueryData.QueryID = queryID; | ||
2974 | |||
2975 | packet.QueryReplies = new DirLandReplyPacket.QueryRepliesBlock[ | ||
2976 | data.Length]; | ||
2977 | |||
2978 | int i = 0; | ||
2979 | foreach (DirLandReplyData d in data) | ||
2980 | { | ||
2981 | packet.QueryReplies[i] = new DirLandReplyPacket.QueryRepliesBlock(); | ||
2982 | packet.QueryReplies[i].ParcelID = d.parcelID; | ||
2983 | packet.QueryReplies[i].Name = | ||
2984 | Utils.StringToBytes(d.name); | ||
2985 | packet.QueryReplies[i].Auction = d.auction; | ||
2986 | packet.QueryReplies[i].ForSale = d.forSale; | ||
2987 | packet.QueryReplies[i].SalePrice = d.salePrice; | ||
2988 | packet.QueryReplies[i].ActualArea = d.actualArea; | ||
2989 | i++; | ||
2990 | } | ||
2991 | |||
2992 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2993 | } | ||
2994 | |||
2995 | public void SendDirPopularReply(UUID queryID, DirPopularReplyData[] data) | ||
2996 | { | ||
2997 | DirPopularReplyPacket packet = (DirPopularReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPopularReply); | ||
2998 | |||
2999 | packet.AgentData = new DirPopularReplyPacket.AgentDataBlock(); | ||
3000 | packet.AgentData.AgentID = AgentId; | ||
3001 | |||
3002 | packet.QueryData = new DirPopularReplyPacket.QueryDataBlock(); | ||
3003 | packet.QueryData.QueryID = queryID; | ||
3004 | |||
3005 | packet.QueryReplies = new DirPopularReplyPacket.QueryRepliesBlock[ | ||
3006 | data.Length]; | ||
3007 | |||
3008 | int i = 0; | ||
3009 | foreach (DirPopularReplyData d in data) | ||
3010 | { | ||
3011 | packet.QueryReplies[i] = new DirPopularReplyPacket.QueryRepliesBlock(); | ||
3012 | packet.QueryReplies[i].ParcelID = d.parcelID; | ||
3013 | packet.QueryReplies[i].Name = | ||
3014 | Utils.StringToBytes(d.name); | ||
3015 | packet.QueryReplies[i].Dwell = d.dwell; | ||
3016 | i++; | ||
3017 | } | ||
3018 | |||
3019 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
3020 | } | ||
3021 | |||
3022 | public void SendEventInfoReply(EventData data) | ||
3023 | { | ||
3024 | EventInfoReplyPacket packet = (EventInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.EventInfoReply); | ||
3025 | |||
3026 | packet.AgentData = new EventInfoReplyPacket.AgentDataBlock(); | ||
3027 | packet.AgentData.AgentID = AgentId; | ||
3028 | |||
3029 | packet.EventData = new EventInfoReplyPacket.EventDataBlock(); | ||
3030 | packet.EventData.EventID = data.eventID; | ||
3031 | packet.EventData.Creator = Utils.StringToBytes(data.creator); | ||
3032 | packet.EventData.Name = Utils.StringToBytes(data.name); | ||
3033 | packet.EventData.Category = Utils.StringToBytes(data.category); | ||
3034 | packet.EventData.Desc = Utils.StringToBytes(data.description); | ||
3035 | packet.EventData.Date = Utils.StringToBytes(data.date); | ||
3036 | packet.EventData.DateUTC = data.dateUTC; | ||
3037 | packet.EventData.Duration = data.duration; | ||
3038 | packet.EventData.Cover = data.cover; | ||
3039 | packet.EventData.Amount = data.amount; | ||
3040 | packet.EventData.SimName = Utils.StringToBytes(data.simName); | ||
3041 | packet.EventData.GlobalPos = new Vector3d(data.globalPos); | ||
3042 | packet.EventData.EventFlags = data.eventFlags; | ||
3043 | |||
3044 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
3045 | } | ||
3046 | |||
3047 | public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags) | ||
3048 | { | ||
3049 | MapItemReplyPacket mirplk = new MapItemReplyPacket(); | ||
3050 | mirplk.AgentData.AgentID = AgentId; | ||
3051 | mirplk.RequestData.ItemType = mapitemtype; | ||
3052 | mirplk.Data = new MapItemReplyPacket.DataBlock[replies.Length]; | ||
3053 | for (int i = 0; i < replies.Length; i++) | ||
3054 | { | ||
3055 | MapItemReplyPacket.DataBlock mrdata = new MapItemReplyPacket.DataBlock(); | ||
3056 | mrdata.X = replies[i].x; | ||
3057 | mrdata.Y = replies[i].y; | ||
3058 | mrdata.ID = replies[i].id; | ||
3059 | mrdata.Extra = replies[i].Extra; | ||
3060 | mrdata.Extra2 = replies[i].Extra2; | ||
3061 | mrdata.Name = Utils.StringToBytes(replies[i].name); | ||
3062 | mirplk.Data[i] = mrdata; | ||
3063 | } | ||
3064 | //m_log.Debug(mirplk.ToString()); | ||
3065 | OutPacket(mirplk, ThrottleOutPacketType.Task); | ||
3066 | |||
3067 | } | ||
3068 | |||
3069 | public void SendOfferCallingCard(UUID srcID, UUID transactionID) | ||
3070 | { | ||
3071 | // a bit special, as this uses AgentID to store the source instead | ||
3072 | // of the destination. The destination (the receiver) goes into destID | ||
3073 | OfferCallingCardPacket p = (OfferCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.OfferCallingCard); | ||
3074 | p.AgentData.AgentID = srcID; | ||
3075 | p.AgentData.SessionID = UUID.Zero; | ||
3076 | p.AgentBlock.DestID = AgentId; | ||
3077 | p.AgentBlock.TransactionID = transactionID; | ||
3078 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3079 | } | ||
3080 | |||
3081 | public void SendAcceptCallingCard(UUID transactionID) | ||
3082 | { | ||
3083 | AcceptCallingCardPacket p = (AcceptCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.AcceptCallingCard); | ||
3084 | p.AgentData.AgentID = AgentId; | ||
3085 | p.AgentData.SessionID = UUID.Zero; | ||
3086 | p.FolderData = new AcceptCallingCardPacket.FolderDataBlock[1]; | ||
3087 | p.FolderData[0] = new AcceptCallingCardPacket.FolderDataBlock(); | ||
3088 | p.FolderData[0].FolderID = UUID.Zero; | ||
3089 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3090 | } | ||
3091 | |||
3092 | public void SendDeclineCallingCard(UUID transactionID) | ||
3093 | { | ||
3094 | DeclineCallingCardPacket p = (DeclineCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.DeclineCallingCard); | ||
3095 | p.AgentData.AgentID = AgentId; | ||
3096 | p.AgentData.SessionID = UUID.Zero; | ||
3097 | p.TransactionBlock.TransactionID = transactionID; | ||
3098 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3099 | } | ||
3100 | |||
3101 | public void SendTerminateFriend(UUID exFriendID) | ||
3102 | { | ||
3103 | TerminateFriendshipPacket p = (TerminateFriendshipPacket)PacketPool.Instance.GetPacket(PacketType.TerminateFriendship); | ||
3104 | p.AgentData.AgentID = AgentId; | ||
3105 | p.AgentData.SessionID = SessionId; | ||
3106 | p.ExBlock.OtherID = exFriendID; | ||
3107 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3108 | } | ||
3109 | |||
3110 | public void SendAvatarGroupsReply(UUID avatarID, GroupMembershipData[] data) | ||
3111 | { | ||
3112 | OSDMap llsd = new OSDMap(3); | ||
3113 | OSDArray AgentData = new OSDArray(1); | ||
3114 | OSDMap AgentDataMap = new OSDMap(1); | ||
3115 | AgentDataMap.Add("AgentID", OSD.FromUUID(this.AgentId)); | ||
3116 | AgentDataMap.Add("AvatarID", OSD.FromUUID(avatarID)); | ||
3117 | AgentData.Add(AgentDataMap); | ||
3118 | llsd.Add("AgentData", AgentData); | ||
3119 | OSDArray GroupData = new OSDArray(data.Length); | ||
3120 | OSDArray NewGroupData = new OSDArray(data.Length); | ||
3121 | foreach (GroupMembershipData m in data) | ||
3122 | { | ||
3123 | OSDMap GroupDataMap = new OSDMap(6); | ||
3124 | OSDMap NewGroupDataMap = new OSDMap(1); | ||
3125 | GroupDataMap.Add("GroupPowers", OSD.FromULong(m.GroupPowers)); | ||
3126 | GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(m.AcceptNotices)); | ||
3127 | GroupDataMap.Add("GroupTitle", OSD.FromString(m.GroupTitle)); | ||
3128 | GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID)); | ||
3129 | GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName)); | ||
3130 | GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture)); | ||
3131 | NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile)); | ||
3132 | GroupData.Add(GroupDataMap); | ||
3133 | NewGroupData.Add(NewGroupDataMap); | ||
3134 | } | ||
3135 | llsd.Add("GroupData", GroupData); | ||
3136 | llsd.Add("NewGroupData", NewGroupData); | ||
3137 | |||
3138 | IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>(); | ||
3139 | if (eq != null) | ||
3140 | { | ||
3141 | eq.Enqueue(BuildEvent("AvatarGroupsReply", llsd), this.AgentId); | ||
3142 | } | ||
3143 | } | ||
3144 | |||
3145 | public void SendJoinGroupReply(UUID groupID, bool success) | ||
3146 | { | ||
3147 | JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply); | ||
3148 | |||
3149 | p.AgentData = new JoinGroupReplyPacket.AgentDataBlock(); | ||
3150 | p.AgentData.AgentID = AgentId; | ||
3151 | |||
3152 | p.GroupData = new JoinGroupReplyPacket.GroupDataBlock(); | ||
3153 | p.GroupData.GroupID = groupID; | ||
3154 | p.GroupData.Success = success; | ||
3155 | |||
3156 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3157 | } | ||
3158 | |||
3159 | public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success) | ||
3160 | { | ||
3161 | EjectGroupMemberReplyPacket p = (EjectGroupMemberReplyPacket)PacketPool.Instance.GetPacket(PacketType.EjectGroupMemberReply); | ||
3162 | |||
3163 | p.AgentData = new EjectGroupMemberReplyPacket.AgentDataBlock(); | ||
3164 | p.AgentData.AgentID = agentID; | ||
3165 | |||
3166 | p.GroupData = new EjectGroupMemberReplyPacket.GroupDataBlock(); | ||
3167 | p.GroupData.GroupID = groupID; | ||
3168 | |||
3169 | p.EjectData = new EjectGroupMemberReplyPacket.EjectDataBlock(); | ||
3170 | p.EjectData.Success = success; | ||
3171 | |||
3172 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3173 | } | ||
3174 | |||
3175 | public void SendLeaveGroupReply(UUID groupID, bool success) | ||
3176 | { | ||
3177 | LeaveGroupReplyPacket p = (LeaveGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.LeaveGroupReply); | ||
3178 | |||
3179 | p.AgentData = new LeaveGroupReplyPacket.AgentDataBlock(); | ||
3180 | p.AgentData.AgentID = AgentId; | ||
3181 | |||
3182 | p.GroupData = new LeaveGroupReplyPacket.GroupDataBlock(); | ||
3183 | p.GroupData.GroupID = groupID; | ||
3184 | p.GroupData.Success = success; | ||
3185 | |||
3186 | OutPacket(p, ThrottleOutPacketType.Task); | ||
3187 | } | ||
3188 | |||
3189 | public void SendAvatarClassifiedReply(UUID targetID, UUID[] classifiedID, string[] name) | ||
3190 | { | ||
3191 | if (classifiedID.Length != name.Length) | ||
3192 | return; | ||
3193 | |||
3194 | AvatarClassifiedReplyPacket ac = | ||
3195 | (AvatarClassifiedReplyPacket)PacketPool.Instance.GetPacket( | ||
3196 | PacketType.AvatarClassifiedReply); | ||
3197 | |||
3198 | ac.AgentData = new AvatarClassifiedReplyPacket.AgentDataBlock(); | ||
3199 | ac.AgentData.AgentID = AgentId; | ||
3200 | ac.AgentData.TargetID = targetID; | ||
3201 | |||
3202 | ac.Data = new AvatarClassifiedReplyPacket.DataBlock[classifiedID.Length]; | ||
3203 | int i; | ||
3204 | for (i = 0; i < classifiedID.Length; i++) | ||
3205 | { | ||
3206 | ac.Data[i].ClassifiedID = classifiedID[i]; | ||
3207 | ac.Data[i].Name = Utils.StringToBytes(name[i]); | ||
3208 | } | ||
3209 | |||
3210 | OutPacket(ac, ThrottleOutPacketType.Task); | ||
3211 | } | ||
3212 | |||
3213 | public void SendClassifiedInfoReply(UUID classifiedID, UUID creatorID, uint creationDate, uint expirationDate, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, string simName, Vector3 globalPos, string parcelName, byte classifiedFlags, int price) | ||
3214 | { | ||
3215 | ClassifiedInfoReplyPacket cr = | ||
3216 | (ClassifiedInfoReplyPacket)PacketPool.Instance.GetPacket( | ||
3217 | PacketType.ClassifiedInfoReply); | ||
3218 | |||
3219 | cr.AgentData = new ClassifiedInfoReplyPacket.AgentDataBlock(); | ||
3220 | cr.AgentData.AgentID = AgentId; | ||
3221 | |||
3222 | cr.Data = new ClassifiedInfoReplyPacket.DataBlock(); | ||
3223 | cr.Data.ClassifiedID = classifiedID; | ||
3224 | cr.Data.CreatorID = creatorID; | ||
3225 | cr.Data.CreationDate = creationDate; | ||
3226 | cr.Data.ExpirationDate = expirationDate; | ||
3227 | cr.Data.Category = category; | ||
3228 | cr.Data.Name = Utils.StringToBytes(name); | ||
3229 | cr.Data.Desc = Utils.StringToBytes(description); | ||
3230 | cr.Data.ParcelID = parcelID; | ||
3231 | cr.Data.ParentEstate = parentEstate; | ||
3232 | cr.Data.SnapshotID = snapshotID; | ||
3233 | cr.Data.SimName = Utils.StringToBytes(simName); | ||
3234 | cr.Data.PosGlobal = new Vector3d(globalPos); | ||
3235 | cr.Data.ParcelName = Utils.StringToBytes(parcelName); | ||
3236 | cr.Data.ClassifiedFlags = classifiedFlags; | ||
3237 | cr.Data.PriceForListing = price; | ||
3238 | |||
3239 | OutPacket(cr, ThrottleOutPacketType.Task); | ||
3240 | } | ||
3241 | |||
3242 | public void SendAgentDropGroup(UUID groupID) | ||
3243 | { | ||
3244 | AgentDropGroupPacket dg = | ||
3245 | (AgentDropGroupPacket)PacketPool.Instance.GetPacket( | ||
3246 | PacketType.AgentDropGroup); | ||
3247 | |||
3248 | dg.AgentData = new AgentDropGroupPacket.AgentDataBlock(); | ||
3249 | dg.AgentData.AgentID = AgentId; | ||
3250 | dg.AgentData.GroupID = groupID; | ||
3251 | |||
3252 | OutPacket(dg, ThrottleOutPacketType.Task); | ||
3253 | } | ||
3254 | |||
3255 | public void SendAvatarNotesReply(UUID targetID, string text) | ||
3256 | { | ||
3257 | AvatarNotesReplyPacket an = | ||
3258 | (AvatarNotesReplyPacket)PacketPool.Instance.GetPacket( | ||
3259 | PacketType.AvatarNotesReply); | ||
3260 | |||
3261 | an.AgentData = new AvatarNotesReplyPacket.AgentDataBlock(); | ||
3262 | an.AgentData.AgentID = AgentId; | ||
3263 | |||
3264 | an.Data = new AvatarNotesReplyPacket.DataBlock(); | ||
3265 | an.Data.TargetID = targetID; | ||
3266 | an.Data.Notes = Utils.StringToBytes(text); | ||
3267 | |||
3268 | OutPacket(an, ThrottleOutPacketType.Task); | ||
3269 | } | ||
3270 | |||
3271 | public void SendAvatarPicksReply(UUID targetID, Dictionary<UUID, string> picks) | ||
3272 | { | ||
3273 | AvatarPicksReplyPacket ap = | ||
3274 | (AvatarPicksReplyPacket)PacketPool.Instance.GetPacket( | ||
3275 | PacketType.AvatarPicksReply); | ||
3276 | |||
3277 | ap.AgentData = new AvatarPicksReplyPacket.AgentDataBlock(); | ||
3278 | ap.AgentData.AgentID = AgentId; | ||
3279 | ap.AgentData.TargetID = targetID; | ||
3280 | |||
3281 | ap.Data = new AvatarPicksReplyPacket.DataBlock[picks.Count]; | ||
3282 | |||
3283 | int i = 0; | ||
3284 | foreach (KeyValuePair<UUID, string> pick in picks) | ||
3285 | { | ||
3286 | ap.Data[i] = new AvatarPicksReplyPacket.DataBlock(); | ||
3287 | ap.Data[i].PickID = pick.Key; | ||
3288 | ap.Data[i].PickName = Utils.StringToBytes(pick.Value); | ||
3289 | i++; | ||
3290 | } | ||
3291 | |||
3292 | OutPacket(ap, ThrottleOutPacketType.Task); | ||
3293 | } | ||
3294 | |||
3295 | public void SendAvatarClassifiedReply(UUID targetID, Dictionary<UUID, string> classifieds) | ||
3296 | { | ||
3297 | AvatarClassifiedReplyPacket ac = | ||
3298 | (AvatarClassifiedReplyPacket)PacketPool.Instance.GetPacket( | ||
3299 | PacketType.AvatarClassifiedReply); | ||
3300 | |||
3301 | ac.AgentData = new AvatarClassifiedReplyPacket.AgentDataBlock(); | ||
3302 | ac.AgentData.AgentID = AgentId; | ||
3303 | ac.AgentData.TargetID = targetID; | ||
3304 | |||
3305 | ac.Data = new AvatarClassifiedReplyPacket.DataBlock[classifieds.Count]; | ||
3306 | |||
3307 | int i = 0; | ||
3308 | foreach (KeyValuePair<UUID, string> classified in classifieds) | ||
3309 | { | ||
3310 | ac.Data[i] = new AvatarClassifiedReplyPacket.DataBlock(); | ||
3311 | ac.Data[i].ClassifiedID = classified.Key; | ||
3312 | ac.Data[i].Name = Utils.StringToBytes(classified.Value); | ||
3313 | i++; | ||
3314 | } | ||
3315 | |||
3316 | OutPacket(ac, ThrottleOutPacketType.Task); | ||
3317 | } | ||
3318 | |||
3319 | public void SendParcelDwellReply(int localID, UUID parcelID, float dwell) | ||
3320 | { | ||
3321 | ParcelDwellReplyPacket pd = | ||
3322 | (ParcelDwellReplyPacket)PacketPool.Instance.GetPacket( | ||
3323 | PacketType.ParcelDwellReply); | ||
3324 | |||
3325 | pd.AgentData = new ParcelDwellReplyPacket.AgentDataBlock(); | ||
3326 | pd.AgentData.AgentID = AgentId; | ||
3327 | |||
3328 | pd.Data = new ParcelDwellReplyPacket.DataBlock(); | ||
3329 | pd.Data.LocalID = localID; | ||
3330 | pd.Data.ParcelID = parcelID; | ||
3331 | pd.Data.Dwell = dwell; | ||
3332 | |||
3333 | OutPacket(pd, ThrottleOutPacketType.Land); | ||
3334 | } | ||
3335 | |||
3336 | public void SendUserInfoReply(bool imViaEmail, bool visible, string email) | ||
3337 | { | ||
3338 | UserInfoReplyPacket ur = | ||
3339 | (UserInfoReplyPacket)PacketPool.Instance.GetPacket( | ||
3340 | PacketType.UserInfoReply); | ||
3341 | |||
3342 | string Visible = "hidden"; | ||
3343 | if (visible) | ||
3344 | Visible = "default"; | ||
3345 | |||
3346 | ur.AgentData = new UserInfoReplyPacket.AgentDataBlock(); | ||
3347 | ur.AgentData.AgentID = AgentId; | ||
3348 | |||
3349 | ur.UserData = new UserInfoReplyPacket.UserDataBlock(); | ||
3350 | ur.UserData.IMViaEMail = imViaEmail; | ||
3351 | ur.UserData.DirectoryVisibility = Utils.StringToBytes(Visible); | ||
3352 | ur.UserData.EMail = Utils.StringToBytes(email); | ||
3353 | |||
3354 | OutPacket(ur, ThrottleOutPacketType.Task); | ||
3355 | } | ||
3356 | |||
3357 | public void SendCreateGroupReply(UUID groupID, bool success, string message) | ||
3358 | { | ||
3359 | CreateGroupReplyPacket createGroupReply = (CreateGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.CreateGroupReply); | ||
3360 | |||
3361 | createGroupReply.AgentData = | ||
3362 | new CreateGroupReplyPacket.AgentDataBlock(); | ||
3363 | createGroupReply.ReplyData = | ||
3364 | new CreateGroupReplyPacket.ReplyDataBlock(); | ||
3365 | |||
3366 | createGroupReply.AgentData.AgentID = AgentId; | ||
3367 | createGroupReply.ReplyData.GroupID = groupID; | ||
3368 | |||
3369 | createGroupReply.ReplyData.Success = success; | ||
3370 | createGroupReply.ReplyData.Message = Utils.StringToBytes(message); | ||
3371 | OutPacket(createGroupReply, ThrottleOutPacketType.Task); | ||
3372 | } | ||
3373 | |||
3374 | public void SendUseCachedMuteList() | ||
3375 | { | ||
3376 | UseCachedMuteListPacket useCachedMuteList = (UseCachedMuteListPacket)PacketPool.Instance.GetPacket(PacketType.UseCachedMuteList); | ||
3377 | |||
3378 | useCachedMuteList.AgentData = new UseCachedMuteListPacket.AgentDataBlock(); | ||
3379 | useCachedMuteList.AgentData.AgentID = AgentId; | ||
3380 | |||
3381 | OutPacket(useCachedMuteList, ThrottleOutPacketType.Task); | ||
3382 | } | ||
3383 | |||
3384 | public void SendMuteListUpdate(string filename) | ||
3385 | { | ||
3386 | MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate); | ||
3387 | |||
3388 | muteListUpdate.MuteData = new MuteListUpdatePacket.MuteDataBlock(); | ||
3389 | muteListUpdate.MuteData.AgentID = AgentId; | ||
3390 | muteListUpdate.MuteData.Filename = Utils.StringToBytes(filename); | ||
3391 | |||
3392 | OutPacket(muteListUpdate, ThrottleOutPacketType.Task); | ||
3393 | } | ||
3394 | |||
3395 | public void SendPickInfoReply(UUID pickID, UUID creatorID, bool topPick, UUID parcelID, string name, string desc, UUID snapshotID, string user, string originalName, string simName, Vector3 posGlobal, int sortOrder, bool enabled) | ||
3396 | { | ||
3397 | PickInfoReplyPacket pickInfoReply = (PickInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.PickInfoReply); | ||
3398 | |||
3399 | pickInfoReply.AgentData = new PickInfoReplyPacket.AgentDataBlock(); | ||
3400 | pickInfoReply.AgentData.AgentID = AgentId; | ||
3401 | |||
3402 | pickInfoReply.Data = new PickInfoReplyPacket.DataBlock(); | ||
3403 | pickInfoReply.Data.PickID = pickID; | ||
3404 | pickInfoReply.Data.CreatorID = creatorID; | ||
3405 | pickInfoReply.Data.TopPick = topPick; | ||
3406 | pickInfoReply.Data.ParcelID = parcelID; | ||
3407 | pickInfoReply.Data.Name = Utils.StringToBytes(name); | ||
3408 | pickInfoReply.Data.Desc = Utils.StringToBytes(desc); | ||
3409 | pickInfoReply.Data.SnapshotID = snapshotID; | ||
3410 | pickInfoReply.Data.User = Utils.StringToBytes(user); | ||
3411 | pickInfoReply.Data.OriginalName = Utils.StringToBytes(originalName); | ||
3412 | pickInfoReply.Data.SimName = Utils.StringToBytes(simName); | ||
3413 | pickInfoReply.Data.PosGlobal = new Vector3d(posGlobal); | ||
3414 | pickInfoReply.Data.SortOrder = sortOrder; | ||
3415 | pickInfoReply.Data.Enabled = enabled; | ||
3416 | |||
3417 | OutPacket(pickInfoReply, ThrottleOutPacketType.Task); | ||
3418 | } | ||
3419 | |||
3420 | #endregion Scene/Avatar to Client | ||
3421 | |||
3422 | // Gesture | ||
3423 | |||
3424 | #region Appearance/ Wearables Methods | ||
3425 | |||
3426 | public void SendWearables(AvatarWearable[] wearables, int serial) | ||
3427 | { | ||
3428 | AgentWearablesUpdatePacket aw = (AgentWearablesUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentWearablesUpdate); | ||
3429 | aw.AgentData.AgentID = AgentId; | ||
3430 | aw.AgentData.SerialNum = (uint)serial; | ||
3431 | aw.AgentData.SessionID = m_sessionId; | ||
3432 | |||
3433 | int count = 0; | ||
3434 | for (int i = 0; i < wearables.Length; i++) | ||
3435 | count += wearables[i].Count; | ||
3436 | |||
3437 | // TODO: don't create new blocks if recycling an old packet | ||
3438 | aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; | ||
3439 | AgentWearablesUpdatePacket.WearableDataBlock awb; | ||
3440 | int idx = 0; | ||
3441 | for (int i = 0; i < wearables.Length; i++) | ||
3442 | { | ||
3443 | for (int j = 0; j < wearables[i].Count; j++) | ||
3444 | { | ||
3445 | awb = new AgentWearablesUpdatePacket.WearableDataBlock(); | ||
3446 | awb.WearableType = (byte)i; | ||
3447 | awb.AssetID = wearables[i][j].AssetID; | ||
3448 | awb.ItemID = wearables[i][j].ItemID; | ||
3449 | aw.WearableData[idx] = awb; | ||
3450 | idx++; | ||
3451 | |||
3452 | // m_log.DebugFormat( | ||
3453 | // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", | ||
3454 | // awb.ItemID, awb.AssetID, i, Name); | ||
3455 | } | ||
3456 | } | ||
3457 | |||
3458 | OutPacket(aw, ThrottleOutPacketType.Task); | ||
3459 | } | ||
3460 | |||
3461 | public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) | ||
3462 | { | ||
3463 | AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); | ||
3464 | // TODO: don't create new blocks if recycling an old packet | ||
3465 | avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; | ||
3466 | avp.ObjectData.TextureEntry = textureEntry; | ||
3467 | |||
3468 | AvatarAppearancePacket.VisualParamBlock avblock = null; | ||
3469 | for (int i = 0; i < visualParams.Length; i++) | ||
3470 | { | ||
3471 | avblock = new AvatarAppearancePacket.VisualParamBlock(); | ||
3472 | avblock.ParamValue = visualParams[i]; | ||
3473 | avp.VisualParam[i] = avblock; | ||
3474 | } | ||
3475 | |||
3476 | avp.Sender.IsTrial = false; | ||
3477 | avp.Sender.ID = agentID; | ||
3478 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | ||
3479 | OutPacket(avp, ThrottleOutPacketType.Task); | ||
3480 | } | ||
3481 | |||
3482 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | ||
3483 | { | ||
3484 | //m_log.DebugFormat("[CLIENT]: Sending animations to {0}", Name); | ||
3485 | |||
3486 | AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation); | ||
3487 | // TODO: don't create new blocks if recycling an old packet | ||
3488 | ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[animations.Length]; | ||
3489 | ani.Sender = new AvatarAnimationPacket.SenderBlock(); | ||
3490 | ani.Sender.ID = sourceAgentId; | ||
3491 | ani.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length]; | ||
3492 | ani.PhysicalAvatarEventList = new AvatarAnimationPacket.PhysicalAvatarEventListBlock[0]; | ||
3493 | |||
3494 | for (int i = 0; i < animations.Length; ++i) | ||
3495 | { | ||
3496 | ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); | ||
3497 | ani.AnimationList[i].AnimID = animations[i]; | ||
3498 | ani.AnimationList[i].AnimSequenceID = seqs[i]; | ||
3499 | |||
3500 | ani.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock(); | ||
3501 | if (objectIDs[i].Equals(sourceAgentId)) | ||
3502 | ani.AnimationSourceList[i].ObjectID = UUID.Zero; | ||
3503 | else | ||
3504 | ani.AnimationSourceList[i].ObjectID = objectIDs[i]; | ||
3505 | } | ||
3506 | ani.Header.Reliable = false; | ||
3507 | OutPacket(ani, ThrottleOutPacketType.Task); | ||
3508 | } | ||
3509 | |||
3510 | #endregion | ||
3511 | |||
3512 | #region Avatar Packet/Data Sending Methods | ||
3513 | |||
3514 | /// <summary> | ||
3515 | /// Send an ObjectUpdate packet with information about an avatar | ||
3516 | /// </summary> | ||
3517 | public void SendAvatarDataImmediate(ISceneEntity avatar) | ||
3518 | { | ||
3519 | ScenePresence presence = avatar as ScenePresence; | ||
3520 | if (presence == null) | ||
3521 | return; | ||
3522 | |||
3523 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
3524 | objupdate.Header.Zerocoded = true; | ||
3525 | |||
3526 | objupdate.RegionData.RegionHandle = presence.RegionHandle; | ||
3527 | objupdate.RegionData.TimeDilation = ushort.MaxValue; | ||
3528 | |||
3529 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
3530 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); | ||
3531 | |||
3532 | OutPacket(objupdate, ThrottleOutPacketType.Task); | ||
3533 | |||
3534 | // We need to record the avatar local id since the root prim of an attachment points to this. | ||
3535 | // m_attachmentsSent.Add(avatar.LocalId); | ||
3536 | } | ||
3537 | |||
3538 | public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) | ||
3539 | { | ||
3540 | if (!IsActive) return; // We don't need to update inactive clients. | ||
3541 | |||
3542 | CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate); | ||
3543 | loc.Header.Reliable = false; | ||
3544 | |||
3545 | // Each packet can only hold around 60 avatar positions and the client clears the mini-map each time | ||
3546 | // a CoarseLocationUpdate packet is received. Oh well. | ||
3547 | int total = Math.Min(CoarseLocations.Count, 60); | ||
3548 | |||
3549 | CoarseLocationUpdatePacket.IndexBlock ib = new CoarseLocationUpdatePacket.IndexBlock(); | ||
3550 | |||
3551 | loc.Location = new CoarseLocationUpdatePacket.LocationBlock[total]; | ||
3552 | loc.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[total]; | ||
3553 | |||
3554 | int selfindex = -1; | ||
3555 | for (int i = 0; i < total; i++) | ||
3556 | { | ||
3557 | CoarseLocationUpdatePacket.LocationBlock lb = | ||
3558 | new CoarseLocationUpdatePacket.LocationBlock(); | ||
3559 | |||
3560 | lb.X = (byte)CoarseLocations[i].X; | ||
3561 | lb.Y = (byte)CoarseLocations[i].Y; | ||
3562 | |||
3563 | lb.Z = CoarseLocations[i].Z > 1024 ? (byte)0 : (byte)(CoarseLocations[i].Z * 0.25f); | ||
3564 | loc.Location[i] = lb; | ||
3565 | loc.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock(); | ||
3566 | loc.AgentData[i].AgentID = users[i]; | ||
3567 | if (users[i] == AgentId) | ||
3568 | selfindex = i; | ||
3569 | } | ||
3570 | |||
3571 | ib.You = (short)selfindex; | ||
3572 | ib.Prey = -1; | ||
3573 | loc.Index = ib; | ||
3574 | |||
3575 | OutPacket(loc, ThrottleOutPacketType.Task); | ||
3576 | } | ||
3577 | |||
3578 | #endregion Avatar Packet/Data Sending Methods | ||
3579 | |||
3580 | #region Primitive Packet/Data Sending Methods | ||
3581 | |||
3582 | |||
3583 | /// <summary> | ||
3584 | /// Generate one of the object update packets based on PrimUpdateFlags | ||
3585 | /// and broadcast the packet to clients | ||
3586 | /// </summary> | ||
3587 | public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) | ||
3588 | { | ||
3589 | if (entity is SceneObjectPart) | ||
3590 | { | ||
3591 | SceneObjectPart e = (SceneObjectPart)entity; | ||
3592 | SceneObjectGroup g = e.ParentGroup; | ||
3593 | if (g.RootPart.Shape.State > 30) // HUD | ||
3594 | if (g.OwnerID != AgentId) | ||
3595 | return; // Don't send updates for other people's HUDs | ||
3596 | } | ||
3597 | |||
3598 | uint priority = m_prioritizer.GetUpdatePriority(this, entity); | ||
3599 | |||
3600 | lock (m_entityUpdates.SyncRoot) | ||
3601 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | ||
3602 | } | ||
3603 | |||
3604 | /// <summary> | ||
3605 | /// Requeue an EntityUpdate when it was not acknowledged by the client. | ||
3606 | /// We will update the priority and put it in the correct queue, merging update flags | ||
3607 | /// with any other updates that may be queued for the same entity. | ||
3608 | /// The original update time is used for the merged update. | ||
3609 | /// </summary> | ||
3610 | private void ResendPrimUpdate(EntityUpdate update) | ||
3611 | { | ||
3612 | // If the update exists in priority queue, it will be updated. | ||
3613 | // If it does not exist then it will be added with the current (rather than its original) priority | ||
3614 | uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); | ||
3615 | |||
3616 | lock (m_entityUpdates.SyncRoot) | ||
3617 | m_entityUpdates.Enqueue(priority, update); | ||
3618 | } | ||
3619 | |||
3620 | /// <summary> | ||
3621 | /// Requeue a list of EntityUpdates when they were not acknowledged by the client. | ||
3622 | /// We will update the priority and put it in the correct queue, merging update flags | ||
3623 | /// with any other updates that may be queued for the same entity. | ||
3624 | /// The original update time is used for the merged update. | ||
3625 | /// </summary> | ||
3626 | private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) | ||
3627 | { | ||
3628 | // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime); | ||
3629 | |||
3630 | // Remove the update packet from the list of packets waiting for acknowledgement | ||
3631 | // because we are requeuing the list of updates. They will be resent in new packets | ||
3632 | // with the most recent state and priority. | ||
3633 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); | ||
3634 | |||
3635 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | ||
3636 | Interlocked.Increment(ref m_udpClient.PacketsResent); | ||
3637 | |||
3638 | foreach (EntityUpdate update in updates) | ||
3639 | ResendPrimUpdate(update); | ||
3640 | } | ||
3641 | |||
3642 | private void ProcessEntityUpdates(int maxUpdates) | ||
3643 | { | ||
3644 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | ||
3645 | OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); | ||
3646 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3647 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3648 | |||
3649 | OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3650 | OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3651 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3652 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3653 | |||
3654 | // Check to see if this is a flush | ||
3655 | if (maxUpdates <= 0) | ||
3656 | { | ||
3657 | maxUpdates = Int32.MaxValue; | ||
3658 | } | ||
3659 | |||
3660 | int updatesThisCall = 0; | ||
3661 | |||
3662 | // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race | ||
3663 | // condition where a kill can be processed before an out-of-date update for the same object. | ||
3664 | float avgTimeDilation = 1.0f; | ||
3665 | IEntityUpdate iupdate; | ||
3666 | Int32 timeinqueue; // this is just debugging code & can be dropped later | ||
3667 | |||
3668 | while (updatesThisCall < maxUpdates) | ||
3669 | { | ||
3670 | lock (m_entityUpdates.SyncRoot) | ||
3671 | if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) | ||
3672 | break; | ||
3673 | |||
3674 | EntityUpdate update = (EntityUpdate)iupdate; | ||
3675 | |||
3676 | avgTimeDilation += update.TimeDilation; | ||
3677 | avgTimeDilation *= 0.5f; | ||
3678 | |||
3679 | if (update.Entity is SceneObjectPart) | ||
3680 | { | ||
3681 | SceneObjectPart part = (SceneObjectPart)update.Entity; | ||
3682 | |||
3683 | // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client | ||
3684 | // will never receive an update after a prim kill. Even then, keeping the kill record may be a good | ||
3685 | // safety measure. | ||
3686 | // | ||
3687 | // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update | ||
3688 | // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs | ||
3689 | // updates and kills on different threads with different scheduling strategies, hence this protection. | ||
3690 | // | ||
3691 | // This doesn't appear to apply to child prims - a client will happily ignore these updates | ||
3692 | // after the root prim has been deleted. | ||
3693 | lock (m_killRecord) | ||
3694 | { | ||
3695 | if (m_killRecord.Contains(part.LocalId)) | ||
3696 | continue; | ||
3697 | if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId)) | ||
3698 | continue; | ||
3699 | } | ||
3700 | |||
3701 | if (part.ParentGroup.IsDeleted) | ||
3702 | continue; | ||
3703 | |||
3704 | if (part.ParentGroup.IsAttachment) | ||
3705 | { // Someone else's HUD, why are we getting these? | ||
3706 | if (part.ParentGroup.OwnerID != AgentId && | ||
3707 | part.ParentGroup.RootPart.Shape.State >= 30) | ||
3708 | continue; | ||
3709 | ScenePresence sp; | ||
3710 | // Owner is not in the sim, don't update it to | ||
3711 | // anyone | ||
3712 | if (!m_scene.TryGetScenePresence(part.OwnerID, out sp)) | ||
3713 | continue; | ||
3714 | |||
3715 | List<SceneObjectGroup> atts = sp.Attachments; | ||
3716 | bool found = false; | ||
3717 | foreach (SceneObjectGroup att in atts) | ||
3718 | { | ||
3719 | if (att == part.ParentGroup) | ||
3720 | { | ||
3721 | found = true; | ||
3722 | break; | ||
3723 | } | ||
3724 | } | ||
3725 | |||
3726 | // It's an attachment of a valid avatar, but | ||
3727 | // doesn't seem to be attached, skip | ||
3728 | if (!found) | ||
3729 | continue; | ||
3730 | } | ||
3731 | if (part.ParentGroup.IsAttachment && m_disableFacelights) | ||
3732 | { | ||
3733 | if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && | ||
3734 | part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) | ||
3735 | { | ||
3736 | part.Shape.LightEntry = false; | ||
3737 | } | ||
3738 | } | ||
3739 | } | ||
3740 | |||
3741 | ++updatesThisCall; | ||
3742 | |||
3743 | #region UpdateFlags to packet type conversion | ||
3744 | |||
3745 | PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; | ||
3746 | |||
3747 | bool canUseCompressed = true; | ||
3748 | bool canUseImproved = true; | ||
3749 | |||
3750 | // Compressed object updates only make sense for LL primitives | ||
3751 | if (!(update.Entity is SceneObjectPart)) | ||
3752 | { | ||
3753 | canUseCompressed = false; | ||
3754 | } | ||
3755 | |||
3756 | if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) | ||
3757 | { | ||
3758 | canUseCompressed = false; | ||
3759 | canUseImproved = false; | ||
3760 | } | ||
3761 | else | ||
3762 | { | ||
3763 | if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || | ||
3764 | updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || | ||
3765 | updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || | ||
3766 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
3767 | { | ||
3768 | canUseCompressed = false; | ||
3769 | } | ||
3770 | |||
3771 | if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || | ||
3772 | updateFlags.HasFlag(PrimUpdateFlags.ParentID) || | ||
3773 | updateFlags.HasFlag(PrimUpdateFlags.Scale) || | ||
3774 | updateFlags.HasFlag(PrimUpdateFlags.PrimData) || | ||
3775 | updateFlags.HasFlag(PrimUpdateFlags.Text) || | ||
3776 | updateFlags.HasFlag(PrimUpdateFlags.NameValue) || | ||
3777 | updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || | ||
3778 | updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || | ||
3779 | updateFlags.HasFlag(PrimUpdateFlags.Sound) || | ||
3780 | updateFlags.HasFlag(PrimUpdateFlags.Particles) || | ||
3781 | updateFlags.HasFlag(PrimUpdateFlags.Material) || | ||
3782 | updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || | ||
3783 | updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || | ||
3784 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
3785 | { | ||
3786 | canUseImproved = false; | ||
3787 | } | ||
3788 | } | ||
3789 | |||
3790 | #endregion UpdateFlags to packet type conversion | ||
3791 | |||
3792 | #region Block Construction | ||
3793 | |||
3794 | // TODO: Remove this once we can build compressed updates | ||
3795 | canUseCompressed = false; | ||
3796 | |||
3797 | if (!canUseImproved && !canUseCompressed) | ||
3798 | { | ||
3799 | if (update.Entity is ScenePresence) | ||
3800 | { | ||
3801 | objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); | ||
3802 | } | ||
3803 | else | ||
3804 | { | ||
3805 | objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); | ||
3806 | } | ||
3807 | } | ||
3808 | else if (!canUseImproved) | ||
3809 | { | ||
3810 | compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); | ||
3811 | } | ||
3812 | else | ||
3813 | { | ||
3814 | if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) | ||
3815 | // Self updates go into a special list | ||
3816 | terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | ||
3817 | else | ||
3818 | // Everything else goes here | ||
3819 | terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | ||
3820 | } | ||
3821 | |||
3822 | #endregion Block Construction | ||
3823 | } | ||
3824 | |||
3825 | #region Packet Sending | ||
3826 | |||
3827 | const float TIME_DILATION = 1.0f; | ||
3828 | ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); | ||
3829 | |||
3830 | if (terseAgentUpdateBlocks.IsValueCreated) | ||
3831 | { | ||
3832 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; | ||
3833 | |||
3834 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); | ||
3835 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3836 | packet.RegionData.TimeDilation = timeDilation; | ||
3837 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3838 | |||
3839 | for (int i = 0; i < blocks.Count; i++) | ||
3840 | packet.ObjectData[i] = blocks[i]; | ||
3841 | |||
3842 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); | ||
3843 | } | ||
3844 | |||
3845 | if (objectUpdateBlocks.IsValueCreated) | ||
3846 | { | ||
3847 | List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; | ||
3848 | |||
3849 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
3850 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3851 | packet.RegionData.TimeDilation = timeDilation; | ||
3852 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3853 | |||
3854 | for (int i = 0; i < blocks.Count; i++) | ||
3855 | packet.ObjectData[i] = blocks[i]; | ||
3856 | |||
3857 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
3858 | } | ||
3859 | |||
3860 | if (compressedUpdateBlocks.IsValueCreated) | ||
3861 | { | ||
3862 | List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; | ||
3863 | |||
3864 | ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); | ||
3865 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3866 | packet.RegionData.TimeDilation = timeDilation; | ||
3867 | packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; | ||
3868 | |||
3869 | for (int i = 0; i < blocks.Count; i++) | ||
3870 | packet.ObjectData[i] = blocks[i]; | ||
3871 | |||
3872 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
3873 | } | ||
3874 | |||
3875 | if (terseUpdateBlocks.IsValueCreated) | ||
3876 | { | ||
3877 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; | ||
3878 | |||
3879 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); | ||
3880 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3881 | packet.RegionData.TimeDilation = timeDilation; | ||
3882 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3883 | |||
3884 | for (int i = 0; i < blocks.Count; i++) | ||
3885 | packet.ObjectData[i] = blocks[i]; | ||
3886 | |||
3887 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
3888 | } | ||
3889 | |||
3890 | #endregion Packet Sending | ||
3891 | } | ||
3892 | |||
3893 | public void ReprioritizeUpdates() | ||
3894 | { | ||
3895 | lock (m_entityUpdates.SyncRoot) | ||
3896 | m_entityUpdates.Reprioritize(UpdatePriorityHandler); | ||
3897 | } | ||
3898 | |||
3899 | private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) | ||
3900 | { | ||
3901 | if (entity != null) | ||
3902 | { | ||
3903 | priority = m_prioritizer.GetUpdatePriority(this, entity); | ||
3904 | return true; | ||
3905 | } | ||
3906 | |||
3907 | return false; | ||
3908 | } | ||
3909 | |||
3910 | public void FlushPrimUpdates() | ||
3911 | { | ||
3912 | m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); | ||
3913 | |||
3914 | while (m_entityUpdates.Count > 0) | ||
3915 | ProcessEntityUpdates(-1); | ||
3916 | } | ||
3917 | |||
3918 | #endregion Primitive Packet/Data Sending Methods | ||
3919 | |||
3920 | // These are used to implement an adaptive backoff in the number | ||
3921 | // of updates converted to packets. Since we don't want packets | ||
3922 | // to sit in the queue with old data, only convert enough updates | ||
3923 | // to packets that can be sent in 200ms. | ||
3924 | private Int32 m_LastQueueFill = 0; | ||
3925 | private Int32 m_maxUpdates = 0; | ||
3926 | |||
3927 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | ||
3928 | { | ||
3929 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | ||
3930 | { | ||
3931 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | ||
3932 | { | ||
3933 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | ||
3934 | } | ||
3935 | else | ||
3936 | { | ||
3937 | if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) | ||
3938 | m_maxUpdates += 5; | ||
3939 | else | ||
3940 | m_maxUpdates = m_maxUpdates >> 1; | ||
3941 | } | ||
3942 | m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500); | ||
3943 | m_LastQueueFill = Util.EnvironmentTickCount(); | ||
3944 | |||
3945 | if (m_entityUpdates.Count > 0) | ||
3946 | ProcessEntityUpdates(m_maxUpdates); | ||
3947 | |||
3948 | if (m_entityProps.Count > 0) | ||
3949 | ProcessEntityPropertyRequests(m_maxUpdates); | ||
3950 | } | ||
3951 | |||
3952 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | ||
3953 | { | ||
3954 | ProcessTextureRequests(); | ||
3955 | } | ||
3956 | } | ||
3957 | |||
3958 | void ProcessTextureRequests() | ||
3959 | { | ||
3960 | if (m_imageManager != null) | ||
3961 | m_imageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); | ||
3962 | } | ||
3963 | |||
3964 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | ||
3965 | { | ||
3966 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); | ||
3967 | newPack.AssetBlock.Type = AssetType; | ||
3968 | newPack.AssetBlock.Success = Success; | ||
3969 | newPack.AssetBlock.UUID = AssetFullID; | ||
3970 | newPack.Header.Zerocoded = true; | ||
3971 | OutPacket(newPack, ThrottleOutPacketType.Asset); | ||
3972 | } | ||
3973 | |||
3974 | public void SendXferRequest(ulong XferID, short AssetType, UUID vFileID, byte FilePath, byte[] FileName) | ||
3975 | { | ||
3976 | RequestXferPacket newPack = new RequestXferPacket(); | ||
3977 | newPack.XferID.ID = XferID; | ||
3978 | newPack.XferID.VFileType = AssetType; | ||
3979 | newPack.XferID.VFileID = vFileID; | ||
3980 | newPack.XferID.FilePath = FilePath; | ||
3981 | newPack.XferID.Filename = FileName; | ||
3982 | newPack.Header.Zerocoded = true; | ||
3983 | OutPacket(newPack, ThrottleOutPacketType.Asset); | ||
3984 | } | ||
3985 | |||
3986 | public void SendConfirmXfer(ulong xferID, uint PacketID) | ||
3987 | { | ||
3988 | ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket(); | ||
3989 | newPack.XferID.ID = xferID; | ||
3990 | newPack.XferID.Packet = PacketID; | ||
3991 | newPack.Header.Zerocoded = true; | ||
3992 | OutPacket(newPack, ThrottleOutPacketType.Asset); | ||
3993 | } | ||
3994 | |||
3995 | public void SendInitiateDownload(string simFileName, string clientFileName) | ||
3996 | { | ||
3997 | InitiateDownloadPacket newPack = new InitiateDownloadPacket(); | ||
3998 | newPack.AgentData.AgentID = AgentId; | ||
3999 | newPack.FileData.SimFilename = Utils.StringToBytes(simFileName); | ||
4000 | newPack.FileData.ViewerFilename = Utils.StringToBytes(clientFileName); | ||
4001 | OutPacket(newPack, ThrottleOutPacketType.Asset); | ||
4002 | } | ||
4003 | |||
4004 | public void SendImageFirstPart( | ||
4005 | ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) | ||
4006 | { | ||
4007 | ImageDataPacket im = new ImageDataPacket(); | ||
4008 | im.Header.Reliable = false; | ||
4009 | im.ImageID.Packets = numParts; | ||
4010 | im.ImageID.ID = ImageUUID; | ||
4011 | |||
4012 | if (ImageSize > 0) | ||
4013 | im.ImageID.Size = ImageSize; | ||
4014 | |||
4015 | im.ImageData.Data = ImageData; | ||
4016 | im.ImageID.Codec = imageCodec; | ||
4017 | im.Header.Zerocoded = true; | ||
4018 | OutPacket(im, ThrottleOutPacketType.Texture); | ||
4019 | } | ||
4020 | |||
4021 | public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) | ||
4022 | { | ||
4023 | ImagePacketPacket im = new ImagePacketPacket(); | ||
4024 | im.Header.Reliable = false; | ||
4025 | im.ImageID.Packet = partNumber; | ||
4026 | im.ImageID.ID = imageUuid; | ||
4027 | im.ImageData.Data = imageData; | ||
4028 | |||
4029 | OutPacket(im, ThrottleOutPacketType.Texture); | ||
4030 | } | ||
4031 | |||
4032 | public void SendImageNotFound(UUID imageid) | ||
4033 | { | ||
4034 | ImageNotInDatabasePacket notFoundPacket | ||
4035 | = (ImageNotInDatabasePacket)PacketPool.Instance.GetPacket(PacketType.ImageNotInDatabase); | ||
4036 | |||
4037 | notFoundPacket.ImageID.ID = imageid; | ||
4038 | |||
4039 | OutPacket(notFoundPacket, ThrottleOutPacketType.Texture); | ||
4040 | } | ||
4041 | |||
4042 | public void SendShutdownConnectionNotice() | ||
4043 | { | ||
4044 | OutPacket(PacketPool.Instance.GetPacket(PacketType.DisableSimulator), ThrottleOutPacketType.Unknown); | ||
4045 | } | ||
4046 | |||
4047 | public void SendSimStats(SimStats stats) | ||
4048 | { | ||
4049 | SimStatsPacket pack = new SimStatsPacket(); | ||
4050 | pack.Region = new SimStatsPacket.RegionBlock(); | ||
4051 | pack.Region.RegionX = stats.RegionX; | ||
4052 | pack.Region.RegionY = stats.RegionY; | ||
4053 | pack.Region.RegionFlags = stats.RegionFlags; | ||
4054 | pack.Region.ObjectCapacity = stats.ObjectCapacity; | ||
4055 | //pack.Region = //stats.RegionBlock; | ||
4056 | pack.Stat = stats.StatsBlock; | ||
4057 | |||
4058 | pack.Header.Reliable = false; | ||
4059 | |||
4060 | OutPacket(pack, ThrottleOutPacketType.Task); | ||
4061 | } | ||
4062 | |||
4063 | private class ObjectPropertyUpdate : IEntityUpdate | ||
4064 | { | ||
4065 | internal bool SendFamilyProps; | ||
4066 | internal bool SendObjectProps; | ||
4067 | |||
4068 | public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) | ||
4069 | : base(entity,flags) | ||
4070 | { | ||
4071 | SendFamilyProps = sendfam; | ||
4072 | SendObjectProps = sendobj; | ||
4073 | } | ||
4074 | public void Update(ObjectPropertyUpdate update) | ||
4075 | { | ||
4076 | SendFamilyProps = SendFamilyProps || update.SendFamilyProps; | ||
4077 | SendObjectProps = SendObjectProps || update.SendObjectProps; | ||
4078 | // other properties may need to be updated by base class | ||
4079 | base.Update(update); | ||
4080 | } | ||
4081 | } | ||
4082 | |||
4083 | public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) | ||
4084 | { | ||
4085 | uint priority = 0; // time based ordering only | ||
4086 | lock (m_entityProps.SyncRoot) | ||
4087 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); | ||
4088 | } | ||
4089 | |||
4090 | private void ResendPropertyUpdate(ObjectPropertyUpdate update) | ||
4091 | { | ||
4092 | uint priority = 0; | ||
4093 | lock (m_entityProps.SyncRoot) | ||
4094 | m_entityProps.Enqueue(priority, update); | ||
4095 | } | ||
4096 | |||
4097 | private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket) | ||
4098 | { | ||
4099 | // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime); | ||
4100 | |||
4101 | // Remove the update packet from the list of packets waiting for acknowledgement | ||
4102 | // because we are requeuing the list of updates. They will be resent in new packets | ||
4103 | // with the most recent state. | ||
4104 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); | ||
4105 | |||
4106 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | ||
4107 | Interlocked.Increment(ref m_udpClient.PacketsResent); | ||
4108 | |||
4109 | foreach (ObjectPropertyUpdate update in updates) | ||
4110 | ResendPropertyUpdate(update); | ||
4111 | } | ||
4112 | |||
4113 | public void SendObjectPropertiesReply(ISceneEntity entity) | ||
4114 | { | ||
4115 | uint priority = 0; // time based ordering only | ||
4116 | lock (m_entityProps.SyncRoot) | ||
4117 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); | ||
4118 | } | ||
4119 | |||
4120 | private void ProcessEntityPropertyRequests(int maxUpdates) | ||
4121 | { | ||
4122 | OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks = | ||
4123 | new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>(); | ||
4124 | |||
4125 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = | ||
4126 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); | ||
4127 | |||
4128 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates = | ||
4129 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4130 | |||
4131 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates = | ||
4132 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4133 | |||
4134 | IEntityUpdate iupdate; | ||
4135 | Int32 timeinqueue; // this is just debugging code & can be dropped later | ||
4136 | |||
4137 | int updatesThisCall = 0; | ||
4138 | while (updatesThisCall < m_maxUpdates) | ||
4139 | { | ||
4140 | lock (m_entityProps.SyncRoot) | ||
4141 | if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) | ||
4142 | break; | ||
4143 | |||
4144 | ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; | ||
4145 | if (update.SendFamilyProps) | ||
4146 | { | ||
4147 | if (update.Entity is SceneObjectPart) | ||
4148 | { | ||
4149 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | ||
4150 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); | ||
4151 | objectFamilyBlocks.Value.Add(objPropDB); | ||
4152 | familyUpdates.Value.Add(update); | ||
4153 | } | ||
4154 | } | ||
4155 | |||
4156 | if (update.SendObjectProps) | ||
4157 | { | ||
4158 | if (update.Entity is SceneObjectPart) | ||
4159 | { | ||
4160 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | ||
4161 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); | ||
4162 | objectPropertiesBlocks.Value.Add(objPropDB); | ||
4163 | propertyUpdates.Value.Add(update); | ||
4164 | } | ||
4165 | } | ||
4166 | |||
4167 | updatesThisCall++; | ||
4168 | } | ||
4169 | |||
4170 | |||
4171 | // Int32 ppcnt = 0; | ||
4172 | // Int32 pbcnt = 0; | ||
4173 | |||
4174 | if (objectPropertiesBlocks.IsValueCreated) | ||
4175 | { | ||
4176 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; | ||
4177 | List<ObjectPropertyUpdate> updates = propertyUpdates.Value; | ||
4178 | |||
4179 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | ||
4180 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; | ||
4181 | for (int i = 0; i < blocks.Count; i++) | ||
4182 | packet.ObjectData[i] = blocks[i]; | ||
4183 | |||
4184 | packet.Header.Zerocoded = true; | ||
4185 | |||
4186 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties | ||
4187 | // of the object rather than the properties when the packet was created | ||
4188 | OutPacket(packet, ThrottleOutPacketType.Task, true, | ||
4189 | delegate(OutgoingPacket oPacket) | ||
4190 | { | ||
4191 | ResendPropertyUpdates(updates, oPacket); | ||
4192 | }); | ||
4193 | |||
4194 | // pbcnt += blocks.Count; | ||
4195 | // ppcnt++; | ||
4196 | } | ||
4197 | |||
4198 | // Int32 fpcnt = 0; | ||
4199 | // Int32 fbcnt = 0; | ||
4200 | |||
4201 | if (objectFamilyBlocks.IsValueCreated) | ||
4202 | { | ||
4203 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; | ||
4204 | |||
4205 | // one packet per object block... uggh... | ||
4206 | for (int i = 0; i < blocks.Count; i++) | ||
4207 | { | ||
4208 | ObjectPropertiesFamilyPacket packet = | ||
4209 | (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | ||
4210 | |||
4211 | packet.ObjectData = blocks[i]; | ||
4212 | packet.Header.Zerocoded = true; | ||
4213 | |||
4214 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties | ||
4215 | // of the object rather than the properties when the packet was created | ||
4216 | List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); | ||
4217 | updates.Add(familyUpdates.Value[i]); | ||
4218 | OutPacket(packet, ThrottleOutPacketType.Task, true, | ||
4219 | delegate(OutgoingPacket oPacket) | ||
4220 | { | ||
4221 | ResendPropertyUpdates(updates, oPacket); | ||
4222 | }); | ||
4223 | |||
4224 | // fpcnt++; | ||
4225 | // fbcnt++; | ||
4226 | } | ||
4227 | |||
4228 | } | ||
4229 | |||
4230 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); | ||
4231 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); | ||
4232 | } | ||
4233 | |||
4234 | private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) | ||
4235 | { | ||
4236 | ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); | ||
4237 | |||
4238 | block.RequestFlags = requestFlags; | ||
4239 | block.ObjectID = sop.UUID; | ||
4240 | if (sop.OwnerID == sop.GroupID) | ||
4241 | block.OwnerID = UUID.Zero; | ||
4242 | else | ||
4243 | block.OwnerID = sop.OwnerID; | ||
4244 | block.GroupID = sop.GroupID; | ||
4245 | block.BaseMask = sop.BaseMask; | ||
4246 | block.OwnerMask = sop.OwnerMask; | ||
4247 | block.GroupMask = sop.GroupMask; | ||
4248 | block.EveryoneMask = sop.EveryoneMask; | ||
4249 | block.NextOwnerMask = sop.NextOwnerMask; | ||
4250 | |||
4251 | // TODO: More properties are needed in SceneObjectPart! | ||
4252 | block.OwnershipCost = sop.OwnershipCost; | ||
4253 | block.SaleType = sop.ObjectSaleType; | ||
4254 | block.SalePrice = sop.SalePrice; | ||
4255 | block.Category = sop.Category; | ||
4256 | block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? | ||
4257 | block.Name = Util.StringToBytes256(sop.Name); | ||
4258 | block.Description = Util.StringToBytes256(sop.Description); | ||
4259 | |||
4260 | return block; | ||
4261 | } | ||
4262 | |||
4263 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) | ||
4264 | { | ||
4265 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | ||
4266 | // TODO: don't create new blocks if recycling an old packet | ||
4267 | |||
4268 | ObjectPropertiesPacket.ObjectDataBlock block = | ||
4269 | new ObjectPropertiesPacket.ObjectDataBlock(); | ||
4270 | |||
4271 | block.ObjectID = sop.UUID; | ||
4272 | block.Name = Util.StringToBytes256(sop.Name); | ||
4273 | block.Description = Util.StringToBytes256(sop.Description); | ||
4274 | |||
4275 | block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds | ||
4276 | block.CreatorID = sop.CreatorID; | ||
4277 | block.GroupID = sop.GroupID; | ||
4278 | block.LastOwnerID = sop.LastOwnerID; | ||
4279 | if (sop.OwnerID == sop.GroupID) | ||
4280 | block.OwnerID = UUID.Zero; | ||
4281 | else | ||
4282 | block.OwnerID = sop.OwnerID; | ||
4283 | |||
4284 | block.ItemID = sop.FromUserInventoryItemID; | ||
4285 | block.FolderID = UUID.Zero; // sop.FromFolderID ?? | ||
4286 | block.FromTaskID = UUID.Zero; // ??? | ||
4287 | block.InventorySerial = (short)sop.InventorySerial; | ||
4288 | |||
4289 | SceneObjectPart root = sop.ParentGroup.RootPart; | ||
4290 | |||
4291 | block.TouchName = Util.StringToBytes256(root.TouchName); | ||
4292 | block.TextureID = new byte[0]; // TextureID ??? | ||
4293 | block.SitName = Util.StringToBytes256(root.SitName); | ||
4294 | block.OwnerMask = root.OwnerMask; | ||
4295 | block.NextOwnerMask = root.NextOwnerMask; | ||
4296 | block.GroupMask = root.GroupMask; | ||
4297 | block.EveryoneMask = root.EveryoneMask; | ||
4298 | block.BaseMask = root.BaseMask; | ||
4299 | block.SaleType = root.ObjectSaleType; | ||
4300 | block.SalePrice = root.SalePrice; | ||
4301 | |||
4302 | return block; | ||
4303 | } | ||
4304 | |||
4305 | #region Estate Data Sending Methods | ||
4306 | |||
4307 | private static bool convertParamStringToBool(byte[] field) | ||
4308 | { | ||
4309 | string s = Utils.BytesToString(field); | ||
4310 | if (s == "1" || s.ToLower() == "y" || s.ToLower() == "yes" || s.ToLower() == "t" || s.ToLower() == "true") | ||
4311 | { | ||
4312 | return true; | ||
4313 | } | ||
4314 | return false; | ||
4315 | } | ||
4316 | |||
4317 | public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID) | ||
4318 | |||
4319 | { | ||
4320 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); | ||
4321 | packet.AgentData.TransactionID = UUID.Random(); | ||
4322 | packet.AgentData.AgentID = AgentId; | ||
4323 | packet.AgentData.SessionID = SessionId; | ||
4324 | packet.MethodData.Invoice = invoice; | ||
4325 | packet.MethodData.Method = Utils.StringToBytes("setaccess"); | ||
4326 | |||
4327 | EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + Data.Length]; | ||
4328 | |||
4329 | for (int i = 0; i < (6 + Data.Length); i++) | ||
4330 | { | ||
4331 | returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); | ||
4332 | } | ||
4333 | int j = 0; | ||
4334 | |||
4335 | returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; | ||
4336 | returnblock[j].Parameter = Utils.StringToBytes(code.ToString()); j++; | ||
4337 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4338 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4339 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4340 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4341 | |||
4342 | j = 2; // Agents | ||
4343 | if ((code & 2) != 0) | ||
4344 | j = 3; // Groups | ||
4345 | if ((code & 8) != 0) | ||
4346 | j = 5; // Managers | ||
4347 | |||
4348 | returnblock[j].Parameter = Utils.StringToBytes(Data.Length.ToString()); | ||
4349 | j = 6; | ||
4350 | |||
4351 | for (int i = 0; i < Data.Length; i++) | ||
4352 | { | ||
4353 | returnblock[j].Parameter = Data[i].GetBytes(); j++; | ||
4354 | } | ||
4355 | packet.ParamList = returnblock; | ||
4356 | packet.Header.Reliable = true; | ||
4357 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4358 | } | ||
4359 | |||
4360 | public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) | ||
4361 | { | ||
4362 | List<UUID> BannedUsers = new List<UUID>(); | ||
4363 | |||
4364 | for (int i = 0; i < bl.Length; i++) | ||
4365 | { | ||
4366 | if (bl[i] == null) | ||
4367 | continue; | ||
4368 | if (bl[i].BannedUserID == UUID.Zero) | ||
4369 | continue; | ||
4370 | BannedUsers.Add(bl[i].BannedUserID); | ||
4371 | } | ||
4372 | |||
4373 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); | ||
4374 | packet.AgentData.TransactionID = UUID.Random(); | ||
4375 | packet.AgentData.AgentID = AgentId; | ||
4376 | packet.AgentData.SessionID = SessionId; | ||
4377 | packet.MethodData.Invoice = invoice; | ||
4378 | packet.MethodData.Method = Utils.StringToBytes("setaccess"); | ||
4379 | |||
4380 | EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count]; | ||
4381 | |||
4382 | for (int i = 0; i < (6 + BannedUsers.Count); i++) | ||
4383 | { | ||
4384 | returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); | ||
4385 | } | ||
4386 | int j = 0; | ||
4387 | |||
4388 | returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; | ||
4389 | returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; | ||
4390 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4391 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4392 | returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++; | ||
4393 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4394 | |||
4395 | foreach (UUID banned in BannedUsers) | ||
4396 | { | ||
4397 | returnblock[j].Parameter = banned.GetBytes(); j++; | ||
4398 | } | ||
4399 | packet.ParamList = returnblock; | ||
4400 | packet.Header.Reliable = false; | ||
4401 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4402 | } | ||
4403 | |||
4404 | public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) | ||
4405 | { | ||
4406 | RegionInfoPacket rinfopack = new RegionInfoPacket(); | ||
4407 | RegionInfoPacket.RegionInfoBlock rinfoblk = new RegionInfoPacket.RegionInfoBlock(); | ||
4408 | rinfopack.AgentData.AgentID = AgentId; | ||
4409 | rinfopack.AgentData.SessionID = SessionId; | ||
4410 | rinfoblk.BillableFactor = args.billableFactor; | ||
4411 | rinfoblk.EstateID = args.estateID; | ||
4412 | rinfoblk.MaxAgents = args.maxAgents; | ||
4413 | rinfoblk.ObjectBonusFactor = args.objectBonusFactor; | ||
4414 | rinfoblk.ParentEstateID = args.parentEstateID; | ||
4415 | rinfoblk.PricePerMeter = args.pricePerMeter; | ||
4416 | rinfoblk.RedirectGridX = args.redirectGridX; | ||
4417 | rinfoblk.RedirectGridY = args.redirectGridY; | ||
4418 | rinfoblk.RegionFlags = args.regionFlags; | ||
4419 | rinfoblk.SimAccess = args.simAccess; | ||
4420 | rinfoblk.SunHour = args.sunHour; | ||
4421 | rinfoblk.TerrainLowerLimit = args.terrainLowerLimit; | ||
4422 | rinfoblk.TerrainRaiseLimit = args.terrainRaiseLimit; | ||
4423 | rinfoblk.UseEstateSun = args.useEstateSun; | ||
4424 | rinfoblk.WaterHeight = args.waterHeight; | ||
4425 | rinfoblk.SimName = Utils.StringToBytes(args.simName); | ||
4426 | |||
4427 | rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block(); | ||
4428 | rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue; | ||
4429 | rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue; | ||
4430 | rinfopack.RegionInfo2.MaxAgents32 = uint.MaxValue; | ||
4431 | rinfopack.RegionInfo2.ProductName = Util.StringToBytes256(args.regionType); | ||
4432 | rinfopack.RegionInfo2.ProductSKU = Utils.EmptyBytes; | ||
4433 | |||
4434 | rinfopack.HasVariableBlocks = true; | ||
4435 | rinfopack.RegionInfo = rinfoblk; | ||
4436 | rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock(); | ||
4437 | rinfopack.AgentData.AgentID = AgentId; | ||
4438 | rinfopack.AgentData.SessionID = SessionId; | ||
4439 | |||
4440 | |||
4441 | OutPacket(rinfopack, ThrottleOutPacketType.Task); | ||
4442 | } | ||
4443 | |||
4444 | public void SendEstateCovenantInformation(UUID covenant) | ||
4445 | { | ||
4446 | // m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name); | ||
4447 | |||
4448 | EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); | ||
4449 | EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); | ||
4450 | edata.CovenantID = covenant; | ||
4451 | edata.CovenantTimestamp = 0; | ||
4452 | edata.EstateOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | ||
4453 | edata.EstateName = Utils.StringToBytes(m_scene.RegionInfo.EstateSettings.EstateName); | ||
4454 | einfopack.Data = edata; | ||
4455 | OutPacket(einfopack, ThrottleOutPacketType.Task); | ||
4456 | } | ||
4457 | |||
4458 | public void SendDetailedEstateData( | ||
4459 | UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, | ||
4460 | UUID covenant, string abuseEmail, UUID estateOwner) | ||
4461 | { | ||
4462 | // m_log.DebugFormat( | ||
4463 | // "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant); | ||
4464 | |||
4465 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); | ||
4466 | packet.MethodData.Invoice = invoice; | ||
4467 | packet.AgentData.TransactionID = UUID.Random(); | ||
4468 | packet.MethodData.Method = Utils.StringToBytes("estateupdateinfo"); | ||
4469 | EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[10]; | ||
4470 | |||
4471 | for (int i = 0; i < 10; i++) | ||
4472 | { | ||
4473 | returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); | ||
4474 | } | ||
4475 | |||
4476 | //Sending Estate Settings | ||
4477 | returnblock[0].Parameter = Utils.StringToBytes(estateName); | ||
4478 | returnblock[1].Parameter = Utils.StringToBytes(estateOwner.ToString()); | ||
4479 | returnblock[2].Parameter = Utils.StringToBytes(estateID.ToString()); | ||
4480 | |||
4481 | returnblock[3].Parameter = Utils.StringToBytes(estateFlags.ToString()); | ||
4482 | returnblock[4].Parameter = Utils.StringToBytes(sunPosition.ToString()); | ||
4483 | returnblock[5].Parameter = Utils.StringToBytes(parentEstate.ToString()); | ||
4484 | returnblock[6].Parameter = Utils.StringToBytes(covenant.ToString()); | ||
4485 | returnblock[7].Parameter = Utils.StringToBytes("1160895077"); // what is this? | ||
4486 | returnblock[8].Parameter = Utils.StringToBytes("1"); // what is this? | ||
4487 | returnblock[9].Parameter = Utils.StringToBytes(abuseEmail); | ||
4488 | |||
4489 | packet.ParamList = returnblock; | ||
4490 | packet.Header.Reliable = false; | ||
4491 | //m_log.Debug("[ESTATE]: SIM--->" + packet.ToString()); | ||
4492 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4493 | } | ||
4494 | |||
4495 | #endregion | ||
4496 | |||
4497 | #region Land Data Sending Methods | ||
4498 | |||
4499 | public void SendLandParcelOverlay(byte[] data, int sequence_id) | ||
4500 | { | ||
4501 | ParcelOverlayPacket packet = (ParcelOverlayPacket)PacketPool.Instance.GetPacket(PacketType.ParcelOverlay); | ||
4502 | packet.ParcelData.Data = data; | ||
4503 | packet.ParcelData.SequenceID = sequence_id; | ||
4504 | packet.Header.Zerocoded = true; | ||
4505 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4506 | } | ||
4507 | |||
4508 | public void SendLandProperties( | ||
4509 | int sequence_id, bool snap_selection, int request_result, ILandObject lo, | ||
4510 | float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) | ||
4511 | { | ||
4512 | // m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name); | ||
4513 | |||
4514 | LandData landData = lo.LandData; | ||
4515 | |||
4516 | ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage(); | ||
4517 | |||
4518 | updateMessage.AABBMax = landData.AABBMax; | ||
4519 | updateMessage.AABBMin = landData.AABBMin; | ||
4520 | updateMessage.Area = landData.Area; | ||
4521 | updateMessage.AuctionID = landData.AuctionID; | ||
4522 | updateMessage.AuthBuyerID = landData.AuthBuyerID; | ||
4523 | updateMessage.Bitmap = landData.Bitmap; | ||
4524 | updateMessage.Desc = landData.Description; | ||
4525 | updateMessage.Category = landData.Category; | ||
4526 | updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate); | ||
4527 | updateMessage.ClaimPrice = landData.ClaimPrice; | ||
4528 | updateMessage.GroupID = landData.GroupID; | ||
4529 | updateMessage.IsGroupOwned = landData.IsGroupOwned; | ||
4530 | updateMessage.LandingType = (LandingType) landData.LandingType; | ||
4531 | updateMessage.LocalID = landData.LocalID; | ||
4532 | |||
4533 | if (landData.Area > 0) | ||
4534 | { | ||
4535 | updateMessage.MaxPrims = parcelObjectCapacity; | ||
4536 | } | ||
4537 | else | ||
4538 | { | ||
4539 | updateMessage.MaxPrims = 0; | ||
4540 | } | ||
4541 | |||
4542 | updateMessage.MediaAutoScale = Convert.ToBoolean(landData.MediaAutoScale); | ||
4543 | updateMessage.MediaID = landData.MediaID; | ||
4544 | updateMessage.MediaURL = landData.MediaURL; | ||
4545 | updateMessage.MusicURL = landData.MusicURL; | ||
4546 | updateMessage.Name = landData.Name; | ||
4547 | updateMessage.OtherCleanTime = landData.OtherCleanTime; | ||
4548 | updateMessage.OtherCount = 0; //TODO: Unimplemented | ||
4549 | updateMessage.OwnerID = landData.OwnerID; | ||
4550 | updateMessage.ParcelFlags = (ParcelFlags) landData.Flags; | ||
4551 | updateMessage.ParcelPrimBonus = simObjectBonusFactor; | ||
4552 | updateMessage.PassHours = landData.PassHours; | ||
4553 | updateMessage.PassPrice = landData.PassPrice; | ||
4554 | updateMessage.PublicCount = 0; //TODO: Unimplemented | ||
4555 | |||
4556 | updateMessage.RegionPushOverride = (regionFlags & (uint)RegionFlags.RestrictPushObject) > 0; | ||
4557 | updateMessage.RegionDenyAnonymous = (regionFlags & (uint)RegionFlags.DenyAnonymous) > 0; | ||
4558 | |||
4559 | //updateMessage.RegionDenyIdentified = (regionFlags & (uint)RegionFlags.DenyIdentified) > 0; | ||
4560 | //updateMessage.RegionDenyTransacted = (regionFlags & (uint)RegionFlags.DenyTransacted) > 0; | ||
4561 | |||
4562 | updateMessage.RentPrice = 0; | ||
4563 | updateMessage.RequestResult = (ParcelResult) request_result; | ||
4564 | updateMessage.SalePrice = landData.SalePrice; | ||
4565 | updateMessage.SelfCount = 0; //TODO: Unimplemented | ||
4566 | updateMessage.SequenceID = sequence_id; | ||
4567 | |||
4568 | if (landData.SimwideArea > 0) | ||
4569 | { | ||
4570 | int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); | ||
4571 | updateMessage.SimWideMaxPrims = simulatorCapacity; | ||
4572 | } | ||
4573 | else | ||
4574 | { | ||
4575 | updateMessage.SimWideMaxPrims = 0; | ||
4576 | } | ||
4577 | |||
4578 | updateMessage.SnapSelection = snap_selection; | ||
4579 | updateMessage.SnapshotID = landData.SnapshotID; | ||
4580 | updateMessage.Status = (ParcelStatus) landData.Status; | ||
4581 | updateMessage.UserLocation = landData.UserLocation; | ||
4582 | updateMessage.UserLookAt = landData.UserLookAt; | ||
4583 | |||
4584 | updateMessage.MediaType = landData.MediaType; | ||
4585 | updateMessage.MediaDesc = landData.MediaDescription; | ||
4586 | updateMessage.MediaWidth = landData.MediaWidth; | ||
4587 | updateMessage.MediaHeight = landData.MediaHeight; | ||
4588 | updateMessage.MediaLoop = landData.MediaLoop; | ||
4589 | updateMessage.ObscureMusic = landData.ObscureMusic; | ||
4590 | updateMessage.ObscureMedia = landData.ObscureMedia; | ||
4591 | |||
4592 | IPrimCounts pc = lo.PrimCounts; | ||
4593 | updateMessage.OwnerPrims = pc.Owner; | ||
4594 | updateMessage.GroupPrims = pc.Group; | ||
4595 | updateMessage.OtherPrims = pc.Others; | ||
4596 | updateMessage.SelectedPrims = pc.Selected; | ||
4597 | updateMessage.TotalPrims = pc.Total; | ||
4598 | updateMessage.SimWideTotalPrims = pc.Simulator; | ||
4599 | |||
4600 | try | ||
4601 | { | ||
4602 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | ||
4603 | if (eq != null) | ||
4604 | { | ||
4605 | eq.ParcelProperties(updateMessage, this.AgentId); | ||
4606 | } | ||
4607 | else | ||
4608 | { | ||
4609 | m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data."); | ||
4610 | } | ||
4611 | } | ||
4612 | catch (Exception ex) | ||
4613 | { | ||
4614 | m_log.Error("[LLCLIENTVIEW]: Unable to send parcel data via eventqueue - exception: " + ex.ToString()); | ||
4615 | } | ||
4616 | } | ||
4617 | |||
4618 | public void SendLandAccessListData(List<UUID> avatars, uint accessFlag, int localLandID) | ||
4619 | { | ||
4620 | ParcelAccessListReplyPacket replyPacket = (ParcelAccessListReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply); | ||
4621 | replyPacket.Data.AgentID = AgentId; | ||
4622 | replyPacket.Data.Flags = accessFlag; | ||
4623 | replyPacket.Data.LocalID = localLandID; | ||
4624 | replyPacket.Data.SequenceID = 0; | ||
4625 | |||
4626 | List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>(); | ||
4627 | foreach (UUID avatar in avatars) | ||
4628 | { | ||
4629 | ParcelAccessListReplyPacket.ListBlock block = new ParcelAccessListReplyPacket.ListBlock(); | ||
4630 | block.Flags = accessFlag; | ||
4631 | block.ID = avatar; | ||
4632 | block.Time = 0; | ||
4633 | list.Add(block); | ||
4634 | } | ||
4635 | |||
4636 | replyPacket.List = list.ToArray(); | ||
4637 | replyPacket.Header.Zerocoded = true; | ||
4638 | OutPacket(replyPacket, ThrottleOutPacketType.Task); | ||
4639 | } | ||
4640 | |||
4641 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | ||
4642 | { | ||
4643 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | ||
4644 | |||
4645 | bool firstCall = true; | ||
4646 | const int MAX_OBJECTS_PER_PACKET = 251; | ||
4647 | ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); | ||
4648 | ForceObjectSelectPacket.DataBlock[] data; | ||
4649 | while (ObjectIDs.Count > 0) | ||
4650 | { | ||
4651 | if (firstCall) | ||
4652 | { | ||
4653 | pack._Header.ResetList = true; | ||
4654 | firstCall = false; | ||
4655 | } | ||
4656 | else | ||
4657 | { | ||
4658 | pack._Header.ResetList = false; | ||
4659 | } | ||
4660 | |||
4661 | if (ObjectIDs.Count > MAX_OBJECTS_PER_PACKET) | ||
4662 | { | ||
4663 | data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET]; | ||
4664 | } | ||
4665 | else | ||
4666 | { | ||
4667 | data = new ForceObjectSelectPacket.DataBlock[ObjectIDs.Count]; | ||
4668 | } | ||
4669 | |||
4670 | int i; | ||
4671 | for (i = 0; i < MAX_OBJECTS_PER_PACKET && ObjectIDs.Count > 0; i++) | ||
4672 | { | ||
4673 | data[i] = new ForceObjectSelectPacket.DataBlock(); | ||
4674 | data[i].LocalID = Convert.ToUInt32(ObjectIDs[0]); | ||
4675 | ObjectIDs.RemoveAt(0); | ||
4676 | } | ||
4677 | pack.Data = data; | ||
4678 | pack.Header.Zerocoded = true; | ||
4679 | OutPacket(pack, ThrottleOutPacketType.Task); | ||
4680 | } | ||
4681 | } | ||
4682 | |||
4683 | public void SendCameraConstraint(Vector4 ConstraintPlane) | ||
4684 | { | ||
4685 | CameraConstraintPacket cpack = (CameraConstraintPacket)PacketPool.Instance.GetPacket(PacketType.CameraConstraint); | ||
4686 | cpack.CameraCollidePlane = new CameraConstraintPacket.CameraCollidePlaneBlock(); | ||
4687 | cpack.CameraCollidePlane.Plane = ConstraintPlane; | ||
4688 | //m_log.DebugFormat("[CLIENTVIEW]: Constraint {0}", ConstraintPlane); | ||
4689 | OutPacket(cpack, ThrottleOutPacketType.Task); | ||
4690 | } | ||
4691 | |||
4692 | public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount) | ||
4693 | { | ||
4694 | int notifyCount = ownersAndCount.Count; | ||
4695 | ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply); | ||
4696 | |||
4697 | if (notifyCount > 0) | ||
4698 | { | ||
4699 | // if (notifyCount > 32) | ||
4700 | // { | ||
4701 | // m_log.InfoFormat( | ||
4702 | // "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" | ||
4703 | // + " - a developer might want to investigate whether this is a hard limit", 32); | ||
4704 | // | ||
4705 | // notifyCount = 32; | ||
4706 | // } | ||
4707 | |||
4708 | ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock | ||
4709 | = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; | ||
4710 | |||
4711 | int num = 0; | ||
4712 | foreach (UUID owner in ownersAndCount.Keys) | ||
4713 | { | ||
4714 | dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock(); | ||
4715 | dataBlock[num].Count = ownersAndCount[owner]; | ||
4716 | |||
4717 | if (land.GroupID == owner || groups.Contains(owner)) | ||
4718 | dataBlock[num].IsGroupOwned = true; | ||
4719 | |||
4720 | dataBlock[num].OnlineStatus = true; //TODO: fix me later | ||
4721 | dataBlock[num].OwnerID = owner; | ||
4722 | |||
4723 | num++; | ||
4724 | |||
4725 | if (num >= notifyCount) | ||
4726 | { | ||
4727 | break; | ||
4728 | } | ||
4729 | } | ||
4730 | |||
4731 | pack.Data = dataBlock; | ||
4732 | } | ||
4733 | else | ||
4734 | { | ||
4735 | pack.Data = new ParcelObjectOwnersReplyPacket.DataBlock[0]; | ||
4736 | } | ||
4737 | pack.Header.Zerocoded = true; | ||
4738 | this.OutPacket(pack, ThrottleOutPacketType.Task); | ||
4739 | } | ||
4740 | |||
4741 | #endregion | ||
4742 | |||
4743 | #region Helper Methods | ||
4744 | |||
4745 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture) | ||
4746 | { | ||
4747 | #region ScenePresence/SOP Handling | ||
4748 | |||
4749 | bool avatar = (entity is ScenePresence); | ||
4750 | uint localID = entity.LocalId; | ||
4751 | uint attachPoint; | ||
4752 | Vector4 collisionPlane; | ||
4753 | Vector3 position, velocity, acceleration, angularVelocity; | ||
4754 | Quaternion rotation; | ||
4755 | byte[] textureEntry; | ||
4756 | |||
4757 | if (entity is ScenePresence) | ||
4758 | { | ||
4759 | ScenePresence presence = (ScenePresence)entity; | ||
4760 | |||
4761 | attachPoint = 0; | ||
4762 | collisionPlane = presence.CollisionPlane; | ||
4763 | position = presence.OffsetPosition; | ||
4764 | velocity = presence.Velocity; | ||
4765 | acceleration = Vector3.Zero; | ||
4766 | angularVelocity = Vector3.Zero; | ||
4767 | rotation = presence.Rotation; | ||
4768 | |||
4769 | if (sendTexture) | ||
4770 | textureEntry = presence.Appearance.Texture.GetBytes(); | ||
4771 | else | ||
4772 | textureEntry = null; | ||
4773 | } | ||
4774 | else | ||
4775 | { | ||
4776 | SceneObjectPart part = (SceneObjectPart)entity; | ||
4777 | |||
4778 | attachPoint = part.AttachmentPoint; | ||
4779 | collisionPlane = Vector4.Zero; | ||
4780 | position = part.RelativePosition; | ||
4781 | velocity = part.Velocity; | ||
4782 | acceleration = part.Acceleration; | ||
4783 | angularVelocity = part.AngularVelocity; | ||
4784 | rotation = part.RotationOffset; | ||
4785 | |||
4786 | if (sendTexture) | ||
4787 | textureEntry = part.Shape.TextureEntry; | ||
4788 | else | ||
4789 | textureEntry = null; | ||
4790 | } | ||
4791 | |||
4792 | #endregion ScenePresence/SOP Handling | ||
4793 | |||
4794 | int pos = 0; | ||
4795 | byte[] data = new byte[(avatar ? 60 : 44)]; | ||
4796 | |||
4797 | // LocalID | ||
4798 | Utils.UIntToBytes(localID, data, pos); | ||
4799 | pos += 4; | ||
4800 | |||
4801 | // Avatar/CollisionPlane | ||
4802 | data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; | ||
4803 | if (avatar) | ||
4804 | { | ||
4805 | data[pos++] = 1; | ||
4806 | |||
4807 | if (collisionPlane == Vector4.Zero) | ||
4808 | collisionPlane = Vector4.UnitW; | ||
4809 | //m_log.DebugFormat("CollisionPlane: {0}",collisionPlane); | ||
4810 | collisionPlane.ToBytes(data, pos); | ||
4811 | pos += 16; | ||
4812 | } | ||
4813 | else | ||
4814 | { | ||
4815 | ++pos; | ||
4816 | } | ||
4817 | |||
4818 | // Position | ||
4819 | position.ToBytes(data, pos); | ||
4820 | pos += 12; | ||
4821 | |||
4822 | // Velocity | ||
4823 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2; | ||
4824 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; | ||
4825 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; | ||
4826 | |||
4827 | // Acceleration | ||
4828 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; | ||
4829 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; | ||
4830 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; | ||
4831 | |||
4832 | // Rotation | ||
4833 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.X, -1.0f, 1.0f), data, pos); pos += 2; | ||
4834 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Y, -1.0f, 1.0f), data, pos); pos += 2; | ||
4835 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Z, -1.0f, 1.0f), data, pos); pos += 2; | ||
4836 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2; | ||
4837 | |||
4838 | // Angular Velocity | ||
4839 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; | ||
4840 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; | ||
4841 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; | ||
4842 | |||
4843 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); | ||
4844 | block.Data = data; | ||
4845 | |||
4846 | if (textureEntry != null && textureEntry.Length > 0) | ||
4847 | { | ||
4848 | byte[] teBytesFinal = new byte[textureEntry.Length + 4]; | ||
4849 | |||
4850 | // Texture Length | ||
4851 | Utils.IntToBytes(textureEntry.Length, textureEntry, 0); | ||
4852 | // Texture | ||
4853 | Buffer.BlockCopy(textureEntry, 0, teBytesFinal, 4, textureEntry.Length); | ||
4854 | |||
4855 | block.TextureEntry = teBytesFinal; | ||
4856 | } | ||
4857 | else | ||
4858 | { | ||
4859 | block.TextureEntry = Utils.EmptyBytes; | ||
4860 | } | ||
4861 | |||
4862 | return block; | ||
4863 | } | ||
4864 | |||
4865 | protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) | ||
4866 | { | ||
4867 | byte[] objectData = new byte[76]; | ||
4868 | |||
4869 | data.CollisionPlane.ToBytes(objectData, 0); | ||
4870 | data.OffsetPosition.ToBytes(objectData, 16); | ||
4871 | //data.Velocity.ToBytes(objectData, 28); | ||
4872 | //data.Acceleration.ToBytes(objectData, 40); | ||
4873 | data.Rotation.ToBytes(objectData, 52); | ||
4874 | //data.AngularVelocity.ToBytes(objectData, 64); | ||
4875 | |||
4876 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | ||
4877 | |||
4878 | update.Data = Utils.EmptyBytes; | ||
4879 | update.ExtraParams = new byte[1]; | ||
4880 | update.FullID = data.UUID; | ||
4881 | update.ID = data.LocalId; | ||
4882 | update.Material = (byte)Material.Flesh; | ||
4883 | update.MediaURL = Utils.EmptyBytes; | ||
4884 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + | ||
4885 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); | ||
4886 | update.ObjectData = objectData; | ||
4887 | update.ParentID = data.ParentID; | ||
4888 | update.PathCurve = 16; | ||
4889 | update.PathScaleX = 100; | ||
4890 | update.PathScaleY = 100; | ||
4891 | update.PCode = (byte)PCode.Avatar; | ||
4892 | update.ProfileCurve = 1; | ||
4893 | update.PSBlock = Utils.EmptyBytes; | ||
4894 | update.Scale = new Vector3(0.45f, 0.6f, 1.9f); | ||
4895 | update.Text = Utils.EmptyBytes; | ||
4896 | update.TextColor = new byte[4]; | ||
4897 | update.TextureAnim = Utils.EmptyBytes; | ||
4898 | update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; | ||
4899 | update.UpdateFlags = (uint)( | ||
4900 | PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | | ||
4901 | PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | | ||
4902 | PrimFlags.ObjectOwnerModify); | ||
4903 | |||
4904 | return update; | ||
4905 | } | ||
4906 | |||
4907 | protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID) | ||
4908 | { | ||
4909 | byte[] objectData = new byte[60]; | ||
4910 | data.RelativePosition.ToBytes(objectData, 0); | ||
4911 | data.Velocity.ToBytes(objectData, 12); | ||
4912 | data.Acceleration.ToBytes(objectData, 24); | ||
4913 | try | ||
4914 | { | ||
4915 | data.RotationOffset.ToBytes(objectData, 36); | ||
4916 | } | ||
4917 | catch (Exception e) | ||
4918 | { | ||
4919 | m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString()); | ||
4920 | OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36); | ||
4921 | } | ||
4922 | data.AngularVelocity.ToBytes(objectData, 48); | ||
4923 | |||
4924 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | ||
4925 | update.ClickAction = (byte)data.ClickAction; | ||
4926 | update.CRC = 0; | ||
4927 | update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes; | ||
4928 | update.FullID = data.UUID; | ||
4929 | update.ID = data.LocalId; | ||
4930 | //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated | ||
4931 | //update.JointPivot = Vector3.Zero; | ||
4932 | //update.JointType = 0; | ||
4933 | update.Material = data.Material; | ||
4934 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim | ||
4935 | if (data.IsAttachment) | ||
4936 | { | ||
4937 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID); | ||
4938 | update.State = (byte)((data.AttachmentPoint % 16) * 16 + (data.AttachmentPoint / 16)); | ||
4939 | } | ||
4940 | else | ||
4941 | { | ||
4942 | update.NameValue = Utils.EmptyBytes; | ||
4943 | update.State = data.Shape.State; | ||
4944 | } | ||
4945 | |||
4946 | update.ObjectData = objectData; | ||
4947 | update.ParentID = data.ParentID; | ||
4948 | update.PathBegin = data.Shape.PathBegin; | ||
4949 | update.PathCurve = data.Shape.PathCurve; | ||
4950 | update.PathEnd = data.Shape.PathEnd; | ||
4951 | update.PathRadiusOffset = data.Shape.PathRadiusOffset; | ||
4952 | update.PathRevolutions = data.Shape.PathRevolutions; | ||
4953 | update.PathScaleX = data.Shape.PathScaleX; | ||
4954 | update.PathScaleY = data.Shape.PathScaleY; | ||
4955 | update.PathShearX = data.Shape.PathShearX; | ||
4956 | update.PathShearY = data.Shape.PathShearY; | ||
4957 | update.PathSkew = data.Shape.PathSkew; | ||
4958 | update.PathTaperX = data.Shape.PathTaperX; | ||
4959 | update.PathTaperY = data.Shape.PathTaperY; | ||
4960 | update.PathTwist = data.Shape.PathTwist; | ||
4961 | update.PathTwistBegin = data.Shape.PathTwistBegin; | ||
4962 | update.PCode = data.Shape.PCode; | ||
4963 | update.ProfileBegin = data.Shape.ProfileBegin; | ||
4964 | update.ProfileCurve = data.Shape.ProfileCurve; | ||
4965 | update.ProfileEnd = data.Shape.ProfileEnd; | ||
4966 | update.ProfileHollow = data.Shape.ProfileHollow; | ||
4967 | update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes; | ||
4968 | update.TextColor = data.GetTextColor().GetBytes(false); | ||
4969 | update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes; | ||
4970 | update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes; | ||
4971 | update.Scale = data.Shape.Scale; | ||
4972 | update.Text = Util.StringToBytes256(data.Text); | ||
4973 | update.MediaURL = Util.StringToBytes256(data.MediaUrl); | ||
4974 | |||
4975 | #region PrimFlags | ||
4976 | |||
4977 | PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID); | ||
4978 | |||
4979 | // Don't send the CreateSelected flag to everyone | ||
4980 | flags &= ~PrimFlags.CreateSelected; | ||
4981 | |||
4982 | if (recipientID == data.OwnerID) | ||
4983 | { | ||
4984 | if (data.CreateSelected) | ||
4985 | { | ||
4986 | // Only send this flag once, then unset it | ||
4987 | flags |= PrimFlags.CreateSelected; | ||
4988 | data.CreateSelected = false; | ||
4989 | } | ||
4990 | } | ||
4991 | |||
4992 | // m_log.DebugFormat( | ||
4993 | // "[LLCLIENTVIEW]: Constructing client update for part {0} {1} with flags {2}, localId {3}", | ||
4994 | // data.Name, update.FullID, flags, update.ID); | ||
4995 | |||
4996 | update.UpdateFlags = (uint)flags; | ||
4997 | |||
4998 | #endregion PrimFlags | ||
4999 | |||
5000 | if (data.Sound != UUID.Zero) | ||
5001 | { | ||
5002 | update.Sound = data.Sound; | ||
5003 | update.OwnerID = data.OwnerID; | ||
5004 | update.Gain = (float)data.SoundGain; | ||
5005 | update.Radius = (float)data.SoundRadius; | ||
5006 | update.Flags = data.SoundFlags; | ||
5007 | } | ||
5008 | |||
5009 | switch ((PCode)data.Shape.PCode) | ||
5010 | { | ||
5011 | case PCode.Grass: | ||
5012 | case PCode.Tree: | ||
5013 | case PCode.NewTree: | ||
5014 | update.Data = new byte[] { data.Shape.State }; | ||
5015 | break; | ||
5016 | default: | ||
5017 | update.Data = Utils.EmptyBytes; | ||
5018 | break; | ||
5019 | } | ||
5020 | |||
5021 | return update; | ||
5022 | } | ||
5023 | |||
5024 | protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags) | ||
5025 | { | ||
5026 | // TODO: Implement this | ||
5027 | return null; | ||
5028 | } | ||
5029 | |||
5030 | public void SendNameReply(UUID profileId, string firstname, string lastname) | ||
5031 | { | ||
5032 | UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply); | ||
5033 | // TODO: don't create new blocks if recycling an old packet | ||
5034 | packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1]; | ||
5035 | packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock(); | ||
5036 | packet.UUIDNameBlock[0].ID = profileId; | ||
5037 | packet.UUIDNameBlock[0].FirstName = Util.StringToBytes256(firstname); | ||
5038 | packet.UUIDNameBlock[0].LastName = Util.StringToBytes256(lastname); | ||
5039 | |||
5040 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
5041 | } | ||
5042 | |||
5043 | public ulong GetGroupPowers(UUID groupID) | ||
5044 | { | ||
5045 | if (groupID == m_activeGroupID) | ||
5046 | return m_activeGroupPowers; | ||
5047 | |||
5048 | if (m_groupPowers.ContainsKey(groupID)) | ||
5049 | return m_groupPowers[groupID]; | ||
5050 | |||
5051 | return 0; | ||
5052 | } | ||
5053 | |||
5054 | /// <summary> | ||
5055 | /// This is a utility method used by single states to not duplicate kicks and blue card of death messages. | ||
5056 | /// </summary> | ||
5057 | public bool ChildAgentStatus() | ||
5058 | { | ||
5059 | return m_scene.PresenceChildStatus(AgentId); | ||
5060 | } | ||
5061 | |||
5062 | #endregion | ||
5063 | |||
5064 | /// <summary> | ||
5065 | /// This is a different way of processing packets then ProcessInPacket | ||
5066 | /// </summary> | ||
5067 | protected virtual void RegisterLocalPacketHandlers() | ||
5068 | { | ||
5069 | AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout); | ||
5070 | AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); | ||
5071 | AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); | ||
5072 | AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); | ||
5073 | AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); | ||
5074 | AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); | ||
5075 | AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); | ||
5076 | AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest, false); | ||
5077 | AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest, false); | ||
5078 | AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage); | ||
5079 | AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest); | ||
5080 | AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); | ||
5081 | AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate); | ||
5082 | AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); | ||
5083 | AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage, false); | ||
5084 | AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); | ||
5085 | AddLocalPacketHandler(PacketType.DeclineFriendship, HandlerDeclineFriendship); | ||
5086 | AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFrendship); | ||
5087 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); | ||
5088 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); | ||
5089 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); | ||
5090 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); | ||
5091 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); | ||
5092 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); | ||
5093 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); | ||
5094 | AddLocalPacketHandler(PacketType.RezSingleAttachmentFromInv, HandlerRezSingleAttachmentFromInv); | ||
5095 | AddLocalPacketHandler(PacketType.RezMultipleAttachmentsFromInv, HandleRezMultipleAttachmentsFromInv); | ||
5096 | AddLocalPacketHandler(PacketType.DetachAttachmentIntoInv, HandleDetachAttachmentIntoInv); | ||
5097 | AddLocalPacketHandler(PacketType.ObjectAttach, HandleObjectAttach); | ||
5098 | AddLocalPacketHandler(PacketType.ObjectDetach, HandleObjectDetach); | ||
5099 | AddLocalPacketHandler(PacketType.ObjectDrop, HandleObjectDrop); | ||
5100 | AddLocalPacketHandler(PacketType.SetAlwaysRun, HandleSetAlwaysRun, false); | ||
5101 | AddLocalPacketHandler(PacketType.CompleteAgentMovement, HandleCompleteAgentMovement); | ||
5102 | AddLocalPacketHandler(PacketType.AgentAnimation, HandleAgentAnimation, false); | ||
5103 | AddLocalPacketHandler(PacketType.AgentRequestSit, HandleAgentRequestSit); | ||
5104 | AddLocalPacketHandler(PacketType.AgentSit, HandleAgentSit); | ||
5105 | AddLocalPacketHandler(PacketType.SoundTrigger, HandleSoundTrigger); | ||
5106 | AddLocalPacketHandler(PacketType.AvatarPickerRequest, HandleAvatarPickerRequest); | ||
5107 | AddLocalPacketHandler(PacketType.AgentDataUpdateRequest, HandleAgentDataUpdateRequest); | ||
5108 | AddLocalPacketHandler(PacketType.UserInfoRequest, HandleUserInfoRequest); | ||
5109 | AddLocalPacketHandler(PacketType.UpdateUserInfo, HandleUpdateUserInfo); | ||
5110 | AddLocalPacketHandler(PacketType.SetStartLocationRequest, HandleSetStartLocationRequest); | ||
5111 | AddLocalPacketHandler(PacketType.AgentThrottle, HandleAgentThrottle, false); | ||
5112 | AddLocalPacketHandler(PacketType.AgentPause, HandleAgentPause, false); | ||
5113 | AddLocalPacketHandler(PacketType.AgentResume, HandleAgentResume, false); | ||
5114 | AddLocalPacketHandler(PacketType.ForceScriptControlRelease, HandleForceScriptControlRelease); | ||
5115 | AddLocalPacketHandler(PacketType.ObjectLink, HandleObjectLink); | ||
5116 | AddLocalPacketHandler(PacketType.ObjectDelink, HandleObjectDelink); | ||
5117 | AddLocalPacketHandler(PacketType.ObjectAdd, HandleObjectAdd); | ||
5118 | AddLocalPacketHandler(PacketType.ObjectShape, HandleObjectShape); | ||
5119 | AddLocalPacketHandler(PacketType.ObjectExtraParams, HandleObjectExtraParams); | ||
5120 | AddLocalPacketHandler(PacketType.ObjectDuplicate, HandleObjectDuplicate); | ||
5121 | AddLocalPacketHandler(PacketType.RequestMultipleObjects, HandleRequestMultipleObjects); | ||
5122 | AddLocalPacketHandler(PacketType.ObjectSelect, HandleObjectSelect); | ||
5123 | AddLocalPacketHandler(PacketType.ObjectDeselect, HandleObjectDeselect); | ||
5124 | AddLocalPacketHandler(PacketType.ObjectPosition, HandleObjectPosition); | ||
5125 | AddLocalPacketHandler(PacketType.ObjectScale, HandleObjectScale); | ||
5126 | AddLocalPacketHandler(PacketType.ObjectRotation, HandleObjectRotation); | ||
5127 | AddLocalPacketHandler(PacketType.ObjectFlagUpdate, HandleObjectFlagUpdate); | ||
5128 | |||
5129 | // Handle ObjectImage (TextureEntry) updates synchronously, since when updating multiple prim faces at once, | ||
5130 | // some clients will send out a separate ObjectImage packet for each face | ||
5131 | AddLocalPacketHandler(PacketType.ObjectImage, HandleObjectImage, false); | ||
5132 | |||
5133 | AddLocalPacketHandler(PacketType.ObjectGrab, HandleObjectGrab, false); | ||
5134 | AddLocalPacketHandler(PacketType.ObjectGrabUpdate, HandleObjectGrabUpdate, false); | ||
5135 | AddLocalPacketHandler(PacketType.ObjectDeGrab, HandleObjectDeGrab); | ||
5136 | AddLocalPacketHandler(PacketType.ObjectSpinStart, HandleObjectSpinStart, false); | ||
5137 | AddLocalPacketHandler(PacketType.ObjectSpinUpdate, HandleObjectSpinUpdate, false); | ||
5138 | AddLocalPacketHandler(PacketType.ObjectSpinStop, HandleObjectSpinStop, false); | ||
5139 | AddLocalPacketHandler(PacketType.ObjectDescription, HandleObjectDescription, false); | ||
5140 | AddLocalPacketHandler(PacketType.ObjectName, HandleObjectName, false); | ||
5141 | AddLocalPacketHandler(PacketType.ObjectPermissions, HandleObjectPermissions, false); | ||
5142 | AddLocalPacketHandler(PacketType.Undo, HandleUndo, false); | ||
5143 | AddLocalPacketHandler(PacketType.UndoLand, HandleLandUndo, false); | ||
5144 | AddLocalPacketHandler(PacketType.Redo, HandleRedo, false); | ||
5145 | AddLocalPacketHandler(PacketType.ObjectDuplicateOnRay, HandleObjectDuplicateOnRay); | ||
5146 | AddLocalPacketHandler(PacketType.RequestObjectPropertiesFamily, HandleRequestObjectPropertiesFamily, false); | ||
5147 | AddLocalPacketHandler(PacketType.ObjectIncludeInSearch, HandleObjectIncludeInSearch); | ||
5148 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); | ||
5149 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); | ||
5150 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); | ||
5151 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); | ||
5152 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); | ||
5153 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); | ||
5154 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); | ||
5155 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); | ||
5156 | AddLocalPacketHandler(PacketType.ConfirmXferPacket, HandleConfirmXferPacket); | ||
5157 | AddLocalPacketHandler(PacketType.AbortXfer, HandleAbortXfer); | ||
5158 | AddLocalPacketHandler(PacketType.CreateInventoryFolder, HandleCreateInventoryFolder); | ||
5159 | AddLocalPacketHandler(PacketType.UpdateInventoryFolder, HandleUpdateInventoryFolder); | ||
5160 | AddLocalPacketHandler(PacketType.MoveInventoryFolder, HandleMoveInventoryFolder); | ||
5161 | AddLocalPacketHandler(PacketType.CreateInventoryItem, HandleCreateInventoryItem); | ||
5162 | AddLocalPacketHandler(PacketType.LinkInventoryItem, HandleLinkInventoryItem); | ||
5163 | AddLocalPacketHandler(PacketType.FetchInventory, HandleFetchInventory); | ||
5164 | AddLocalPacketHandler(PacketType.FetchInventoryDescendents, HandleFetchInventoryDescendents); | ||
5165 | AddLocalPacketHandler(PacketType.PurgeInventoryDescendents, HandlePurgeInventoryDescendents); | ||
5166 | AddLocalPacketHandler(PacketType.UpdateInventoryItem, HandleUpdateInventoryItem); | ||
5167 | AddLocalPacketHandler(PacketType.CopyInventoryItem, HandleCopyInventoryItem); | ||
5168 | AddLocalPacketHandler(PacketType.MoveInventoryItem, HandleMoveInventoryItem); | ||
5169 | AddLocalPacketHandler(PacketType.RemoveInventoryItem, HandleRemoveInventoryItem); | ||
5170 | AddLocalPacketHandler(PacketType.RemoveInventoryFolder, HandleRemoveInventoryFolder); | ||
5171 | AddLocalPacketHandler(PacketType.RemoveInventoryObjects, HandleRemoveInventoryObjects); | ||
5172 | AddLocalPacketHandler(PacketType.RequestTaskInventory, HandleRequestTaskInventory); | ||
5173 | AddLocalPacketHandler(PacketType.UpdateTaskInventory, HandleUpdateTaskInventory); | ||
5174 | AddLocalPacketHandler(PacketType.RemoveTaskInventory, HandleRemoveTaskInventory); | ||
5175 | AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory); | ||
5176 | AddLocalPacketHandler(PacketType.RezScript, HandleRezScript); | ||
5177 | AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest, false); | ||
5178 | AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest, false); | ||
5179 | AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest, false); | ||
5180 | AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest); | ||
5181 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); | ||
5182 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); | ||
5183 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); | ||
5184 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); | ||
5185 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); | ||
5186 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); | ||
5187 | AddLocalPacketHandler(PacketType.ParcelPropertiesRequest, HandleParcelPropertiesRequest, false); | ||
5188 | AddLocalPacketHandler(PacketType.ParcelDivide, HandleParcelDivide); | ||
5189 | AddLocalPacketHandler(PacketType.ParcelJoin, HandleParcelJoin); | ||
5190 | AddLocalPacketHandler(PacketType.ParcelPropertiesUpdate, HandleParcelPropertiesUpdate); | ||
5191 | AddLocalPacketHandler(PacketType.ParcelSelectObjects, HandleParcelSelectObjects); | ||
5192 | AddLocalPacketHandler(PacketType.ParcelObjectOwnersRequest, HandleParcelObjectOwnersRequest); | ||
5193 | AddLocalPacketHandler(PacketType.ParcelGodForceOwner, HandleParcelGodForceOwner); | ||
5194 | AddLocalPacketHandler(PacketType.ParcelRelease, HandleParcelRelease); | ||
5195 | AddLocalPacketHandler(PacketType.ParcelReclaim, HandleParcelReclaim); | ||
5196 | AddLocalPacketHandler(PacketType.ParcelReturnObjects, HandleParcelReturnObjects); | ||
5197 | AddLocalPacketHandler(PacketType.ParcelSetOtherCleanTime, HandleParcelSetOtherCleanTime); | ||
5198 | AddLocalPacketHandler(PacketType.LandStatRequest, HandleLandStatRequest); | ||
5199 | AddLocalPacketHandler(PacketType.ParcelDwellRequest, HandleParcelDwellRequest); | ||
5200 | AddLocalPacketHandler(PacketType.EstateOwnerMessage, HandleEstateOwnerMessage); | ||
5201 | AddLocalPacketHandler(PacketType.RequestRegionInfo, HandleRequestRegionInfo, false); | ||
5202 | AddLocalPacketHandler(PacketType.EstateCovenantRequest, HandleEstateCovenantRequest); | ||
5203 | AddLocalPacketHandler(PacketType.RequestGodlikePowers, HandleRequestGodlikePowers); | ||
5204 | AddLocalPacketHandler(PacketType.GodKickUser, HandleGodKickUser); | ||
5205 | AddLocalPacketHandler(PacketType.MoneyBalanceRequest, HandleMoneyBalanceRequest); | ||
5206 | AddLocalPacketHandler(PacketType.EconomyDataRequest, HandleEconomyDataRequest); | ||
5207 | AddLocalPacketHandler(PacketType.RequestPayPrice, HandleRequestPayPrice); | ||
5208 | AddLocalPacketHandler(PacketType.ObjectSaleInfo, HandleObjectSaleInfo); | ||
5209 | AddLocalPacketHandler(PacketType.ObjectBuy, HandleObjectBuy); | ||
5210 | AddLocalPacketHandler(PacketType.GetScriptRunning, HandleGetScriptRunning); | ||
5211 | AddLocalPacketHandler(PacketType.SetScriptRunning, HandleSetScriptRunning); | ||
5212 | AddLocalPacketHandler(PacketType.ScriptReset, HandleScriptReset); | ||
5213 | AddLocalPacketHandler(PacketType.ActivateGestures, HandleActivateGestures); | ||
5214 | AddLocalPacketHandler(PacketType.DeactivateGestures, HandleDeactivateGestures); | ||
5215 | AddLocalPacketHandler(PacketType.ObjectOwner, HandleObjectOwner); | ||
5216 | AddLocalPacketHandler(PacketType.AgentFOV, HandleAgentFOV, false); | ||
5217 | AddLocalPacketHandler(PacketType.ViewerStats, HandleViewerStats); | ||
5218 | AddLocalPacketHandler(PacketType.MapItemRequest, HandleMapItemRequest, false); | ||
5219 | AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); | ||
5220 | AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); | ||
5221 | AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); | ||
5222 | AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments); | ||
5223 | AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); | ||
5224 | AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); | ||
5225 | AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); | ||
5226 | AddLocalPacketHandler(PacketType.DirFindQuery, HandleDirFindQuery); | ||
5227 | AddLocalPacketHandler(PacketType.DirLandQuery, HandleDirLandQuery); | ||
5228 | AddLocalPacketHandler(PacketType.DirPopularQuery, HandleDirPopularQuery); | ||
5229 | AddLocalPacketHandler(PacketType.DirClassifiedQuery, HandleDirClassifiedQuery); | ||
5230 | AddLocalPacketHandler(PacketType.EventInfoRequest, HandleEventInfoRequest); | ||
5231 | AddLocalPacketHandler(PacketType.OfferCallingCard, HandleOfferCallingCard); | ||
5232 | AddLocalPacketHandler(PacketType.AcceptCallingCard, HandleAcceptCallingCard); | ||
5233 | AddLocalPacketHandler(PacketType.DeclineCallingCard, HandleDeclineCallingCard); | ||
5234 | AddLocalPacketHandler(PacketType.ActivateGroup, HandleActivateGroup); | ||
5235 | AddLocalPacketHandler(PacketType.GroupTitlesRequest, HandleGroupTitlesRequest); | ||
5236 | AddLocalPacketHandler(PacketType.GroupProfileRequest, HandleGroupProfileRequest); | ||
5237 | AddLocalPacketHandler(PacketType.GroupMembersRequest, HandleGroupMembersRequest); | ||
5238 | AddLocalPacketHandler(PacketType.GroupRoleDataRequest, HandleGroupRoleDataRequest); | ||
5239 | AddLocalPacketHandler(PacketType.GroupRoleMembersRequest, HandleGroupRoleMembersRequest); | ||
5240 | AddLocalPacketHandler(PacketType.CreateGroupRequest, HandleCreateGroupRequest); | ||
5241 | AddLocalPacketHandler(PacketType.UpdateGroupInfo, HandleUpdateGroupInfo); | ||
5242 | AddLocalPacketHandler(PacketType.SetGroupAcceptNotices, HandleSetGroupAcceptNotices); | ||
5243 | AddLocalPacketHandler(PacketType.GroupTitleUpdate, HandleGroupTitleUpdate); | ||
5244 | AddLocalPacketHandler(PacketType.ParcelDeedToGroup, HandleParcelDeedToGroup); | ||
5245 | AddLocalPacketHandler(PacketType.GroupNoticesListRequest, HandleGroupNoticesListRequest); | ||
5246 | AddLocalPacketHandler(PacketType.GroupNoticeRequest, HandleGroupNoticeRequest); | ||
5247 | AddLocalPacketHandler(PacketType.GroupRoleUpdate, HandleGroupRoleUpdate); | ||
5248 | AddLocalPacketHandler(PacketType.GroupRoleChanges, HandleGroupRoleChanges); | ||
5249 | AddLocalPacketHandler(PacketType.JoinGroupRequest, HandleJoinGroupRequest); | ||
5250 | AddLocalPacketHandler(PacketType.LeaveGroupRequest, HandleLeaveGroupRequest); | ||
5251 | AddLocalPacketHandler(PacketType.EjectGroupMemberRequest, HandleEjectGroupMemberRequest); | ||
5252 | AddLocalPacketHandler(PacketType.InviteGroupRequest, HandleInviteGroupRequest); | ||
5253 | AddLocalPacketHandler(PacketType.StartLure, HandleStartLure); | ||
5254 | AddLocalPacketHandler(PacketType.TeleportLureRequest, HandleTeleportLureRequest); | ||
5255 | AddLocalPacketHandler(PacketType.ClassifiedInfoRequest, HandleClassifiedInfoRequest); | ||
5256 | AddLocalPacketHandler(PacketType.ClassifiedInfoUpdate, HandleClassifiedInfoUpdate); | ||
5257 | AddLocalPacketHandler(PacketType.ClassifiedDelete, HandleClassifiedDelete); | ||
5258 | AddLocalPacketHandler(PacketType.ClassifiedGodDelete, HandleClassifiedGodDelete); | ||
5259 | AddLocalPacketHandler(PacketType.EventGodDelete, HandleEventGodDelete); | ||
5260 | AddLocalPacketHandler(PacketType.EventNotificationAddRequest, HandleEventNotificationAddRequest); | ||
5261 | AddLocalPacketHandler(PacketType.EventNotificationRemoveRequest, HandleEventNotificationRemoveRequest); | ||
5262 | AddLocalPacketHandler(PacketType.RetrieveInstantMessages, HandleRetrieveInstantMessages); | ||
5263 | AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); | ||
5264 | AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); | ||
5265 | AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); | ||
5266 | AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate); | ||
5267 | AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate); | ||
5268 | AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); | ||
5269 | AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); | ||
5270 | AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); | ||
5271 | AddLocalPacketHandler(PacketType.RemoveMuteListEntry, HandleRemoveMuteListEntry); | ||
5272 | AddLocalPacketHandler(PacketType.UserReport, HandleUserReport); | ||
5273 | AddLocalPacketHandler(PacketType.FindAgent, HandleFindAgent); | ||
5274 | AddLocalPacketHandler(PacketType.TrackAgent, HandleTrackAgent); | ||
5275 | AddLocalPacketHandler(PacketType.GodUpdateRegionInfo, HandleGodUpdateRegionInfoUpdate); | ||
5276 | AddLocalPacketHandler(PacketType.GodlikeMessage, HandleGodlikeMessage); | ||
5277 | AddLocalPacketHandler(PacketType.StateSave, HandleSaveStatePacket); | ||
5278 | AddLocalPacketHandler(PacketType.GroupAccountDetailsRequest, HandleGroupAccountDetailsRequest); | ||
5279 | AddLocalPacketHandler(PacketType.GroupAccountSummaryRequest, HandleGroupAccountSummaryRequest); | ||
5280 | AddLocalPacketHandler(PacketType.GroupAccountTransactionsRequest, HandleGroupTransactionsDetailsRequest); | ||
5281 | AddLocalPacketHandler(PacketType.FreezeUser, HandleFreezeUser); | ||
5282 | AddLocalPacketHandler(PacketType.EjectUser, HandleEjectUser); | ||
5283 | AddLocalPacketHandler(PacketType.ParcelBuyPass, HandleParcelBuyPass); | ||
5284 | AddLocalPacketHandler(PacketType.ParcelGodMarkAsContent, HandleParcelGodMarkAsContent); | ||
5285 | AddLocalPacketHandler(PacketType.GroupActiveProposalsRequest, HandleGroupActiveProposalsRequest); | ||
5286 | AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); | ||
5287 | AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); | ||
5288 | AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); | ||
5289 | } | ||
5290 | |||
5291 | #region Packet Handlers | ||
5292 | |||
5293 | #region Scene/Avatar | ||
5294 | |||
5295 | private bool HandleAgentUpdate(IClientAPI sener, Packet Pack) | ||
5296 | { | ||
5297 | if (OnAgentUpdate != null) | ||
5298 | { | ||
5299 | bool update = false; | ||
5300 | AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack; | ||
5301 | |||
5302 | #region Packet Session and User Check | ||
5303 | if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId) | ||
5304 | return false; | ||
5305 | #endregion | ||
5306 | |||
5307 | AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData; | ||
5308 | |||
5309 | // We can only check when we have something to check | ||
5310 | // against. | ||
5311 | |||
5312 | if (lastarg != null) | ||
5313 | { | ||
5314 | update = | ||
5315 | ( | ||
5316 | (x.BodyRotation != lastarg.BodyRotation) || | ||
5317 | (x.CameraAtAxis != lastarg.CameraAtAxis) || | ||
5318 | (x.CameraCenter != lastarg.CameraCenter) || | ||
5319 | (x.CameraLeftAxis != lastarg.CameraLeftAxis) || | ||
5320 | (x.CameraUpAxis != lastarg.CameraUpAxis) || | ||
5321 | (x.ControlFlags != lastarg.ControlFlags) || | ||
5322 | (x.ControlFlags != 0) || | ||
5323 | (x.Far != lastarg.Far) || | ||
5324 | (x.Flags != lastarg.Flags) || | ||
5325 | (x.State != lastarg.State) || | ||
5326 | (x.HeadRotation != lastarg.HeadRotation) || | ||
5327 | (x.SessionID != lastarg.SessionID) || | ||
5328 | (x.AgentID != lastarg.AgentID) | ||
5329 | ); | ||
5330 | } | ||
5331 | else | ||
5332 | update = true; | ||
5333 | |||
5334 | // These should be ordered from most-likely to | ||
5335 | // least likely to change. I've made an initial | ||
5336 | // guess at that. | ||
5337 | |||
5338 | if (update) | ||
5339 | { | ||
5340 | AgentUpdateArgs arg = new AgentUpdateArgs(); | ||
5341 | arg.AgentID = x.AgentID; | ||
5342 | arg.BodyRotation = x.BodyRotation; | ||
5343 | arg.CameraAtAxis = x.CameraAtAxis; | ||
5344 | arg.CameraCenter = x.CameraCenter; | ||
5345 | arg.CameraLeftAxis = x.CameraLeftAxis; | ||
5346 | arg.CameraUpAxis = x.CameraUpAxis; | ||
5347 | arg.ControlFlags = x.ControlFlags; | ||
5348 | arg.Far = x.Far; | ||
5349 | arg.Flags = x.Flags; | ||
5350 | arg.HeadRotation = x.HeadRotation; | ||
5351 | arg.SessionID = x.SessionID; | ||
5352 | arg.State = x.State; | ||
5353 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | ||
5354 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | ||
5355 | lastarg = arg; // save this set of arguments for nexttime | ||
5356 | if (handlerPreAgentUpdate != null) | ||
5357 | OnPreAgentUpdate(this, arg); | ||
5358 | if (handlerAgentUpdate != null) | ||
5359 | OnAgentUpdate(this, arg); | ||
5360 | |||
5361 | handlerAgentUpdate = null; | ||
5362 | handlerPreAgentUpdate = null; | ||
5363 | } | ||
5364 | } | ||
5365 | |||
5366 | return true; | ||
5367 | } | ||
5368 | |||
5369 | private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack) | ||
5370 | { | ||
5371 | MoneyTransferRequestPacket money = (MoneyTransferRequestPacket)Pack; | ||
5372 | // validate the agent owns the agentID and sessionID | ||
5373 | if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId && | ||
5374 | money.AgentData.SessionID == sender.SessionId) | ||
5375 | { | ||
5376 | MoneyTransferRequest handlerMoneyTransferRequest = OnMoneyTransferRequest; | ||
5377 | if (handlerMoneyTransferRequest != null) | ||
5378 | { | ||
5379 | handlerMoneyTransferRequest(money.MoneyData.SourceID, money.MoneyData.DestID, | ||
5380 | money.MoneyData.Amount, money.MoneyData.TransactionType, | ||
5381 | Util.FieldToString(money.MoneyData.Description)); | ||
5382 | } | ||
5383 | |||
5384 | return true; | ||
5385 | } | ||
5386 | |||
5387 | return false; | ||
5388 | } | ||
5389 | |||
5390 | private bool HandleParcelGodMarkAsContent(IClientAPI client, Packet Packet) | ||
5391 | { | ||
5392 | ParcelGodMarkAsContentPacket ParcelGodMarkAsContent = | ||
5393 | (ParcelGodMarkAsContentPacket)Packet; | ||
5394 | |||
5395 | ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark; | ||
5396 | if (ParcelGodMarkAsContentHandler != null) | ||
5397 | { | ||
5398 | ParcelGodMarkAsContentHandler(this, | ||
5399 | ParcelGodMarkAsContent.AgentData.AgentID, | ||
5400 | ParcelGodMarkAsContent.ParcelData.LocalID); | ||
5401 | return true; | ||
5402 | } | ||
5403 | return false; | ||
5404 | } | ||
5405 | |||
5406 | private bool HandleFreezeUser(IClientAPI client, Packet Packet) | ||
5407 | { | ||
5408 | FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet; | ||
5409 | |||
5410 | FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser; | ||
5411 | if (FreezeUserHandler != null) | ||
5412 | { | ||
5413 | FreezeUserHandler(this, | ||
5414 | FreezeUser.AgentData.AgentID, | ||
5415 | FreezeUser.Data.Flags, | ||
5416 | FreezeUser.Data.TargetID); | ||
5417 | return true; | ||
5418 | } | ||
5419 | return false; | ||
5420 | } | ||
5421 | |||
5422 | private bool HandleEjectUser(IClientAPI client, Packet Packet) | ||
5423 | { | ||
5424 | EjectUserPacket EjectUser = | ||
5425 | (EjectUserPacket)Packet; | ||
5426 | |||
5427 | EjectUserUpdate EjectUserHandler = OnParcelEjectUser; | ||
5428 | if (EjectUserHandler != null) | ||
5429 | { | ||
5430 | EjectUserHandler(this, | ||
5431 | EjectUser.AgentData.AgentID, | ||
5432 | EjectUser.Data.Flags, | ||
5433 | EjectUser.Data.TargetID); | ||
5434 | return true; | ||
5435 | } | ||
5436 | return false; | ||
5437 | } | ||
5438 | |||
5439 | private bool HandleParcelBuyPass(IClientAPI client, Packet Packet) | ||
5440 | { | ||
5441 | ParcelBuyPassPacket ParcelBuyPass = | ||
5442 | (ParcelBuyPassPacket)Packet; | ||
5443 | |||
5444 | ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass; | ||
5445 | if (ParcelBuyPassHandler != null) | ||
5446 | { | ||
5447 | ParcelBuyPassHandler(this, | ||
5448 | ParcelBuyPass.AgentData.AgentID, | ||
5449 | ParcelBuyPass.ParcelData.LocalID); | ||
5450 | return true; | ||
5451 | } | ||
5452 | return false; | ||
5453 | } | ||
5454 | |||
5455 | private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) | ||
5456 | { | ||
5457 | ParcelBuyPacket parcel = (ParcelBuyPacket)Pack; | ||
5458 | if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == SessionId) | ||
5459 | { | ||
5460 | ParcelBuy handlerParcelBuy = OnParcelBuy; | ||
5461 | if (handlerParcelBuy != null) | ||
5462 | { | ||
5463 | handlerParcelBuy(parcel.AgentData.AgentID, parcel.Data.GroupID, parcel.Data.Final, | ||
5464 | parcel.Data.IsGroupOwned, | ||
5465 | parcel.Data.RemoveContribution, parcel.Data.LocalID, parcel.ParcelData.Area, | ||
5466 | parcel.ParcelData.Price, | ||
5467 | false); | ||
5468 | } | ||
5469 | return true; | ||
5470 | } | ||
5471 | return false; | ||
5472 | } | ||
5473 | |||
5474 | private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) | ||
5475 | { | ||
5476 | UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; | ||
5477 | |||
5478 | |||
5479 | for (int i = 0; i < upack.UUIDNameBlock.Length; i++) | ||
5480 | { | ||
5481 | UUIDNameRequest handlerUUIDGroupNameRequest = OnUUIDGroupNameRequest; | ||
5482 | if (handlerUUIDGroupNameRequest != null) | ||
5483 | { | ||
5484 | handlerUUIDGroupNameRequest(upack.UUIDNameBlock[i].ID, this); | ||
5485 | } | ||
5486 | } | ||
5487 | |||
5488 | return true; | ||
5489 | } | ||
5490 | |||
5491 | public bool HandleGenericMessage(IClientAPI sender, Packet pack) | ||
5492 | { | ||
5493 | GenericMessagePacket gmpack = (GenericMessagePacket)pack; | ||
5494 | if (m_genericPacketHandlers.Count == 0) return false; | ||
5495 | if (gmpack.AgentData.SessionID != SessionId) return false; | ||
5496 | |||
5497 | GenericMessage handlerGenericMessage = null; | ||
5498 | |||
5499 | string method = Util.FieldToString(gmpack.MethodData.Method).ToLower().Trim(); | ||
5500 | |||
5501 | if (m_genericPacketHandlers.TryGetValue(method, out handlerGenericMessage)) | ||
5502 | { | ||
5503 | List<string> msg = new List<string>(); | ||
5504 | List<byte[]> msgBytes = new List<byte[]>(); | ||
5505 | |||
5506 | if (handlerGenericMessage != null) | ||
5507 | { | ||
5508 | foreach (GenericMessagePacket.ParamListBlock block in gmpack.ParamList) | ||
5509 | { | ||
5510 | msg.Add(Util.FieldToString(block.Parameter)); | ||
5511 | msgBytes.Add(block.Parameter); | ||
5512 | } | ||
5513 | try | ||
5514 | { | ||
5515 | if (OnBinaryGenericMessage != null) | ||
5516 | { | ||
5517 | OnBinaryGenericMessage(this, method, msgBytes.ToArray()); | ||
5518 | } | ||
5519 | handlerGenericMessage(sender, method, msg); | ||
5520 | return true; | ||
5521 | } | ||
5522 | catch (Exception e) | ||
5523 | { | ||
5524 | m_log.ErrorFormat( | ||
5525 | "[LLCLIENTVIEW]: Exeception when handling generic message {0}{1}", e.Message, e.StackTrace); | ||
5526 | } | ||
5527 | } | ||
5528 | } | ||
5529 | |||
5530 | //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method); | ||
5531 | return false; | ||
5532 | } | ||
5533 | |||
5534 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) | ||
5535 | { | ||
5536 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; | ||
5537 | if (ogpack.AgentData.SessionID != SessionId) return false; | ||
5538 | |||
5539 | RequestObjectPropertiesFamily handlerObjectGroupRequest = OnObjectGroupRequest; | ||
5540 | if (handlerObjectGroupRequest != null) | ||
5541 | { | ||
5542 | for (int i = 0; i < ogpack.ObjectData.Length; i++) | ||
5543 | { | ||
5544 | handlerObjectGroupRequest(this, ogpack.AgentData.GroupID, ogpack.ObjectData[i].ObjectLocalID, UUID.Zero); | ||
5545 | } | ||
5546 | } | ||
5547 | return true; | ||
5548 | } | ||
5549 | |||
5550 | private bool HandleViewerEffect(IClientAPI sender, Packet Pack) | ||
5551 | { | ||
5552 | ViewerEffectPacket viewer = (ViewerEffectPacket)Pack; | ||
5553 | if (viewer.AgentData.SessionID != SessionId) return false; | ||
5554 | ViewerEffectEventHandler handlerViewerEffect = OnViewerEffect; | ||
5555 | if (handlerViewerEffect != null) | ||
5556 | { | ||
5557 | int length = viewer.Effect.Length; | ||
5558 | List<ViewerEffectEventHandlerArg> args = new List<ViewerEffectEventHandlerArg>(length); | ||
5559 | for (int i = 0; i < length; i++) | ||
5560 | { | ||
5561 | //copy the effects block arguments into the event handler arg. | ||
5562 | ViewerEffectEventHandlerArg argument = new ViewerEffectEventHandlerArg(); | ||
5563 | argument.AgentID = viewer.Effect[i].AgentID; | ||
5564 | argument.Color = viewer.Effect[i].Color; | ||
5565 | argument.Duration = viewer.Effect[i].Duration; | ||
5566 | argument.ID = viewer.Effect[i].ID; | ||
5567 | argument.Type = viewer.Effect[i].Type; | ||
5568 | argument.TypeData = viewer.Effect[i].TypeData; | ||
5569 | args.Add(argument); | ||
5570 | } | ||
5571 | |||
5572 | handlerViewerEffect(sender, args); | ||
5573 | } | ||
5574 | |||
5575 | return true; | ||
5576 | } | ||
5577 | |||
5578 | private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) | ||
5579 | { | ||
5580 | AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; | ||
5581 | |||
5582 | #region Packet Session and User Check | ||
5583 | if (m_checkPackets) | ||
5584 | { | ||
5585 | if (avatarProperties.AgentData.SessionID != SessionId || | ||
5586 | avatarProperties.AgentData.AgentID != AgentId) | ||
5587 | return true; | ||
5588 | } | ||
5589 | #endregion | ||
5590 | |||
5591 | RequestAvatarProperties handlerRequestAvatarProperties = OnRequestAvatarProperties; | ||
5592 | if (handlerRequestAvatarProperties != null) | ||
5593 | { | ||
5594 | handlerRequestAvatarProperties(this, avatarProperties.AgentData.AvatarID); | ||
5595 | } | ||
5596 | return true; | ||
5597 | } | ||
5598 | |||
5599 | private bool HandleChatFromViewer(IClientAPI sender, Packet Pack) | ||
5600 | { | ||
5601 | ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack; | ||
5602 | |||
5603 | #region Packet Session and User Check | ||
5604 | if (m_checkPackets) | ||
5605 | { | ||
5606 | if (inchatpack.AgentData.SessionID != SessionId || | ||
5607 | inchatpack.AgentData.AgentID != AgentId) | ||
5608 | return true; | ||
5609 | } | ||
5610 | #endregion | ||
5611 | |||
5612 | string fromName = String.Empty; //ClientAvatar.firstname + " " + ClientAvatar.lastname; | ||
5613 | byte[] message = inchatpack.ChatData.Message; | ||
5614 | byte type = inchatpack.ChatData.Type; | ||
5615 | Vector3 fromPos = new Vector3(); // ClientAvatar.Pos; | ||
5616 | // UUID fromAgentID = AgentId; | ||
5617 | |||
5618 | int channel = inchatpack.ChatData.Channel; | ||
5619 | |||
5620 | if (OnChatFromClient != null) | ||
5621 | { | ||
5622 | OSChatMessage args = new OSChatMessage(); | ||
5623 | args.Channel = channel; | ||
5624 | args.From = fromName; | ||
5625 | args.Message = Utils.BytesToString(message); | ||
5626 | args.Type = (ChatTypeEnum)type; | ||
5627 | args.Position = fromPos; | ||
5628 | |||
5629 | args.Scene = Scene; | ||
5630 | args.Sender = this; | ||
5631 | args.SenderUUID = this.AgentId; | ||
5632 | |||
5633 | ChatMessage handlerChatFromClient = OnChatFromClient; | ||
5634 | if (handlerChatFromClient != null) | ||
5635 | handlerChatFromClient(this, args); | ||
5636 | } | ||
5637 | return true; | ||
5638 | } | ||
5639 | |||
5640 | private bool HandlerAvatarPropertiesUpdate(IClientAPI sender, Packet Pack) | ||
5641 | { | ||
5642 | AvatarPropertiesUpdatePacket avatarProps = (AvatarPropertiesUpdatePacket)Pack; | ||
5643 | |||
5644 | #region Packet Session and User Check | ||
5645 | if (m_checkPackets) | ||
5646 | { | ||
5647 | if (avatarProps.AgentData.SessionID != SessionId || | ||
5648 | avatarProps.AgentData.AgentID != AgentId) | ||
5649 | return true; | ||
5650 | } | ||
5651 | #endregion | ||
5652 | |||
5653 | UpdateAvatarProperties handlerUpdateAvatarProperties = OnUpdateAvatarProperties; | ||
5654 | if (handlerUpdateAvatarProperties != null) | ||
5655 | { | ||
5656 | AvatarPropertiesUpdatePacket.PropertiesDataBlock Properties = avatarProps.PropertiesData; | ||
5657 | UserProfileData UserProfile = new UserProfileData(); | ||
5658 | UserProfile.ID = AgentId; | ||
5659 | UserProfile.AboutText = Utils.BytesToString(Properties.AboutText); | ||
5660 | UserProfile.FirstLifeAboutText = Utils.BytesToString(Properties.FLAboutText); | ||
5661 | UserProfile.FirstLifeImage = Properties.FLImageID; | ||
5662 | UserProfile.Image = Properties.ImageID; | ||
5663 | UserProfile.ProfileUrl = Utils.BytesToString(Properties.ProfileURL); | ||
5664 | UserProfile.UserFlags &= ~3; | ||
5665 | UserProfile.UserFlags |= Properties.AllowPublish ? 1 : 0; | ||
5666 | UserProfile.UserFlags |= Properties.MaturePublish ? 2 : 0; | ||
5667 | |||
5668 | handlerUpdateAvatarProperties(this, UserProfile); | ||
5669 | } | ||
5670 | return true; | ||
5671 | } | ||
5672 | |||
5673 | private bool HandlerScriptDialogReply(IClientAPI sender, Packet Pack) | ||
5674 | { | ||
5675 | ScriptDialogReplyPacket rdialog = (ScriptDialogReplyPacket)Pack; | ||
5676 | |||
5677 | //m_log.DebugFormat("[CLIENT]: Received ScriptDialogReply from {0}", rdialog.Data.ObjectID); | ||
5678 | |||
5679 | #region Packet Session and User Check | ||
5680 | if (m_checkPackets) | ||
5681 | { | ||
5682 | if (rdialog.AgentData.SessionID != SessionId || | ||
5683 | rdialog.AgentData.AgentID != AgentId) | ||
5684 | return true; | ||
5685 | } | ||
5686 | #endregion | ||
5687 | |||
5688 | int ch = rdialog.Data.ChatChannel; | ||
5689 | byte[] msg = rdialog.Data.ButtonLabel; | ||
5690 | if (OnChatFromClient != null) | ||
5691 | { | ||
5692 | OSChatMessage args = new OSChatMessage(); | ||
5693 | args.Channel = ch; | ||
5694 | args.From = String.Empty; | ||
5695 | args.Message = Utils.BytesToString(msg); | ||
5696 | args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance | ||
5697 | args.Position = new Vector3(); | ||
5698 | args.Scene = Scene; | ||
5699 | args.Sender = this; | ||
5700 | ChatMessage handlerChatFromClient2 = OnChatFromClient; | ||
5701 | if (handlerChatFromClient2 != null) | ||
5702 | handlerChatFromClient2(this, args); | ||
5703 | } | ||
5704 | |||
5705 | return true; | ||
5706 | } | ||
5707 | |||
5708 | private bool HandlerImprovedInstantMessage(IClientAPI sender, Packet Pack) | ||
5709 | { | ||
5710 | ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack; | ||
5711 | |||
5712 | #region Packet Session and User Check | ||
5713 | if (m_checkPackets) | ||
5714 | { | ||
5715 | if (msgpack.AgentData.SessionID != SessionId || | ||
5716 | msgpack.AgentData.AgentID != AgentId) | ||
5717 | return true; | ||
5718 | } | ||
5719 | #endregion | ||
5720 | |||
5721 | string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName); | ||
5722 | string IMmessage = Utils.BytesToString(msgpack.MessageBlock.Message); | ||
5723 | ImprovedInstantMessage handlerInstantMessage = OnInstantMessage; | ||
5724 | |||
5725 | if (handlerInstantMessage != null) | ||
5726 | { | ||
5727 | GridInstantMessage im = new GridInstantMessage(Scene, | ||
5728 | msgpack.AgentData.AgentID, | ||
5729 | IMfromName, | ||
5730 | msgpack.MessageBlock.ToAgentID, | ||
5731 | msgpack.MessageBlock.Dialog, | ||
5732 | msgpack.MessageBlock.FromGroup, | ||
5733 | IMmessage, | ||
5734 | msgpack.MessageBlock.ID, | ||
5735 | msgpack.MessageBlock.Offline != 0 ? true : false, | ||
5736 | msgpack.MessageBlock.Position, | ||
5737 | msgpack.MessageBlock.BinaryBucket); | ||
5738 | |||
5739 | handlerInstantMessage(this, im); | ||
5740 | } | ||
5741 | return true; | ||
5742 | |||
5743 | } | ||
5744 | |||
5745 | private bool HandlerAcceptFriendship(IClientAPI sender, Packet Pack) | ||
5746 | { | ||
5747 | AcceptFriendshipPacket afriendpack = (AcceptFriendshipPacket)Pack; | ||
5748 | |||
5749 | #region Packet Session and User Check | ||
5750 | if (m_checkPackets) | ||
5751 | { | ||
5752 | if (afriendpack.AgentData.SessionID != SessionId || | ||
5753 | afriendpack.AgentData.AgentID != AgentId) | ||
5754 | return true; | ||
5755 | } | ||
5756 | #endregion | ||
5757 | |||
5758 | // My guess is this is the folder to stick the calling card into | ||
5759 | List<UUID> callingCardFolders = new List<UUID>(); | ||
5760 | |||
5761 | UUID agentID = afriendpack.AgentData.AgentID; | ||
5762 | UUID transactionID = afriendpack.TransactionBlock.TransactionID; | ||
5763 | |||
5764 | for (int fi = 0; fi < afriendpack.FolderData.Length; fi++) | ||
5765 | { | ||
5766 | callingCardFolders.Add(afriendpack.FolderData[fi].FolderID); | ||
5767 | } | ||
5768 | |||
5769 | FriendActionDelegate handlerApproveFriendRequest = OnApproveFriendRequest; | ||
5770 | if (handlerApproveFriendRequest != null) | ||
5771 | { | ||
5772 | handlerApproveFriendRequest(this, agentID, transactionID, callingCardFolders); | ||
5773 | } | ||
5774 | return true; | ||
5775 | |||
5776 | } | ||
5777 | |||
5778 | private bool HandlerDeclineFriendship(IClientAPI sender, Packet Pack) | ||
5779 | { | ||
5780 | DeclineFriendshipPacket dfriendpack = (DeclineFriendshipPacket)Pack; | ||
5781 | |||
5782 | #region Packet Session and User Check | ||
5783 | if (m_checkPackets) | ||
5784 | { | ||
5785 | if (dfriendpack.AgentData.SessionID != SessionId || | ||
5786 | dfriendpack.AgentData.AgentID != AgentId) | ||
5787 | return true; | ||
5788 | } | ||
5789 | #endregion | ||
5790 | |||
5791 | if (OnDenyFriendRequest != null) | ||
5792 | { | ||
5793 | OnDenyFriendRequest(this, | ||
5794 | dfriendpack.AgentData.AgentID, | ||
5795 | dfriendpack.TransactionBlock.TransactionID, | ||
5796 | null); | ||
5797 | } | ||
5798 | return true; | ||
5799 | } | ||
5800 | |||
5801 | private bool HandlerTerminateFrendship(IClientAPI sender, Packet Pack) | ||
5802 | { | ||
5803 | TerminateFriendshipPacket tfriendpack = (TerminateFriendshipPacket)Pack; | ||
5804 | |||
5805 | #region Packet Session and User Check | ||
5806 | if (m_checkPackets) | ||
5807 | { | ||
5808 | if (tfriendpack.AgentData.SessionID != SessionId || | ||
5809 | tfriendpack.AgentData.AgentID != AgentId) | ||
5810 | return true; | ||
5811 | } | ||
5812 | #endregion | ||
5813 | |||
5814 | UUID listOwnerAgentID = tfriendpack.AgentData.AgentID; | ||
5815 | UUID exFriendID = tfriendpack.ExBlock.OtherID; | ||
5816 | |||
5817 | FriendshipTermination handlerTerminateFriendship = OnTerminateFriendship; | ||
5818 | if (handlerTerminateFriendship != null) | ||
5819 | { | ||
5820 | handlerTerminateFriendship(this, listOwnerAgentID, exFriendID); | ||
5821 | } | ||
5822 | return true; | ||
5823 | } | ||
5824 | |||
5825 | private bool HandleFindAgent(IClientAPI client, Packet Packet) | ||
5826 | { | ||
5827 | FindAgentPacket FindAgent = | ||
5828 | (FindAgentPacket)Packet; | ||
5829 | |||
5830 | FindAgentUpdate FindAgentHandler = OnFindAgent; | ||
5831 | if (FindAgentHandler != null) | ||
5832 | { | ||
5833 | FindAgentHandler(this,FindAgent.AgentBlock.Hunter,FindAgent.AgentBlock.Prey); | ||
5834 | return true; | ||
5835 | } | ||
5836 | return false; | ||
5837 | } | ||
5838 | |||
5839 | private bool HandleTrackAgent(IClientAPI client, Packet Packet) | ||
5840 | { | ||
5841 | TrackAgentPacket TrackAgent = | ||
5842 | (TrackAgentPacket)Packet; | ||
5843 | |||
5844 | TrackAgentUpdate TrackAgentHandler = OnTrackAgent; | ||
5845 | if (TrackAgentHandler != null) | ||
5846 | { | ||
5847 | TrackAgentHandler(this, | ||
5848 | TrackAgent.AgentData.AgentID, | ||
5849 | TrackAgent.TargetData.PreyID); | ||
5850 | return true; | ||
5851 | } | ||
5852 | return false; | ||
5853 | } | ||
5854 | |||
5855 | private bool HandlerRezObject(IClientAPI sender, Packet Pack) | ||
5856 | { | ||
5857 | RezObjectPacket rezPacket = (RezObjectPacket)Pack; | ||
5858 | |||
5859 | #region Packet Session and User Check | ||
5860 | if (m_checkPackets) | ||
5861 | { | ||
5862 | if (rezPacket.AgentData.SessionID != SessionId || | ||
5863 | rezPacket.AgentData.AgentID != AgentId) | ||
5864 | return true; | ||
5865 | } | ||
5866 | #endregion | ||
5867 | |||
5868 | RezObject handlerRezObject = OnRezObject; | ||
5869 | if (handlerRezObject != null) | ||
5870 | { | ||
5871 | handlerRezObject(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd, | ||
5872 | rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID, | ||
5873 | rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection, | ||
5874 | rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem, | ||
5875 | rezPacket.RezData.FromTaskID); | ||
5876 | } | ||
5877 | return true; | ||
5878 | } | ||
5879 | |||
5880 | private bool HandlerDeRezObject(IClientAPI sender, Packet Pack) | ||
5881 | { | ||
5882 | DeRezObjectPacket DeRezPacket = (DeRezObjectPacket)Pack; | ||
5883 | |||
5884 | #region Packet Session and User Check | ||
5885 | if (m_checkPackets) | ||
5886 | { | ||
5887 | if (DeRezPacket.AgentData.SessionID != SessionId || | ||
5888 | DeRezPacket.AgentData.AgentID != AgentId) | ||
5889 | return true; | ||
5890 | } | ||
5891 | #endregion | ||
5892 | |||
5893 | DeRezObject handlerDeRezObject = OnDeRezObject; | ||
5894 | if (handlerDeRezObject != null) | ||
5895 | { | ||
5896 | List<uint> deRezIDs = new List<uint>(); | ||
5897 | |||
5898 | foreach (DeRezObjectPacket.ObjectDataBlock data in | ||
5899 | DeRezPacket.ObjectData) | ||
5900 | { | ||
5901 | deRezIDs.Add(data.ObjectLocalID); | ||
5902 | } | ||
5903 | // It just so happens that the values on the DeRezAction enumerator match the Destination | ||
5904 | // values given by a Second Life client | ||
5905 | handlerDeRezObject(this, deRezIDs, | ||
5906 | DeRezPacket.AgentBlock.GroupID, | ||
5907 | (DeRezAction)DeRezPacket.AgentBlock.Destination, | ||
5908 | DeRezPacket.AgentBlock.DestinationID); | ||
5909 | |||
5910 | } | ||
5911 | return true; | ||
5912 | } | ||
5913 | |||
5914 | private bool HandlerModifyLand(IClientAPI sender, Packet Pack) | ||
5915 | { | ||
5916 | ModifyLandPacket modify = (ModifyLandPacket)Pack; | ||
5917 | |||
5918 | #region Packet Session and User Check | ||
5919 | if (m_checkPackets) | ||
5920 | { | ||
5921 | if (modify.AgentData.SessionID != SessionId || | ||
5922 | modify.AgentData.AgentID != AgentId) | ||
5923 | return true; | ||
5924 | } | ||
5925 | |||
5926 | #endregion | ||
5927 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); | ||
5928 | if (modify.ParcelData.Length > 0) | ||
5929 | { | ||
5930 | if (OnModifyTerrain != null) | ||
5931 | { | ||
5932 | for (int i = 0; i < modify.ParcelData.Length; i++) | ||
5933 | { | ||
5934 | ModifyTerrain handlerModifyTerrain = OnModifyTerrain; | ||
5935 | if (handlerModifyTerrain != null) | ||
5936 | { | ||
5937 | handlerModifyTerrain(AgentId, modify.ModifyBlock.Height, modify.ModifyBlock.Seconds, | ||
5938 | modify.ModifyBlock.BrushSize, | ||
5939 | modify.ModifyBlock.Action, modify.ParcelData[i].North, | ||
5940 | modify.ParcelData[i].West, modify.ParcelData[i].South, | ||
5941 | modify.ParcelData[i].East, AgentId); | ||
5942 | } | ||
5943 | } | ||
5944 | } | ||
5945 | } | ||
5946 | |||
5947 | return true; | ||
5948 | } | ||
5949 | |||
5950 | private bool HandlerRegionHandshakeReply(IClientAPI sender, Packet Pack) | ||
5951 | { | ||
5952 | Action<IClientAPI> handlerRegionHandShakeReply = OnRegionHandShakeReply; | ||
5953 | if (handlerRegionHandShakeReply != null) | ||
5954 | { | ||
5955 | handlerRegionHandShakeReply(this); | ||
5956 | } | ||
5957 | |||
5958 | return true; | ||
5959 | } | ||
5960 | |||
5961 | private bool HandlerAgentWearablesRequest(IClientAPI sender, Packet Pack) | ||
5962 | { | ||
5963 | GenericCall1 handlerRequestWearables = OnRequestWearables; | ||
5964 | |||
5965 | if (handlerRequestWearables != null) | ||
5966 | { | ||
5967 | handlerRequestWearables(sender); | ||
5968 | } | ||
5969 | |||
5970 | Action<IClientAPI> handlerRequestAvatarsData = OnRequestAvatarsData; | ||
5971 | |||
5972 | if (handlerRequestAvatarsData != null) | ||
5973 | { | ||
5974 | handlerRequestAvatarsData(this); | ||
5975 | } | ||
5976 | |||
5977 | return true; | ||
5978 | } | ||
5979 | |||
5980 | private bool HandlerAgentSetAppearance(IClientAPI sender, Packet Pack) | ||
5981 | { | ||
5982 | AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack; | ||
5983 | |||
5984 | #region Packet Session and User Check | ||
5985 | if (m_checkPackets) | ||
5986 | { | ||
5987 | if (appear.AgentData.SessionID != SessionId || | ||
5988 | appear.AgentData.AgentID != AgentId) | ||
5989 | return true; | ||
5990 | } | ||
5991 | #endregion | ||
5992 | |||
5993 | SetAppearance handlerSetAppearance = OnSetAppearance; | ||
5994 | if (handlerSetAppearance != null) | ||
5995 | { | ||
5996 | // Temporarily protect ourselves from the mantis #951 failure. | ||
5997 | // However, we could do this for several other handlers where a failure isn't terminal | ||
5998 | // for the client session anyway, in order to protect ourselves against bad code in plugins | ||
5999 | try | ||
6000 | { | ||
6001 | |||
6002 | byte[] visualparams = new byte[appear.VisualParam.Length]; | ||
6003 | for (int i = 0; i < appear.VisualParam.Length; i++) | ||
6004 | visualparams[i] = appear.VisualParam[i].ParamValue; | ||
6005 | |||
6006 | Primitive.TextureEntry te = null; | ||
6007 | if (appear.ObjectData.TextureEntry.Length > 1) | ||
6008 | te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); | ||
6009 | |||
6010 | handlerSetAppearance(sender, te, visualparams); | ||
6011 | } | ||
6012 | catch (Exception e) | ||
6013 | { | ||
6014 | m_log.ErrorFormat( | ||
6015 | "[CLIENT VIEW]: AgentSetApperance packet handler threw an exception, {0}", | ||
6016 | e); | ||
6017 | } | ||
6018 | } | ||
6019 | |||
6020 | return true; | ||
6021 | } | ||
6022 | |||
6023 | private bool HandlerAgentIsNowWearing(IClientAPI sender, Packet Pack) | ||
6024 | { | ||
6025 | if (OnAvatarNowWearing != null) | ||
6026 | { | ||
6027 | AgentIsNowWearingPacket nowWearing = (AgentIsNowWearingPacket)Pack; | ||
6028 | |||
6029 | #region Packet Session and User Check | ||
6030 | if (m_checkPackets) | ||
6031 | { | ||
6032 | if (nowWearing.AgentData.SessionID != SessionId || | ||
6033 | nowWearing.AgentData.AgentID != AgentId) | ||
6034 | return true; | ||
6035 | } | ||
6036 | #endregion | ||
6037 | |||
6038 | AvatarWearingArgs wearingArgs = new AvatarWearingArgs(); | ||
6039 | for (int i = 0; i < nowWearing.WearableData.Length; i++) | ||
6040 | { | ||
6041 | m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID); | ||
6042 | AvatarWearingArgs.Wearable wearable = | ||
6043 | new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID, | ||
6044 | nowWearing.WearableData[i].WearableType); | ||
6045 | wearingArgs.NowWearing.Add(wearable); | ||
6046 | } | ||
6047 | |||
6048 | AvatarNowWearing handlerAvatarNowWearing = OnAvatarNowWearing; | ||
6049 | if (handlerAvatarNowWearing != null) | ||
6050 | { | ||
6051 | handlerAvatarNowWearing(this, wearingArgs); | ||
6052 | } | ||
6053 | } | ||
6054 | return true; | ||
6055 | } | ||
6056 | |||
6057 | private bool HandlerRezSingleAttachmentFromInv(IClientAPI sender, Packet Pack) | ||
6058 | { | ||
6059 | RezSingleAttachmentFromInv handlerRezSingleAttachment = OnRezSingleAttachmentFromInv; | ||
6060 | if (handlerRezSingleAttachment != null) | ||
6061 | { | ||
6062 | RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack; | ||
6063 | |||
6064 | #region Packet Session and User Check | ||
6065 | if (m_checkPackets) | ||
6066 | { | ||
6067 | if (rez.AgentData.SessionID != SessionId || | ||
6068 | rez.AgentData.AgentID != AgentId) | ||
6069 | return true; | ||
6070 | } | ||
6071 | #endregion | ||
6072 | |||
6073 | handlerRezSingleAttachment(this, rez.ObjectData.ItemID, | ||
6074 | rez.ObjectData.AttachmentPt); | ||
6075 | } | ||
6076 | |||
6077 | return true; | ||
6078 | } | ||
6079 | |||
6080 | private bool HandleRezMultipleAttachmentsFromInv(IClientAPI sender, Packet Pack) | ||
6081 | { | ||
6082 | RezMultipleAttachmentsFromInv handlerRezMultipleAttachments = OnRezMultipleAttachmentsFromInv; | ||
6083 | if (handlerRezMultipleAttachments != null) | ||
6084 | { | ||
6085 | RezMultipleAttachmentsFromInvPacket rez = (RezMultipleAttachmentsFromInvPacket)Pack; | ||
6086 | handlerRezMultipleAttachments(this, rez.HeaderData, | ||
6087 | rez.ObjectData); | ||
6088 | } | ||
6089 | |||
6090 | return true; | ||
6091 | } | ||
6092 | |||
6093 | private bool HandleDetachAttachmentIntoInv(IClientAPI sender, Packet Pack) | ||
6094 | { | ||
6095 | UUIDNameRequest handlerDetachAttachmentIntoInv = OnDetachAttachmentIntoInv; | ||
6096 | if (handlerDetachAttachmentIntoInv != null) | ||
6097 | { | ||
6098 | DetachAttachmentIntoInvPacket detachtoInv = (DetachAttachmentIntoInvPacket)Pack; | ||
6099 | |||
6100 | #region Packet Session and User Check | ||
6101 | // UNSUPPORTED ON THIS PACKET | ||
6102 | #endregion | ||
6103 | |||
6104 | UUID itemID = detachtoInv.ObjectData.ItemID; | ||
6105 | // UUID ATTACH_agentID = detachtoInv.ObjectData.AgentID; | ||
6106 | |||
6107 | handlerDetachAttachmentIntoInv(itemID, this); | ||
6108 | } | ||
6109 | return true; | ||
6110 | } | ||
6111 | |||
6112 | private bool HandleObjectAttach(IClientAPI sender, Packet Pack) | ||
6113 | { | ||
6114 | if (OnObjectAttach != null) | ||
6115 | { | ||
6116 | ObjectAttachPacket att = (ObjectAttachPacket)Pack; | ||
6117 | |||
6118 | #region Packet Session and User Check | ||
6119 | if (m_checkPackets) | ||
6120 | { | ||
6121 | if (att.AgentData.SessionID != SessionId || | ||
6122 | att.AgentData.AgentID != AgentId) | ||
6123 | return true; | ||
6124 | } | ||
6125 | #endregion | ||
6126 | |||
6127 | ObjectAttach handlerObjectAttach = OnObjectAttach; | ||
6128 | |||
6129 | if (handlerObjectAttach != null) | ||
6130 | { | ||
6131 | if (att.ObjectData.Length > 0) | ||
6132 | { | ||
6133 | handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, false); | ||
6134 | } | ||
6135 | } | ||
6136 | } | ||
6137 | return true; | ||
6138 | } | ||
6139 | |||
6140 | private bool HandleObjectDetach(IClientAPI sender, Packet Pack) | ||
6141 | { | ||
6142 | ObjectDetachPacket dett = (ObjectDetachPacket)Pack; | ||
6143 | |||
6144 | #region Packet Session and User Check | ||
6145 | if (m_checkPackets) | ||
6146 | { | ||
6147 | if (dett.AgentData.SessionID != SessionId || | ||
6148 | dett.AgentData.AgentID != AgentId) | ||
6149 | return true; | ||
6150 | } | ||
6151 | #endregion | ||
6152 | |||
6153 | for (int j = 0; j < dett.ObjectData.Length; j++) | ||
6154 | { | ||
6155 | uint obj = dett.ObjectData[j].ObjectLocalID; | ||
6156 | ObjectDeselect handlerObjectDetach = OnObjectDetach; | ||
6157 | if (handlerObjectDetach != null) | ||
6158 | { | ||
6159 | handlerObjectDetach(obj, this); | ||
6160 | } | ||
6161 | |||
6162 | } | ||
6163 | return true; | ||
6164 | } | ||
6165 | |||
6166 | private bool HandleObjectDrop(IClientAPI sender, Packet Pack) | ||
6167 | { | ||
6168 | ObjectDropPacket dropp = (ObjectDropPacket)Pack; | ||
6169 | |||
6170 | #region Packet Session and User Check | ||
6171 | if (m_checkPackets) | ||
6172 | { | ||
6173 | if (dropp.AgentData.SessionID != SessionId || | ||
6174 | dropp.AgentData.AgentID != AgentId) | ||
6175 | return true; | ||
6176 | } | ||
6177 | #endregion | ||
6178 | |||
6179 | for (int j = 0; j < dropp.ObjectData.Length; j++) | ||
6180 | { | ||
6181 | uint obj = dropp.ObjectData[j].ObjectLocalID; | ||
6182 | ObjectDrop handlerObjectDrop = OnObjectDrop; | ||
6183 | if (handlerObjectDrop != null) | ||
6184 | { | ||
6185 | handlerObjectDrop(obj, this); | ||
6186 | } | ||
6187 | } | ||
6188 | return true; | ||
6189 | } | ||
6190 | |||
6191 | private bool HandleSetAlwaysRun(IClientAPI sender, Packet Pack) | ||
6192 | { | ||
6193 | SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack; | ||
6194 | |||
6195 | #region Packet Session and User Check | ||
6196 | if (m_checkPackets) | ||
6197 | { | ||
6198 | if (run.AgentData.SessionID != SessionId || | ||
6199 | run.AgentData.AgentID != AgentId) | ||
6200 | return true; | ||
6201 | } | ||
6202 | #endregion | ||
6203 | |||
6204 | SetAlwaysRun handlerSetAlwaysRun = OnSetAlwaysRun; | ||
6205 | if (handlerSetAlwaysRun != null) | ||
6206 | handlerSetAlwaysRun(this, run.AgentData.AlwaysRun); | ||
6207 | |||
6208 | return true; | ||
6209 | } | ||
6210 | |||
6211 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) | ||
6212 | { | ||
6213 | GenericCall1 handlerCompleteMovementToRegion = OnCompleteMovementToRegion; | ||
6214 | if (handlerCompleteMovementToRegion != null) | ||
6215 | { | ||
6216 | handlerCompleteMovementToRegion(sender); | ||
6217 | } | ||
6218 | handlerCompleteMovementToRegion = null; | ||
6219 | |||
6220 | return true; | ||
6221 | } | ||
6222 | |||
6223 | private bool HandleAgentAnimation(IClientAPI sender, Packet Pack) | ||
6224 | { | ||
6225 | AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack; | ||
6226 | |||
6227 | #region Packet Session and User Check | ||
6228 | if (m_checkPackets) | ||
6229 | { | ||
6230 | if (AgentAni.AgentData.SessionID != SessionId || | ||
6231 | AgentAni.AgentData.AgentID != AgentId) | ||
6232 | return true; | ||
6233 | } | ||
6234 | #endregion | ||
6235 | |||
6236 | StartAnim handlerStartAnim = null; | ||
6237 | StopAnim handlerStopAnim = null; | ||
6238 | |||
6239 | for (int i = 0; i < AgentAni.AnimationList.Length; i++) | ||
6240 | { | ||
6241 | if (AgentAni.AnimationList[i].StartAnim) | ||
6242 | { | ||
6243 | handlerStartAnim = OnStartAnim; | ||
6244 | if (handlerStartAnim != null) | ||
6245 | { | ||
6246 | handlerStartAnim(this, AgentAni.AnimationList[i].AnimID); | ||
6247 | } | ||
6248 | } | ||
6249 | else | ||
6250 | { | ||
6251 | handlerStopAnim = OnStopAnim; | ||
6252 | if (handlerStopAnim != null) | ||
6253 | { | ||
6254 | handlerStopAnim(this, AgentAni.AnimationList[i].AnimID); | ||
6255 | } | ||
6256 | } | ||
6257 | } | ||
6258 | return true; | ||
6259 | } | ||
6260 | |||
6261 | private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) | ||
6262 | { | ||
6263 | if (OnAgentRequestSit != null) | ||
6264 | { | ||
6265 | AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket)Pack; | ||
6266 | |||
6267 | #region Packet Session and User Check | ||
6268 | if (m_checkPackets) | ||
6269 | { | ||
6270 | if (agentRequestSit.AgentData.SessionID != SessionId || | ||
6271 | agentRequestSit.AgentData.AgentID != AgentId) | ||
6272 | return true; | ||
6273 | } | ||
6274 | #endregion | ||
6275 | |||
6276 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; | ||
6277 | if (handlerAgentRequestSit != null) | ||
6278 | handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, | ||
6279 | agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); | ||
6280 | } | ||
6281 | return true; | ||
6282 | } | ||
6283 | |||
6284 | private bool HandleAgentSit(IClientAPI sender, Packet Pack) | ||
6285 | { | ||
6286 | if (OnAgentSit != null) | ||
6287 | { | ||
6288 | AgentSitPacket agentSit = (AgentSitPacket)Pack; | ||
6289 | |||
6290 | #region Packet Session and User Check | ||
6291 | if (m_checkPackets) | ||
6292 | { | ||
6293 | if (agentSit.AgentData.SessionID != SessionId || | ||
6294 | agentSit.AgentData.AgentID != AgentId) | ||
6295 | return true; | ||
6296 | } | ||
6297 | #endregion | ||
6298 | |||
6299 | AgentSit handlerAgentSit = OnAgentSit; | ||
6300 | if (handlerAgentSit != null) | ||
6301 | { | ||
6302 | OnAgentSit(this, agentSit.AgentData.AgentID); | ||
6303 | } | ||
6304 | } | ||
6305 | return true; | ||
6306 | } | ||
6307 | |||
6308 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) | ||
6309 | { | ||
6310 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; | ||
6311 | |||
6312 | #region Packet Session and User Check | ||
6313 | if (m_checkPackets) | ||
6314 | { | ||
6315 | // UNSUPPORTED ON THIS PACKET | ||
6316 | } | ||
6317 | #endregion | ||
6318 | |||
6319 | SoundTrigger handlerSoundTrigger = OnSoundTrigger; | ||
6320 | if (handlerSoundTrigger != null) | ||
6321 | { | ||
6322 | // UUIDS are sent as zeroes by the client, substitute agent's id | ||
6323 | handlerSoundTrigger(soundTriggerPacket.SoundData.SoundID, AgentId, | ||
6324 | AgentId, AgentId, | ||
6325 | soundTriggerPacket.SoundData.Gain, soundTriggerPacket.SoundData.Position, | ||
6326 | soundTriggerPacket.SoundData.Handle, 0); | ||
6327 | |||
6328 | } | ||
6329 | return true; | ||
6330 | } | ||
6331 | |||
6332 | private bool HandleAvatarPickerRequest(IClientAPI sender, Packet Pack) | ||
6333 | { | ||
6334 | AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack; | ||
6335 | |||
6336 | #region Packet Session and User Check | ||
6337 | if (m_checkPackets) | ||
6338 | { | ||
6339 | if (avRequestQuery.AgentData.SessionID != SessionId || | ||
6340 | avRequestQuery.AgentData.AgentID != AgentId) | ||
6341 | return true; | ||
6342 | } | ||
6343 | #endregion | ||
6344 | |||
6345 | AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData; | ||
6346 | AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data; | ||
6347 | //m_log.Debug("Agent Sends:" + Utils.BytesToString(querydata.Name)); | ||
6348 | |||
6349 | AvatarPickerRequest handlerAvatarPickerRequest = OnAvatarPickerRequest; | ||
6350 | if (handlerAvatarPickerRequest != null) | ||
6351 | { | ||
6352 | handlerAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID, | ||
6353 | Utils.BytesToString(querydata.Name)); | ||
6354 | } | ||
6355 | return true; | ||
6356 | } | ||
6357 | |||
6358 | private bool HandleAgentDataUpdateRequest(IClientAPI sender, Packet Pack) | ||
6359 | { | ||
6360 | AgentDataUpdateRequestPacket avRequestDataUpdatePacket = (AgentDataUpdateRequestPacket)Pack; | ||
6361 | |||
6362 | #region Packet Session and User Check | ||
6363 | if (m_checkPackets) | ||
6364 | { | ||
6365 | if (avRequestDataUpdatePacket.AgentData.SessionID != SessionId || | ||
6366 | avRequestDataUpdatePacket.AgentData.AgentID != AgentId) | ||
6367 | return true; | ||
6368 | } | ||
6369 | #endregion | ||
6370 | |||
6371 | FetchInventory handlerAgentDataUpdateRequest = OnAgentDataUpdateRequest; | ||
6372 | |||
6373 | if (handlerAgentDataUpdateRequest != null) | ||
6374 | { | ||
6375 | handlerAgentDataUpdateRequest(this, avRequestDataUpdatePacket.AgentData.AgentID, avRequestDataUpdatePacket.AgentData.SessionID); | ||
6376 | } | ||
6377 | |||
6378 | return true; | ||
6379 | } | ||
6380 | |||
6381 | private bool HandleUserInfoRequest(IClientAPI sender, Packet Pack) | ||
6382 | { | ||
6383 | UserInfoRequest handlerUserInfoRequest = OnUserInfoRequest; | ||
6384 | if (handlerUserInfoRequest != null) | ||
6385 | { | ||
6386 | handlerUserInfoRequest(this); | ||
6387 | } | ||
6388 | else | ||
6389 | { | ||
6390 | SendUserInfoReply(false, true, ""); | ||
6391 | } | ||
6392 | return true; | ||
6393 | |||
6394 | } | ||
6395 | |||
6396 | private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack) | ||
6397 | { | ||
6398 | UpdateUserInfoPacket updateUserInfo = (UpdateUserInfoPacket)Pack; | ||
6399 | |||
6400 | #region Packet Session and User Check | ||
6401 | if (m_checkPackets) | ||
6402 | { | ||
6403 | if (updateUserInfo.AgentData.SessionID != SessionId || | ||
6404 | updateUserInfo.AgentData.AgentID != AgentId) | ||
6405 | return true; | ||
6406 | } | ||
6407 | #endregion | ||
6408 | |||
6409 | UpdateUserInfo handlerUpdateUserInfo = OnUpdateUserInfo; | ||
6410 | if (handlerUpdateUserInfo != null) | ||
6411 | { | ||
6412 | bool visible = true; | ||
6413 | string DirectoryVisibility = | ||
6414 | Utils.BytesToString(updateUserInfo.UserData.DirectoryVisibility); | ||
6415 | if (DirectoryVisibility == "hidden") | ||
6416 | visible = false; | ||
6417 | |||
6418 | handlerUpdateUserInfo( | ||
6419 | updateUserInfo.UserData.IMViaEMail, | ||
6420 | visible, this); | ||
6421 | } | ||
6422 | return true; | ||
6423 | } | ||
6424 | |||
6425 | private bool HandleSetStartLocationRequest(IClientAPI sender, Packet Pack) | ||
6426 | { | ||
6427 | SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; | ||
6428 | |||
6429 | #region Packet Session and User Check | ||
6430 | if (m_checkPackets) | ||
6431 | { | ||
6432 | if (avSetStartLocationRequestPacket.AgentData.SessionID != SessionId || | ||
6433 | avSetStartLocationRequestPacket.AgentData.AgentID != AgentId) | ||
6434 | return true; | ||
6435 | } | ||
6436 | #endregion | ||
6437 | |||
6438 | if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId) | ||
6439 | { | ||
6440 | // Linden Client limitation.. | ||
6441 | if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f | ||
6442 | || avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f) | ||
6443 | { | ||
6444 | ScenePresence avatar = null; | ||
6445 | if (((Scene)m_scene).TryGetScenePresence(AgentId, out avatar)) | ||
6446 | { | ||
6447 | if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f) | ||
6448 | { | ||
6449 | avSetStartLocationRequestPacket.StartLocationData.LocationPos.X = avatar.AbsolutePosition.X; | ||
6450 | } | ||
6451 | if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f) | ||
6452 | { | ||
6453 | avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y = avatar.AbsolutePosition.Y; | ||
6454 | } | ||
6455 | } | ||
6456 | |||
6457 | } | ||
6458 | TeleportLocationRequest handlerSetStartLocationRequest = OnSetStartLocationRequest; | ||
6459 | if (handlerSetStartLocationRequest != null) | ||
6460 | { | ||
6461 | handlerSetStartLocationRequest(this, 0, avSetStartLocationRequestPacket.StartLocationData.LocationPos, | ||
6462 | avSetStartLocationRequestPacket.StartLocationData.LocationLookAt, | ||
6463 | avSetStartLocationRequestPacket.StartLocationData.LocationID); | ||
6464 | } | ||
6465 | } | ||
6466 | return true; | ||
6467 | } | ||
6468 | |||
6469 | private bool HandleAgentThrottle(IClientAPI sender, Packet Pack) | ||
6470 | { | ||
6471 | AgentThrottlePacket atpack = (AgentThrottlePacket)Pack; | ||
6472 | |||
6473 | #region Packet Session and User Check | ||
6474 | if (m_checkPackets) | ||
6475 | { | ||
6476 | if (atpack.AgentData.SessionID != SessionId || | ||
6477 | atpack.AgentData.AgentID != AgentId) | ||
6478 | return true; | ||
6479 | } | ||
6480 | #endregion | ||
6481 | |||
6482 | m_udpClient.SetThrottles(atpack.Throttle.Throttles); | ||
6483 | return true; | ||
6484 | } | ||
6485 | |||
6486 | private bool HandleAgentPause(IClientAPI sender, Packet Pack) | ||
6487 | { | ||
6488 | m_udpClient.IsPaused = true; | ||
6489 | return true; | ||
6490 | } | ||
6491 | |||
6492 | private bool HandleAgentResume(IClientAPI sender, Packet Pack) | ||
6493 | { | ||
6494 | m_udpClient.IsPaused = false; | ||
6495 | SendStartPingCheck(m_udpClient.CurrentPingSequence++); | ||
6496 | return true; | ||
6497 | } | ||
6498 | |||
6499 | private bool HandleForceScriptControlRelease(IClientAPI sender, Packet Pack) | ||
6500 | { | ||
6501 | ForceReleaseControls handlerForceReleaseControls = OnForceReleaseControls; | ||
6502 | if (handlerForceReleaseControls != null) | ||
6503 | { | ||
6504 | handlerForceReleaseControls(this, AgentId); | ||
6505 | } | ||
6506 | return true; | ||
6507 | } | ||
6508 | |||
6509 | #endregion Scene/Avatar | ||
6510 | |||
6511 | #region Objects/m_sceneObjects | ||
6512 | |||
6513 | private bool HandleObjectLink(IClientAPI sender, Packet Pack) | ||
6514 | { | ||
6515 | ObjectLinkPacket link = (ObjectLinkPacket)Pack; | ||
6516 | |||
6517 | #region Packet Session and User Check | ||
6518 | if (m_checkPackets) | ||
6519 | { | ||
6520 | if (link.AgentData.SessionID != SessionId || | ||
6521 | link.AgentData.AgentID != AgentId) | ||
6522 | return true; | ||
6523 | } | ||
6524 | #endregion | ||
6525 | |||
6526 | uint parentprimid = 0; | ||
6527 | List<uint> childrenprims = new List<uint>(); | ||
6528 | if (link.ObjectData.Length > 1) | ||
6529 | { | ||
6530 | parentprimid = link.ObjectData[0].ObjectLocalID; | ||
6531 | |||
6532 | for (int i = 1; i < link.ObjectData.Length; i++) | ||
6533 | { | ||
6534 | childrenprims.Add(link.ObjectData[i].ObjectLocalID); | ||
6535 | } | ||
6536 | } | ||
6537 | LinkObjects handlerLinkObjects = OnLinkObjects; | ||
6538 | if (handlerLinkObjects != null) | ||
6539 | { | ||
6540 | handlerLinkObjects(this, parentprimid, childrenprims); | ||
6541 | } | ||
6542 | return true; | ||
6543 | } | ||
6544 | |||
6545 | private bool HandleObjectDelink(IClientAPI sender, Packet Pack) | ||
6546 | { | ||
6547 | ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack; | ||
6548 | |||
6549 | #region Packet Session and User Check | ||
6550 | if (m_checkPackets) | ||
6551 | { | ||
6552 | if (delink.AgentData.SessionID != SessionId || | ||
6553 | delink.AgentData.AgentID != AgentId) | ||
6554 | return true; | ||
6555 | } | ||
6556 | #endregion | ||
6557 | |||
6558 | // It appears the prim at index 0 is not always the root prim (for | ||
6559 | // instance, when one prim of a link set has been edited independently | ||
6560 | // of the others). Therefore, we'll pass all the ids onto the delink | ||
6561 | // method for it to decide which is the root. | ||
6562 | List<uint> prims = new List<uint>(); | ||
6563 | for (int i = 0; i < delink.ObjectData.Length; i++) | ||
6564 | { | ||
6565 | prims.Add(delink.ObjectData[i].ObjectLocalID); | ||
6566 | } | ||
6567 | DelinkObjects handlerDelinkObjects = OnDelinkObjects; | ||
6568 | if (handlerDelinkObjects != null) | ||
6569 | { | ||
6570 | handlerDelinkObjects(prims, this); | ||
6571 | } | ||
6572 | |||
6573 | return true; | ||
6574 | } | ||
6575 | |||
6576 | private bool HandleObjectAdd(IClientAPI sender, Packet Pack) | ||
6577 | { | ||
6578 | if (OnAddPrim != null) | ||
6579 | { | ||
6580 | ObjectAddPacket addPacket = (ObjectAddPacket)Pack; | ||
6581 | |||
6582 | #region Packet Session and User Check | ||
6583 | if (m_checkPackets) | ||
6584 | { | ||
6585 | if (addPacket.AgentData.SessionID != SessionId || | ||
6586 | addPacket.AgentData.AgentID != AgentId) | ||
6587 | return true; | ||
6588 | } | ||
6589 | #endregion | ||
6590 | |||
6591 | PrimitiveBaseShape shape = GetShapeFromAddPacket(addPacket); | ||
6592 | // m_log.Info("[REZData]: " + addPacket.ToString()); | ||
6593 | //BypassRaycast: 1 | ||
6594 | //RayStart: <69.79469, 158.2652, 98.40343> | ||
6595 | //RayEnd: <61.97724, 141.995, 92.58341> | ||
6596 | //RayTargetID: 00000000-0000-0000-0000-000000000000 | ||
6597 | |||
6598 | //Check to see if adding the prim is allowed; useful for any module wanting to restrict the | ||
6599 | //object from rezing initially | ||
6600 | |||
6601 | AddNewPrim handlerAddPrim = OnAddPrim; | ||
6602 | if (handlerAddPrim != null) | ||
6603 | handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); | ||
6604 | } | ||
6605 | return true; | ||
6606 | } | ||
6607 | |||
6608 | private bool HandleObjectShape(IClientAPI sender, Packet Pack) | ||
6609 | { | ||
6610 | ObjectShapePacket shapePacket = (ObjectShapePacket)Pack; | ||
6611 | |||
6612 | #region Packet Session and User Check | ||
6613 | if (m_checkPackets) | ||
6614 | { | ||
6615 | if (shapePacket.AgentData.SessionID != SessionId || | ||
6616 | shapePacket.AgentData.AgentID != AgentId) | ||
6617 | return true; | ||
6618 | } | ||
6619 | #endregion | ||
6620 | |||
6621 | UpdateShape handlerUpdatePrimShape = null; | ||
6622 | for (int i = 0; i < shapePacket.ObjectData.Length; i++) | ||
6623 | { | ||
6624 | handlerUpdatePrimShape = OnUpdatePrimShape; | ||
6625 | if (handlerUpdatePrimShape != null) | ||
6626 | { | ||
6627 | UpdateShapeArgs shapeData = new UpdateShapeArgs(); | ||
6628 | shapeData.ObjectLocalID = shapePacket.ObjectData[i].ObjectLocalID; | ||
6629 | shapeData.PathBegin = shapePacket.ObjectData[i].PathBegin; | ||
6630 | shapeData.PathCurve = shapePacket.ObjectData[i].PathCurve; | ||
6631 | shapeData.PathEnd = shapePacket.ObjectData[i].PathEnd; | ||
6632 | shapeData.PathRadiusOffset = shapePacket.ObjectData[i].PathRadiusOffset; | ||
6633 | shapeData.PathRevolutions = shapePacket.ObjectData[i].PathRevolutions; | ||
6634 | shapeData.PathScaleX = shapePacket.ObjectData[i].PathScaleX; | ||
6635 | shapeData.PathScaleY = shapePacket.ObjectData[i].PathScaleY; | ||
6636 | shapeData.PathShearX = shapePacket.ObjectData[i].PathShearX; | ||
6637 | shapeData.PathShearY = shapePacket.ObjectData[i].PathShearY; | ||
6638 | shapeData.PathSkew = shapePacket.ObjectData[i].PathSkew; | ||
6639 | shapeData.PathTaperX = shapePacket.ObjectData[i].PathTaperX; | ||
6640 | shapeData.PathTaperY = shapePacket.ObjectData[i].PathTaperY; | ||
6641 | shapeData.PathTwist = shapePacket.ObjectData[i].PathTwist; | ||
6642 | shapeData.PathTwistBegin = shapePacket.ObjectData[i].PathTwistBegin; | ||
6643 | shapeData.ProfileBegin = shapePacket.ObjectData[i].ProfileBegin; | ||
6644 | shapeData.ProfileCurve = shapePacket.ObjectData[i].ProfileCurve; | ||
6645 | shapeData.ProfileEnd = shapePacket.ObjectData[i].ProfileEnd; | ||
6646 | shapeData.ProfileHollow = shapePacket.ObjectData[i].ProfileHollow; | ||
6647 | |||
6648 | handlerUpdatePrimShape(m_agentId, shapePacket.ObjectData[i].ObjectLocalID, | ||
6649 | shapeData); | ||
6650 | } | ||
6651 | } | ||
6652 | return true; | ||
6653 | } | ||
6654 | |||
6655 | private bool HandleObjectExtraParams(IClientAPI sender, Packet Pack) | ||
6656 | { | ||
6657 | ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; | ||
6658 | |||
6659 | #region Packet Session and User Check | ||
6660 | if (m_checkPackets) | ||
6661 | { | ||
6662 | if (extraPar.AgentData.SessionID != SessionId || | ||
6663 | extraPar.AgentData.AgentID != AgentId) | ||
6664 | return true; | ||
6665 | } | ||
6666 | #endregion | ||
6667 | |||
6668 | ObjectExtraParams handlerUpdateExtraParams = OnUpdateExtraParams; | ||
6669 | if (handlerUpdateExtraParams != null) | ||
6670 | { | ||
6671 | for (int i = 0; i < extraPar.ObjectData.Length; i++) | ||
6672 | { | ||
6673 | handlerUpdateExtraParams(m_agentId, extraPar.ObjectData[i].ObjectLocalID, | ||
6674 | extraPar.ObjectData[i].ParamType, | ||
6675 | extraPar.ObjectData[i].ParamInUse, extraPar.ObjectData[i].ParamData); | ||
6676 | } | ||
6677 | } | ||
6678 | return true; | ||
6679 | } | ||
6680 | |||
6681 | private bool HandleObjectDuplicate(IClientAPI sender, Packet Pack) | ||
6682 | { | ||
6683 | ObjectDuplicatePacket dupe = (ObjectDuplicatePacket)Pack; | ||
6684 | |||
6685 | #region Packet Session and User Check | ||
6686 | if (m_checkPackets) | ||
6687 | { | ||
6688 | if (dupe.AgentData.SessionID != SessionId || | ||
6689 | dupe.AgentData.AgentID != AgentId) | ||
6690 | return true; | ||
6691 | } | ||
6692 | #endregion | ||
6693 | |||
6694 | // ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData; | ||
6695 | |||
6696 | ObjectDuplicate handlerObjectDuplicate = null; | ||
6697 | |||
6698 | for (int i = 0; i < dupe.ObjectData.Length; i++) | ||
6699 | { | ||
6700 | handlerObjectDuplicate = OnObjectDuplicate; | ||
6701 | if (handlerObjectDuplicate != null) | ||
6702 | { | ||
6703 | handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, | ||
6704 | dupe.SharedData.DuplicateFlags, AgentId, | ||
6705 | m_activeGroupID); | ||
6706 | } | ||
6707 | } | ||
6708 | |||
6709 | return true; | ||
6710 | } | ||
6711 | |||
6712 | private bool HandleRequestMultipleObjects(IClientAPI sender, Packet Pack) | ||
6713 | { | ||
6714 | RequestMultipleObjectsPacket incomingRequest = (RequestMultipleObjectsPacket)Pack; | ||
6715 | |||
6716 | #region Packet Session and User Check | ||
6717 | if (m_checkPackets) | ||
6718 | { | ||
6719 | if (incomingRequest.AgentData.SessionID != SessionId || | ||
6720 | incomingRequest.AgentData.AgentID != AgentId) | ||
6721 | return true; | ||
6722 | } | ||
6723 | #endregion | ||
6724 | |||
6725 | ObjectRequest handlerObjectRequest = null; | ||
6726 | |||
6727 | for (int i = 0; i < incomingRequest.ObjectData.Length; i++) | ||
6728 | { | ||
6729 | handlerObjectRequest = OnObjectRequest; | ||
6730 | if (handlerObjectRequest != null) | ||
6731 | { | ||
6732 | handlerObjectRequest(incomingRequest.ObjectData[i].ID, this); | ||
6733 | } | ||
6734 | } | ||
6735 | return true; | ||
6736 | } | ||
6737 | |||
6738 | private bool HandleObjectSelect(IClientAPI sender, Packet Pack) | ||
6739 | { | ||
6740 | ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack; | ||
6741 | |||
6742 | #region Packet Session and User Check | ||
6743 | if (m_checkPackets) | ||
6744 | { | ||
6745 | if (incomingselect.AgentData.SessionID != SessionId || | ||
6746 | incomingselect.AgentData.AgentID != AgentId) | ||
6747 | return true; | ||
6748 | } | ||
6749 | #endregion | ||
6750 | |||
6751 | ObjectSelect handlerObjectSelect = null; | ||
6752 | |||
6753 | for (int i = 0; i < incomingselect.ObjectData.Length; i++) | ||
6754 | { | ||
6755 | handlerObjectSelect = OnObjectSelect; | ||
6756 | if (handlerObjectSelect != null) | ||
6757 | { | ||
6758 | handlerObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this); | ||
6759 | } | ||
6760 | } | ||
6761 | return true; | ||
6762 | } | ||
6763 | |||
6764 | private bool HandleObjectDeselect(IClientAPI sender, Packet Pack) | ||
6765 | { | ||
6766 | ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket)Pack; | ||
6767 | |||
6768 | #region Packet Session and User Check | ||
6769 | if (m_checkPackets) | ||
6770 | { | ||
6771 | if (incomingdeselect.AgentData.SessionID != SessionId || | ||
6772 | incomingdeselect.AgentData.AgentID != AgentId) | ||
6773 | return true; | ||
6774 | } | ||
6775 | #endregion | ||
6776 | |||
6777 | ObjectDeselect handlerObjectDeselect = null; | ||
6778 | |||
6779 | for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) | ||
6780 | { | ||
6781 | handlerObjectDeselect = OnObjectDeselect; | ||
6782 | if (handlerObjectDeselect != null) | ||
6783 | { | ||
6784 | OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this); | ||
6785 | } | ||
6786 | } | ||
6787 | return true; | ||
6788 | } | ||
6789 | |||
6790 | private bool HandleObjectPosition(IClientAPI sender, Packet Pack) | ||
6791 | { | ||
6792 | // DEPRECATED: but till libsecondlife removes it, people will use it | ||
6793 | ObjectPositionPacket position = (ObjectPositionPacket)Pack; | ||
6794 | |||
6795 | #region Packet Session and User Check | ||
6796 | if (m_checkPackets) | ||
6797 | { | ||
6798 | if (position.AgentData.SessionID != SessionId || | ||
6799 | position.AgentData.AgentID != AgentId) | ||
6800 | return true; | ||
6801 | } | ||
6802 | #endregion | ||
6803 | |||
6804 | |||
6805 | for (int i = 0; i < position.ObjectData.Length; i++) | ||
6806 | { | ||
6807 | UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; | ||
6808 | if (handlerUpdateVector != null) | ||
6809 | handlerUpdateVector(position.ObjectData[i].ObjectLocalID, position.ObjectData[i].Position, this); | ||
6810 | } | ||
6811 | |||
6812 | return true; | ||
6813 | } | ||
6814 | |||
6815 | private bool HandleObjectScale(IClientAPI sender, Packet Pack) | ||
6816 | { | ||
6817 | // DEPRECATED: but till libsecondlife removes it, people will use it | ||
6818 | ObjectScalePacket scale = (ObjectScalePacket)Pack; | ||
6819 | |||
6820 | #region Packet Session and User Check | ||
6821 | if (m_checkPackets) | ||
6822 | { | ||
6823 | if (scale.AgentData.SessionID != SessionId || | ||
6824 | scale.AgentData.AgentID != AgentId) | ||
6825 | return true; | ||
6826 | } | ||
6827 | #endregion | ||
6828 | |||
6829 | for (int i = 0; i < scale.ObjectData.Length; i++) | ||
6830 | { | ||
6831 | UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; | ||
6832 | if (handlerUpdatePrimGroupScale != null) | ||
6833 | handlerUpdatePrimGroupScale(scale.ObjectData[i].ObjectLocalID, scale.ObjectData[i].Scale, this); | ||
6834 | } | ||
6835 | |||
6836 | return true; | ||
6837 | } | ||
6838 | |||
6839 | private bool HandleObjectRotation(IClientAPI sender, Packet Pack) | ||
6840 | { | ||
6841 | // DEPRECATED: but till libsecondlife removes it, people will use it | ||
6842 | ObjectRotationPacket rotation = (ObjectRotationPacket)Pack; | ||
6843 | |||
6844 | #region Packet Session and User Check | ||
6845 | if (m_checkPackets) | ||
6846 | { | ||
6847 | if (rotation.AgentData.SessionID != SessionId || | ||
6848 | rotation.AgentData.AgentID != AgentId) | ||
6849 | return true; | ||
6850 | } | ||
6851 | #endregion | ||
6852 | |||
6853 | for (int i = 0; i < rotation.ObjectData.Length; i++) | ||
6854 | { | ||
6855 | UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; | ||
6856 | if (handlerUpdatePrimRotation != null) | ||
6857 | handlerUpdatePrimRotation(rotation.ObjectData[i].ObjectLocalID, rotation.ObjectData[i].Rotation, this); | ||
6858 | } | ||
6859 | |||
6860 | return true; | ||
6861 | } | ||
6862 | |||
6863 | private bool HandleObjectFlagUpdate(IClientAPI sender, Packet Pack) | ||
6864 | { | ||
6865 | ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack; | ||
6866 | |||
6867 | #region Packet Session and User Check | ||
6868 | if (m_checkPackets) | ||
6869 | { | ||
6870 | if (flags.AgentData.SessionID != SessionId || | ||
6871 | flags.AgentData.AgentID != AgentId) | ||
6872 | return true; | ||
6873 | } | ||
6874 | #endregion | ||
6875 | |||
6876 | UpdatePrimFlags handlerUpdatePrimFlags = OnUpdatePrimFlags; | ||
6877 | |||
6878 | if (handlerUpdatePrimFlags != null) | ||
6879 | { | ||
6880 | byte[] data = Pack.ToBytes(); | ||
6881 | // 46,47,48 are special positions within the packet | ||
6882 | // This may change so perhaps we need a better way | ||
6883 | // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) | ||
6884 | bool UsePhysics = (data[46] != 0) ? true : false; | ||
6885 | bool IsTemporary = (data[47] != 0) ? true : false; | ||
6886 | bool IsPhantom = (data[48] != 0) ? true : false; | ||
6887 | handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this); | ||
6888 | } | ||
6889 | return true; | ||
6890 | } | ||
6891 | |||
6892 | private bool HandleObjectImage(IClientAPI sender, Packet Pack) | ||
6893 | { | ||
6894 | ObjectImagePacket imagePack = (ObjectImagePacket)Pack; | ||
6895 | |||
6896 | UpdatePrimTexture handlerUpdatePrimTexture = null; | ||
6897 | for (int i = 0; i < imagePack.ObjectData.Length; i++) | ||
6898 | { | ||
6899 | handlerUpdatePrimTexture = OnUpdatePrimTexture; | ||
6900 | if (handlerUpdatePrimTexture != null) | ||
6901 | { | ||
6902 | handlerUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, | ||
6903 | imagePack.ObjectData[i].TextureEntry, this); | ||
6904 | } | ||
6905 | } | ||
6906 | return true; | ||
6907 | } | ||
6908 | |||
6909 | private bool HandleObjectGrab(IClientAPI sender, Packet Pack) | ||
6910 | { | ||
6911 | ObjectGrabPacket grab = (ObjectGrabPacket)Pack; | ||
6912 | |||
6913 | #region Packet Session and User Check | ||
6914 | if (m_checkPackets) | ||
6915 | { | ||
6916 | if (grab.AgentData.SessionID != SessionId || | ||
6917 | grab.AgentData.AgentID != AgentId) | ||
6918 | return true; | ||
6919 | } | ||
6920 | #endregion | ||
6921 | |||
6922 | GrabObject handlerGrabObject = OnGrabObject; | ||
6923 | |||
6924 | if (handlerGrabObject != null) | ||
6925 | { | ||
6926 | List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>(); | ||
6927 | if ((grab.SurfaceInfo != null) && (grab.SurfaceInfo.Length > 0)) | ||
6928 | { | ||
6929 | foreach (ObjectGrabPacket.SurfaceInfoBlock surfaceInfo in grab.SurfaceInfo) | ||
6930 | { | ||
6931 | SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs(); | ||
6932 | arg.Binormal = surfaceInfo.Binormal; | ||
6933 | arg.FaceIndex = surfaceInfo.FaceIndex; | ||
6934 | arg.Normal = surfaceInfo.Normal; | ||
6935 | arg.Position = surfaceInfo.Position; | ||
6936 | arg.STCoord = surfaceInfo.STCoord; | ||
6937 | arg.UVCoord = surfaceInfo.UVCoord; | ||
6938 | touchArgs.Add(arg); | ||
6939 | } | ||
6940 | } | ||
6941 | handlerGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this, touchArgs); | ||
6942 | } | ||
6943 | return true; | ||
6944 | } | ||
6945 | |||
6946 | private bool HandleObjectGrabUpdate(IClientAPI sender, Packet Pack) | ||
6947 | { | ||
6948 | ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)Pack; | ||
6949 | |||
6950 | #region Packet Session and User Check | ||
6951 | if (m_checkPackets) | ||
6952 | { | ||
6953 | if (grabUpdate.AgentData.SessionID != SessionId || | ||
6954 | grabUpdate.AgentData.AgentID != AgentId) | ||
6955 | return true; | ||
6956 | } | ||
6957 | #endregion | ||
6958 | |||
6959 | MoveObject handlerGrabUpdate = OnGrabUpdate; | ||
6960 | |||
6961 | if (handlerGrabUpdate != null) | ||
6962 | { | ||
6963 | List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>(); | ||
6964 | if ((grabUpdate.SurfaceInfo != null) && (grabUpdate.SurfaceInfo.Length > 0)) | ||
6965 | { | ||
6966 | foreach (ObjectGrabUpdatePacket.SurfaceInfoBlock surfaceInfo in grabUpdate.SurfaceInfo) | ||
6967 | { | ||
6968 | SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs(); | ||
6969 | arg.Binormal = surfaceInfo.Binormal; | ||
6970 | arg.FaceIndex = surfaceInfo.FaceIndex; | ||
6971 | arg.Normal = surfaceInfo.Normal; | ||
6972 | arg.Position = surfaceInfo.Position; | ||
6973 | arg.STCoord = surfaceInfo.STCoord; | ||
6974 | arg.UVCoord = surfaceInfo.UVCoord; | ||
6975 | touchArgs.Add(arg); | ||
6976 | } | ||
6977 | } | ||
6978 | handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, | ||
6979 | grabUpdate.ObjectData.GrabPosition, this, touchArgs); | ||
6980 | } | ||
6981 | return true; | ||
6982 | } | ||
6983 | |||
6984 | private bool HandleObjectDeGrab(IClientAPI sender, Packet Pack) | ||
6985 | { | ||
6986 | ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket)Pack; | ||
6987 | |||
6988 | #region Packet Session and User Check | ||
6989 | if (m_checkPackets) | ||
6990 | { | ||
6991 | if (deGrab.AgentData.SessionID != SessionId || | ||
6992 | deGrab.AgentData.AgentID != AgentId) | ||
6993 | return true; | ||
6994 | } | ||
6995 | #endregion | ||
6996 | |||
6997 | DeGrabObject handlerDeGrabObject = OnDeGrabObject; | ||
6998 | if (handlerDeGrabObject != null) | ||
6999 | { | ||
7000 | List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>(); | ||
7001 | if ((deGrab.SurfaceInfo != null) && (deGrab.SurfaceInfo.Length > 0)) | ||
7002 | { | ||
7003 | foreach (ObjectDeGrabPacket.SurfaceInfoBlock surfaceInfo in deGrab.SurfaceInfo) | ||
7004 | { | ||
7005 | SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs(); | ||
7006 | arg.Binormal = surfaceInfo.Binormal; | ||
7007 | arg.FaceIndex = surfaceInfo.FaceIndex; | ||
7008 | arg.Normal = surfaceInfo.Normal; | ||
7009 | arg.Position = surfaceInfo.Position; | ||
7010 | arg.STCoord = surfaceInfo.STCoord; | ||
7011 | arg.UVCoord = surfaceInfo.UVCoord; | ||
7012 | touchArgs.Add(arg); | ||
7013 | } | ||
7014 | } | ||
7015 | handlerDeGrabObject(deGrab.ObjectData.LocalID, this, touchArgs); | ||
7016 | } | ||
7017 | return true; | ||
7018 | } | ||
7019 | |||
7020 | private bool HandleObjectSpinStart(IClientAPI sender, Packet Pack) | ||
7021 | { | ||
7022 | //m_log.Warn("[CLIENT]: unhandled ObjectSpinStart packet"); | ||
7023 | ObjectSpinStartPacket spinStart = (ObjectSpinStartPacket)Pack; | ||
7024 | |||
7025 | #region Packet Session and User Check | ||
7026 | if (m_checkPackets) | ||
7027 | { | ||
7028 | if (spinStart.AgentData.SessionID != SessionId || | ||
7029 | spinStart.AgentData.AgentID != AgentId) | ||
7030 | return true; | ||
7031 | } | ||
7032 | #endregion | ||
7033 | |||
7034 | SpinStart handlerSpinStart = OnSpinStart; | ||
7035 | if (handlerSpinStart != null) | ||
7036 | { | ||
7037 | handlerSpinStart(spinStart.ObjectData.ObjectID, this); | ||
7038 | } | ||
7039 | return true; | ||
7040 | } | ||
7041 | |||
7042 | private bool HandleObjectSpinUpdate(IClientAPI sender, Packet Pack) | ||
7043 | { | ||
7044 | //m_log.Warn("[CLIENT]: unhandled ObjectSpinUpdate packet"); | ||
7045 | ObjectSpinUpdatePacket spinUpdate = (ObjectSpinUpdatePacket)Pack; | ||
7046 | |||
7047 | #region Packet Session and User Check | ||
7048 | if (m_checkPackets) | ||
7049 | { | ||
7050 | if (spinUpdate.AgentData.SessionID != SessionId || | ||
7051 | spinUpdate.AgentData.AgentID != AgentId) | ||
7052 | return true; | ||
7053 | } | ||
7054 | #endregion | ||
7055 | |||
7056 | Vector3 axis; | ||
7057 | float angle; | ||
7058 | spinUpdate.ObjectData.Rotation.GetAxisAngle(out axis, out angle); | ||
7059 | //m_log.Warn("[CLIENT]: ObjectSpinUpdate packet rot axis:" + axis + " angle:" + angle); | ||
7060 | |||
7061 | SpinObject handlerSpinUpdate = OnSpinUpdate; | ||
7062 | if (handlerSpinUpdate != null) | ||
7063 | { | ||
7064 | handlerSpinUpdate(spinUpdate.ObjectData.ObjectID, spinUpdate.ObjectData.Rotation, this); | ||
7065 | } | ||
7066 | return true; | ||
7067 | } | ||
7068 | |||
7069 | private bool HandleObjectSpinStop(IClientAPI sender, Packet Pack) | ||
7070 | { | ||
7071 | //m_log.Warn("[CLIENT]: unhandled ObjectSpinStop packet"); | ||
7072 | ObjectSpinStopPacket spinStop = (ObjectSpinStopPacket)Pack; | ||
7073 | |||
7074 | #region Packet Session and User Check | ||
7075 | if (m_checkPackets) | ||
7076 | { | ||
7077 | if (spinStop.AgentData.SessionID != SessionId || | ||
7078 | spinStop.AgentData.AgentID != AgentId) | ||
7079 | return true; | ||
7080 | } | ||
7081 | #endregion | ||
7082 | |||
7083 | SpinStop handlerSpinStop = OnSpinStop; | ||
7084 | if (handlerSpinStop != null) | ||
7085 | { | ||
7086 | handlerSpinStop(spinStop.ObjectData.ObjectID, this); | ||
7087 | } | ||
7088 | return true; | ||
7089 | } | ||
7090 | |||
7091 | private bool HandleObjectDescription(IClientAPI sender, Packet Pack) | ||
7092 | { | ||
7093 | ObjectDescriptionPacket objDes = (ObjectDescriptionPacket)Pack; | ||
7094 | |||
7095 | #region Packet Session and User Check | ||
7096 | if (m_checkPackets) | ||
7097 | { | ||
7098 | if (objDes.AgentData.SessionID != SessionId || | ||
7099 | objDes.AgentData.AgentID != AgentId) | ||
7100 | return true; | ||
7101 | } | ||
7102 | #endregion | ||
7103 | |||
7104 | GenericCall7 handlerObjectDescription = null; | ||
7105 | |||
7106 | for (int i = 0; i < objDes.ObjectData.Length; i++) | ||
7107 | { | ||
7108 | handlerObjectDescription = OnObjectDescription; | ||
7109 | if (handlerObjectDescription != null) | ||
7110 | { | ||
7111 | handlerObjectDescription(this, objDes.ObjectData[i].LocalID, | ||
7112 | Util.FieldToString(objDes.ObjectData[i].Description)); | ||
7113 | } | ||
7114 | } | ||
7115 | return true; | ||
7116 | } | ||
7117 | |||
7118 | private bool HandleObjectName(IClientAPI sender, Packet Pack) | ||
7119 | { | ||
7120 | ObjectNamePacket objName = (ObjectNamePacket)Pack; | ||
7121 | |||
7122 | #region Packet Session and User Check | ||
7123 | if (m_checkPackets) | ||
7124 | { | ||
7125 | if (objName.AgentData.SessionID != SessionId || | ||
7126 | objName.AgentData.AgentID != AgentId) | ||
7127 | return true; | ||
7128 | } | ||
7129 | #endregion | ||
7130 | |||
7131 | GenericCall7 handlerObjectName = null; | ||
7132 | for (int i = 0; i < objName.ObjectData.Length; i++) | ||
7133 | { | ||
7134 | handlerObjectName = OnObjectName; | ||
7135 | if (handlerObjectName != null) | ||
7136 | { | ||
7137 | handlerObjectName(this, objName.ObjectData[i].LocalID, | ||
7138 | Util.FieldToString(objName.ObjectData[i].Name)); | ||
7139 | } | ||
7140 | } | ||
7141 | return true; | ||
7142 | } | ||
7143 | |||
7144 | private bool HandleObjectPermissions(IClientAPI sender, Packet Pack) | ||
7145 | { | ||
7146 | if (OnObjectPermissions != null) | ||
7147 | { | ||
7148 | ObjectPermissionsPacket newobjPerms = (ObjectPermissionsPacket)Pack; | ||
7149 | |||
7150 | #region Packet Session and User Check | ||
7151 | if (m_checkPackets) | ||
7152 | { | ||
7153 | if (newobjPerms.AgentData.SessionID != SessionId || | ||
7154 | newobjPerms.AgentData.AgentID != AgentId) | ||
7155 | return true; | ||
7156 | } | ||
7157 | #endregion | ||
7158 | |||
7159 | UUID AgentID = newobjPerms.AgentData.AgentID; | ||
7160 | UUID SessionID = newobjPerms.AgentData.SessionID; | ||
7161 | |||
7162 | ObjectPermissions handlerObjectPermissions = null; | ||
7163 | |||
7164 | for (int i = 0; i < newobjPerms.ObjectData.Length; i++) | ||
7165 | { | ||
7166 | ObjectPermissionsPacket.ObjectDataBlock permChanges = newobjPerms.ObjectData[i]; | ||
7167 | |||
7168 | byte field = permChanges.Field; | ||
7169 | uint localID = permChanges.ObjectLocalID; | ||
7170 | uint mask = permChanges.Mask; | ||
7171 | byte set = permChanges.Set; | ||
7172 | |||
7173 | handlerObjectPermissions = OnObjectPermissions; | ||
7174 | |||
7175 | if (handlerObjectPermissions != null) | ||
7176 | handlerObjectPermissions(this, AgentID, SessionID, field, localID, mask, set); | ||
7177 | } | ||
7178 | } | ||
7179 | |||
7180 | // Here's our data, | ||
7181 | // PermField contains the field the info goes into | ||
7182 | // PermField determines which mask we're changing | ||
7183 | // | ||
7184 | // chmask is the mask of the change | ||
7185 | // setTF is whether we're adding it or taking it away | ||
7186 | // | ||
7187 | // objLocalID is the localID of the object. | ||
7188 | |||
7189 | // Unfortunately, we have to pass the event the packet because objData is an array | ||
7190 | // That means multiple object perms may be updated in a single packet. | ||
7191 | |||
7192 | return true; | ||
7193 | } | ||
7194 | |||
7195 | private bool HandleUndo(IClientAPI sender, Packet Pack) | ||
7196 | { | ||
7197 | UndoPacket undoitem = (UndoPacket)Pack; | ||
7198 | |||
7199 | #region Packet Session and User Check | ||
7200 | if (m_checkPackets) | ||
7201 | { | ||
7202 | if (undoitem.AgentData.SessionID != SessionId || | ||
7203 | undoitem.AgentData.AgentID != AgentId) | ||
7204 | return true; | ||
7205 | } | ||
7206 | #endregion | ||
7207 | |||
7208 | if (undoitem.ObjectData.Length > 0) | ||
7209 | { | ||
7210 | for (int i = 0; i < undoitem.ObjectData.Length; i++) | ||
7211 | { | ||
7212 | UUID objiD = undoitem.ObjectData[i].ObjectID; | ||
7213 | AgentSit handlerOnUndo = OnUndo; | ||
7214 | if (handlerOnUndo != null) | ||
7215 | { | ||
7216 | handlerOnUndo(this, objiD); | ||
7217 | } | ||
7218 | |||
7219 | } | ||
7220 | } | ||
7221 | return true; | ||
7222 | } | ||
7223 | |||
7224 | private bool HandleLandUndo(IClientAPI sender, Packet Pack) | ||
7225 | { | ||
7226 | UndoLandPacket undolanditem = (UndoLandPacket)Pack; | ||
7227 | |||
7228 | #region Packet Session and User Check | ||
7229 | if (m_checkPackets) | ||
7230 | { | ||
7231 | if (undolanditem.AgentData.SessionID != SessionId || | ||
7232 | undolanditem.AgentData.AgentID != AgentId) | ||
7233 | return true; | ||
7234 | } | ||
7235 | #endregion | ||
7236 | |||
7237 | LandUndo handlerOnUndo = OnLandUndo; | ||
7238 | if (handlerOnUndo != null) | ||
7239 | { | ||
7240 | handlerOnUndo(this); | ||
7241 | } | ||
7242 | return true; | ||
7243 | } | ||
7244 | |||
7245 | private bool HandleRedo(IClientAPI sender, Packet Pack) | ||
7246 | { | ||
7247 | RedoPacket redoitem = (RedoPacket)Pack; | ||
7248 | |||
7249 | #region Packet Session and User Check | ||
7250 | if (m_checkPackets) | ||
7251 | { | ||
7252 | if (redoitem.AgentData.SessionID != SessionId || | ||
7253 | redoitem.AgentData.AgentID != AgentId) | ||
7254 | return true; | ||
7255 | } | ||
7256 | #endregion | ||
7257 | |||
7258 | if (redoitem.ObjectData.Length > 0) | ||
7259 | { | ||
7260 | for (int i = 0; i < redoitem.ObjectData.Length; i++) | ||
7261 | { | ||
7262 | UUID objiD = redoitem.ObjectData[i].ObjectID; | ||
7263 | AgentSit handlerOnRedo = OnRedo; | ||
7264 | if (handlerOnRedo != null) | ||
7265 | { | ||
7266 | handlerOnRedo(this, objiD); | ||
7267 | } | ||
7268 | |||
7269 | } | ||
7270 | } | ||
7271 | return true; | ||
7272 | } | ||
7273 | |||
7274 | private bool HandleObjectDuplicateOnRay(IClientAPI sender, Packet Pack) | ||
7275 | { | ||
7276 | ObjectDuplicateOnRayPacket dupeOnRay = (ObjectDuplicateOnRayPacket)Pack; | ||
7277 | |||
7278 | #region Packet Session and User Check | ||
7279 | if (m_checkPackets) | ||
7280 | { | ||
7281 | if (dupeOnRay.AgentData.SessionID != SessionId || | ||
7282 | dupeOnRay.AgentData.AgentID != AgentId) | ||
7283 | return true; | ||
7284 | } | ||
7285 | #endregion | ||
7286 | |||
7287 | ObjectDuplicateOnRay handlerObjectDuplicateOnRay = null; | ||
7288 | |||
7289 | for (int i = 0; i < dupeOnRay.ObjectData.Length; i++) | ||
7290 | { | ||
7291 | handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay; | ||
7292 | if (handlerObjectDuplicateOnRay != null) | ||
7293 | { | ||
7294 | handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, | ||
7295 | AgentId, m_activeGroupID, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, | ||
7296 | dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, | ||
7297 | dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); | ||
7298 | } | ||
7299 | } | ||
7300 | |||
7301 | return true; | ||
7302 | } | ||
7303 | |||
7304 | private bool HandleRequestObjectPropertiesFamily(IClientAPI sender, Packet Pack) | ||
7305 | { | ||
7306 | //This powers the little tooltip that appears when you move your mouse over an object | ||
7307 | RequestObjectPropertiesFamilyPacket packToolTip = (RequestObjectPropertiesFamilyPacket)Pack; | ||
7308 | |||
7309 | #region Packet Session and User Check | ||
7310 | if (m_checkPackets) | ||
7311 | { | ||
7312 | if (packToolTip.AgentData.SessionID != SessionId || | ||
7313 | packToolTip.AgentData.AgentID != AgentId) | ||
7314 | return true; | ||
7315 | } | ||
7316 | #endregion | ||
7317 | |||
7318 | RequestObjectPropertiesFamilyPacket.ObjectDataBlock packObjBlock = packToolTip.ObjectData; | ||
7319 | |||
7320 | RequestObjectPropertiesFamily handlerRequestObjectPropertiesFamily = OnRequestObjectPropertiesFamily; | ||
7321 | |||
7322 | if (handlerRequestObjectPropertiesFamily != null) | ||
7323 | { | ||
7324 | handlerRequestObjectPropertiesFamily(this, m_agentId, packObjBlock.RequestFlags, | ||
7325 | packObjBlock.ObjectID); | ||
7326 | } | ||
7327 | |||
7328 | return true; | ||
7329 | } | ||
7330 | |||
7331 | private bool HandleObjectIncludeInSearch(IClientAPI sender, Packet Pack) | ||
7332 | { | ||
7333 | //This lets us set objects to appear in search (stuff like DataSnapshot, etc) | ||
7334 | ObjectIncludeInSearchPacket packInSearch = (ObjectIncludeInSearchPacket)Pack; | ||
7335 | ObjectIncludeInSearch handlerObjectIncludeInSearch = null; | ||
7336 | |||
7337 | #region Packet Session and User Check | ||
7338 | if (m_checkPackets) | ||
7339 | { | ||
7340 | if (packInSearch.AgentData.SessionID != SessionId || | ||
7341 | packInSearch.AgentData.AgentID != AgentId) | ||
7342 | return true; | ||
7343 | } | ||
7344 | #endregion | ||
7345 | |||
7346 | foreach (ObjectIncludeInSearchPacket.ObjectDataBlock objData in packInSearch.ObjectData) | ||
7347 | { | ||
7348 | bool inSearch = objData.IncludeInSearch; | ||
7349 | uint localID = objData.ObjectLocalID; | ||
7350 | |||
7351 | handlerObjectIncludeInSearch = OnObjectIncludeInSearch; | ||
7352 | |||
7353 | if (handlerObjectIncludeInSearch != null) | ||
7354 | { | ||
7355 | handlerObjectIncludeInSearch(this, inSearch, localID); | ||
7356 | } | ||
7357 | } | ||
7358 | return true; | ||
7359 | } | ||
7360 | |||
7361 | private bool HandleScriptAnswerYes(IClientAPI sender, Packet Pack) | ||
7362 | { | ||
7363 | ScriptAnswerYesPacket scriptAnswer = (ScriptAnswerYesPacket)Pack; | ||
7364 | |||
7365 | #region Packet Session and User Check | ||
7366 | if (m_checkPackets) | ||
7367 | { | ||
7368 | if (scriptAnswer.AgentData.SessionID != SessionId || | ||
7369 | scriptAnswer.AgentData.AgentID != AgentId) | ||
7370 | return true; | ||
7371 | } | ||
7372 | #endregion | ||
7373 | |||
7374 | ScriptAnswer handlerScriptAnswer = OnScriptAnswer; | ||
7375 | if (handlerScriptAnswer != null) | ||
7376 | { | ||
7377 | handlerScriptAnswer(this, scriptAnswer.Data.TaskID, scriptAnswer.Data.ItemID, scriptAnswer.Data.Questions); | ||
7378 | } | ||
7379 | return true; | ||
7380 | } | ||
7381 | |||
7382 | private bool HandleObjectClickAction(IClientAPI sender, Packet Pack) | ||
7383 | { | ||
7384 | ObjectClickActionPacket ocpacket = (ObjectClickActionPacket)Pack; | ||
7385 | |||
7386 | #region Packet Session and User Check | ||
7387 | if (m_checkPackets) | ||
7388 | { | ||
7389 | if (ocpacket.AgentData.SessionID != SessionId || | ||
7390 | ocpacket.AgentData.AgentID != AgentId) | ||
7391 | return true; | ||
7392 | } | ||
7393 | #endregion | ||
7394 | |||
7395 | GenericCall7 handlerObjectClickAction = OnObjectClickAction; | ||
7396 | if (handlerObjectClickAction != null) | ||
7397 | { | ||
7398 | foreach (ObjectClickActionPacket.ObjectDataBlock odata in ocpacket.ObjectData) | ||
7399 | { | ||
7400 | byte action = odata.ClickAction; | ||
7401 | uint localID = odata.ObjectLocalID; | ||
7402 | handlerObjectClickAction(this, localID, action.ToString()); | ||
7403 | } | ||
7404 | } | ||
7405 | return true; | ||
7406 | } | ||
7407 | |||
7408 | private bool HandleObjectMaterial(IClientAPI sender, Packet Pack) | ||
7409 | { | ||
7410 | ObjectMaterialPacket ompacket = (ObjectMaterialPacket)Pack; | ||
7411 | |||
7412 | #region Packet Session and User Check | ||
7413 | if (m_checkPackets) | ||
7414 | { | ||
7415 | if (ompacket.AgentData.SessionID != SessionId || | ||
7416 | ompacket.AgentData.AgentID != AgentId) | ||
7417 | return true; | ||
7418 | } | ||
7419 | #endregion | ||
7420 | |||
7421 | GenericCall7 handlerObjectMaterial = OnObjectMaterial; | ||
7422 | if (handlerObjectMaterial != null) | ||
7423 | { | ||
7424 | foreach (ObjectMaterialPacket.ObjectDataBlock odata in ompacket.ObjectData) | ||
7425 | { | ||
7426 | byte material = odata.Material; | ||
7427 | uint localID = odata.ObjectLocalID; | ||
7428 | handlerObjectMaterial(this, localID, material.ToString()); | ||
7429 | } | ||
7430 | } | ||
7431 | return true; | ||
7432 | } | ||
7433 | |||
7434 | #endregion Objects/m_sceneObjects | ||
7435 | |||
7436 | #region Inventory/Asset/Other related packets | ||
7437 | |||
7438 | private bool HandleRequestImage(IClientAPI sender, Packet Pack) | ||
7439 | { | ||
7440 | RequestImagePacket imageRequest = (RequestImagePacket)Pack; | ||
7441 | //m_log.Debug("image request: " + Pack.ToString()); | ||
7442 | |||
7443 | #region Packet Session and User Check | ||
7444 | if (m_checkPackets) | ||
7445 | { | ||
7446 | if (imageRequest.AgentData.SessionID != SessionId || | ||
7447 | imageRequest.AgentData.AgentID != AgentId) | ||
7448 | return true; | ||
7449 | } | ||
7450 | #endregion | ||
7451 | |||
7452 | //handlerTextureRequest = null; | ||
7453 | for (int i = 0; i < imageRequest.RequestImage.Length; i++) | ||
7454 | { | ||
7455 | TextureRequestArgs args = new TextureRequestArgs(); | ||
7456 | |||
7457 | RequestImagePacket.RequestImageBlock block = imageRequest.RequestImage[i]; | ||
7458 | |||
7459 | args.RequestedAssetID = block.Image; | ||
7460 | args.DiscardLevel = block.DiscardLevel; | ||
7461 | args.PacketNumber = block.Packet; | ||
7462 | args.Priority = block.DownloadPriority; | ||
7463 | args.requestSequence = imageRequest.Header.Sequence; | ||
7464 | |||
7465 | // NOTE: This is not a built in part of the LLUDP protocol, but we double the | ||
7466 | // priority of avatar textures to get avatars rezzing in faster than the | ||
7467 | // surrounding scene | ||
7468 | if ((ImageType)block.Type == ImageType.Baked) | ||
7469 | args.Priority *= 2.0f; | ||
7470 | |||
7471 | // in the end, we null this, so we have to check if it's null | ||
7472 | if (m_imageManager != null) | ||
7473 | { | ||
7474 | m_imageManager.EnqueueReq(args); | ||
7475 | } | ||
7476 | } | ||
7477 | return true; | ||
7478 | } | ||
7479 | |||
7480 | /// <summary> | ||
7481 | /// This is the entry point for the UDP route by which the client can retrieve asset data. If the request | ||
7482 | /// is successful then a TransferInfo packet will be sent back, followed by one or more TransferPackets | ||
7483 | /// </summary> | ||
7484 | /// <param name="sender"></param> | ||
7485 | /// <param name="Pack"></param> | ||
7486 | /// <returns>This parameter may be ignored since we appear to return true whatever happens</returns> | ||
7487 | private bool HandleTransferRequest(IClientAPI sender, Packet Pack) | ||
7488 | { | ||
7489 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); | ||
7490 | |||
7491 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | ||
7492 | //m_log.Debug("Transfer Request: " + transfer.ToString()); | ||
7493 | // Validate inventory transfers | ||
7494 | // Has to be done here, because AssetCache can't do it | ||
7495 | // | ||
7496 | UUID taskID = UUID.Zero; | ||
7497 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | ||
7498 | { | ||
7499 | taskID = new UUID(transfer.TransferInfo.Params, 48); | ||
7500 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); | ||
7501 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); | ||
7502 | |||
7503 | // m_log.DebugFormat( | ||
7504 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", | ||
7505 | // requestID, itemID, taskID, Name); | ||
7506 | |||
7507 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) | ||
7508 | { | ||
7509 | if (taskID != UUID.Zero) // Prim | ||
7510 | { | ||
7511 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); | ||
7512 | |||
7513 | if (part == null) | ||
7514 | { | ||
7515 | m_log.WarnFormat( | ||
7516 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", | ||
7517 | Name, requestID, itemID, taskID); | ||
7518 | return true; | ||
7519 | } | ||
7520 | |||
7521 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); | ||
7522 | if (tii == null) | ||
7523 | { | ||
7524 | m_log.WarnFormat( | ||
7525 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", | ||
7526 | Name, requestID, itemID, taskID); | ||
7527 | return true; | ||
7528 | } | ||
7529 | |||
7530 | if (tii.Type == (int)AssetType.LSLText) | ||
7531 | { | ||
7532 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | ||
7533 | return true; | ||
7534 | } | ||
7535 | else if (tii.Type == (int)AssetType.Notecard) | ||
7536 | { | ||
7537 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
7538 | return true; | ||
7539 | } | ||
7540 | else | ||
7541 | { | ||
7542 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
7543 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
7544 | if (part.OwnerID != AgentId) | ||
7545 | { | ||
7546 | m_log.WarnFormat( | ||
7547 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
7548 | Name, requestID, itemID, taskID, part.OwnerID); | ||
7549 | return true; | ||
7550 | } | ||
7551 | |||
7552 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | ||
7553 | { | ||
7554 | m_log.WarnFormat( | ||
7555 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", | ||
7556 | Name, requestID, itemID, taskID); | ||
7557 | return true; | ||
7558 | } | ||
7559 | |||
7560 | if (tii.OwnerID != AgentId) | ||
7561 | { | ||
7562 | m_log.WarnFormat( | ||
7563 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", | ||
7564 | Name, requestID, itemID, taskID, tii.OwnerID); | ||
7565 | return true; | ||
7566 | } | ||
7567 | |||
7568 | if (( | ||
7569 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
7570 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
7571 | { | ||
7572 | m_log.WarnFormat( | ||
7573 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | ||
7574 | Name, requestID, itemID, taskID); | ||
7575 | return true; | ||
7576 | } | ||
7577 | |||
7578 | if (tii.AssetID != requestID) | ||
7579 | { | ||
7580 | m_log.WarnFormat( | ||
7581 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | ||
7582 | Name, requestID, itemID, taskID, tii.AssetID); | ||
7583 | return true; | ||
7584 | } | ||
7585 | } | ||
7586 | } | ||
7587 | else // Agent | ||
7588 | { | ||
7589 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
7590 | if (invAccess != null) | ||
7591 | { | ||
7592 | if (!invAccess.GetAgentInventoryItem(this, itemID, requestID)) | ||
7593 | return false; | ||
7594 | |||
7595 | } | ||
7596 | else | ||
7597 | return false; | ||
7598 | |||
7599 | } | ||
7600 | } | ||
7601 | } | ||
7602 | |||
7603 | MakeAssetRequest(transfer, taskID); | ||
7604 | |||
7605 | return true; | ||
7606 | } | ||
7607 | |||
7608 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) | ||
7609 | { | ||
7610 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | ||
7611 | |||
7612 | |||
7613 | // m_log.Debug("upload request " + request.ToString()); | ||
7614 | // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); | ||
7615 | UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); | ||
7616 | |||
7617 | UDPAssetUploadRequest handlerAssetUploadRequest = OnAssetUploadRequest; | ||
7618 | |||
7619 | if (handlerAssetUploadRequest != null) | ||
7620 | { | ||
7621 | handlerAssetUploadRequest(this, temp, | ||
7622 | request.AssetBlock.TransactionID, request.AssetBlock.Type, | ||
7623 | request.AssetBlock.AssetData, request.AssetBlock.StoreLocal, | ||
7624 | request.AssetBlock.Tempfile); | ||
7625 | } | ||
7626 | return true; | ||
7627 | } | ||
7628 | |||
7629 | private bool HandleRequestXfer(IClientAPI sender, Packet Pack) | ||
7630 | { | ||
7631 | RequestXferPacket xferReq = (RequestXferPacket)Pack; | ||
7632 | |||
7633 | RequestXfer handlerRequestXfer = OnRequestXfer; | ||
7634 | |||
7635 | if (handlerRequestXfer != null) | ||
7636 | { | ||
7637 | handlerRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename)); | ||
7638 | } | ||
7639 | return true; | ||
7640 | } | ||
7641 | |||
7642 | private bool HandleSendXferPacket(IClientAPI sender, Packet Pack) | ||
7643 | { | ||
7644 | SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack; | ||
7645 | |||
7646 | XferReceive handlerXferReceive = OnXferReceive; | ||
7647 | if (handlerXferReceive != null) | ||
7648 | { | ||
7649 | handlerXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data); | ||
7650 | } | ||
7651 | return true; | ||
7652 | } | ||
7653 | |||
7654 | private bool HandleConfirmXferPacket(IClientAPI sender, Packet Pack) | ||
7655 | { | ||
7656 | ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; | ||
7657 | |||
7658 | ConfirmXfer handlerConfirmXfer = OnConfirmXfer; | ||
7659 | if (handlerConfirmXfer != null) | ||
7660 | { | ||
7661 | handlerConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet); | ||
7662 | } | ||
7663 | return true; | ||
7664 | } | ||
7665 | |||
7666 | private bool HandleAbortXfer(IClientAPI sender, Packet Pack) | ||
7667 | { | ||
7668 | AbortXferPacket abortXfer = (AbortXferPacket)Pack; | ||
7669 | AbortXfer handlerAbortXfer = OnAbortXfer; | ||
7670 | if (handlerAbortXfer != null) | ||
7671 | { | ||
7672 | handlerAbortXfer(this, abortXfer.XferID.ID); | ||
7673 | } | ||
7674 | |||
7675 | return true; | ||
7676 | } | ||
7677 | |||
7678 | private bool HandleCreateInventoryFolder(IClientAPI sender, Packet Pack) | ||
7679 | { | ||
7680 | CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack; | ||
7681 | |||
7682 | #region Packet Session and User Check | ||
7683 | if (m_checkPackets) | ||
7684 | { | ||
7685 | if (invFolder.AgentData.SessionID != SessionId || | ||
7686 | invFolder.AgentData.AgentID != AgentId) | ||
7687 | return true; | ||
7688 | } | ||
7689 | #endregion | ||
7690 | |||
7691 | CreateInventoryFolder handlerCreateInventoryFolder = OnCreateNewInventoryFolder; | ||
7692 | if (handlerCreateInventoryFolder != null) | ||
7693 | { | ||
7694 | handlerCreateInventoryFolder(this, invFolder.FolderData.FolderID, | ||
7695 | (ushort)invFolder.FolderData.Type, | ||
7696 | Util.FieldToString(invFolder.FolderData.Name), | ||
7697 | invFolder.FolderData.ParentID); | ||
7698 | } | ||
7699 | return true; | ||
7700 | } | ||
7701 | |||
7702 | private bool HandleUpdateInventoryFolder(IClientAPI sender, Packet Pack) | ||
7703 | { | ||
7704 | if (OnUpdateInventoryFolder != null) | ||
7705 | { | ||
7706 | UpdateInventoryFolderPacket invFolderx = (UpdateInventoryFolderPacket)Pack; | ||
7707 | |||
7708 | #region Packet Session and User Check | ||
7709 | if (m_checkPackets) | ||
7710 | { | ||
7711 | if (invFolderx.AgentData.SessionID != SessionId || | ||
7712 | invFolderx.AgentData.AgentID != AgentId) | ||
7713 | return true; | ||
7714 | } | ||
7715 | #endregion | ||
7716 | |||
7717 | UpdateInventoryFolder handlerUpdateInventoryFolder = null; | ||
7718 | |||
7719 | for (int i = 0; i < invFolderx.FolderData.Length; i++) | ||
7720 | { | ||
7721 | handlerUpdateInventoryFolder = OnUpdateInventoryFolder; | ||
7722 | if (handlerUpdateInventoryFolder != null) | ||
7723 | { | ||
7724 | OnUpdateInventoryFolder(this, invFolderx.FolderData[i].FolderID, | ||
7725 | (ushort)invFolderx.FolderData[i].Type, | ||
7726 | Util.FieldToString(invFolderx.FolderData[i].Name), | ||
7727 | invFolderx.FolderData[i].ParentID); | ||
7728 | } | ||
7729 | } | ||
7730 | } | ||
7731 | return true; | ||
7732 | } | ||
7733 | |||
7734 | private bool HandleMoveInventoryFolder(IClientAPI sender, Packet Pack) | ||
7735 | { | ||
7736 | if (OnMoveInventoryFolder != null) | ||
7737 | { | ||
7738 | MoveInventoryFolderPacket invFoldery = (MoveInventoryFolderPacket)Pack; | ||
7739 | |||
7740 | #region Packet Session and User Check | ||
7741 | if (m_checkPackets) | ||
7742 | { | ||
7743 | if (invFoldery.AgentData.SessionID != SessionId || | ||
7744 | invFoldery.AgentData.AgentID != AgentId) | ||
7745 | return true; | ||
7746 | } | ||
7747 | #endregion | ||
7748 | |||
7749 | MoveInventoryFolder handlerMoveInventoryFolder = null; | ||
7750 | |||
7751 | for (int i = 0; i < invFoldery.InventoryData.Length; i++) | ||
7752 | { | ||
7753 | handlerMoveInventoryFolder = OnMoveInventoryFolder; | ||
7754 | if (handlerMoveInventoryFolder != null) | ||
7755 | { | ||
7756 | OnMoveInventoryFolder(this, invFoldery.InventoryData[i].FolderID, | ||
7757 | invFoldery.InventoryData[i].ParentID); | ||
7758 | } | ||
7759 | } | ||
7760 | } | ||
7761 | return true; | ||
7762 | } | ||
7763 | |||
7764 | private bool HandleCreateInventoryItem(IClientAPI sender, Packet Pack) | ||
7765 | { | ||
7766 | CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; | ||
7767 | |||
7768 | #region Packet Session and User Check | ||
7769 | if (m_checkPackets) | ||
7770 | { | ||
7771 | if (createItem.AgentData.SessionID != SessionId || | ||
7772 | createItem.AgentData.AgentID != AgentId) | ||
7773 | return true; | ||
7774 | } | ||
7775 | #endregion | ||
7776 | |||
7777 | CreateNewInventoryItem handlerCreateNewInventoryItem = OnCreateNewInventoryItem; | ||
7778 | if (handlerCreateNewInventoryItem != null) | ||
7779 | { | ||
7780 | handlerCreateNewInventoryItem(this, createItem.InventoryBlock.TransactionID, | ||
7781 | createItem.InventoryBlock.FolderID, | ||
7782 | createItem.InventoryBlock.CallbackID, | ||
7783 | Util.FieldToString(createItem.InventoryBlock.Description), | ||
7784 | Util.FieldToString(createItem.InventoryBlock.Name), | ||
7785 | createItem.InventoryBlock.InvType, | ||
7786 | createItem.InventoryBlock.Type, | ||
7787 | createItem.InventoryBlock.WearableType, | ||
7788 | createItem.InventoryBlock.NextOwnerMask, | ||
7789 | Util.UnixTimeSinceEpoch()); | ||
7790 | } | ||
7791 | return true; | ||
7792 | } | ||
7793 | |||
7794 | private bool HandleLinkInventoryItem(IClientAPI sender, Packet Pack) | ||
7795 | { | ||
7796 | LinkInventoryItemPacket createLink = (LinkInventoryItemPacket)Pack; | ||
7797 | |||
7798 | #region Packet Session and User Check | ||
7799 | if (m_checkPackets) | ||
7800 | { | ||
7801 | if (createLink.AgentData.SessionID != SessionId || | ||
7802 | createLink.AgentData.AgentID != AgentId) | ||
7803 | return true; | ||
7804 | } | ||
7805 | #endregion | ||
7806 | |||
7807 | LinkInventoryItem linkInventoryItem = OnLinkInventoryItem; | ||
7808 | |||
7809 | if (linkInventoryItem != null) | ||
7810 | { | ||
7811 | linkInventoryItem( | ||
7812 | this, | ||
7813 | createLink.InventoryBlock.TransactionID, | ||
7814 | createLink.InventoryBlock.FolderID, | ||
7815 | createLink.InventoryBlock.CallbackID, | ||
7816 | Util.FieldToString(createLink.InventoryBlock.Description), | ||
7817 | Util.FieldToString(createLink.InventoryBlock.Name), | ||
7818 | createLink.InventoryBlock.InvType, | ||
7819 | createLink.InventoryBlock.Type, | ||
7820 | createLink.InventoryBlock.OldItemID); | ||
7821 | } | ||
7822 | |||
7823 | return true; | ||
7824 | } | ||
7825 | |||
7826 | private bool HandleFetchInventory(IClientAPI sender, Packet Pack) | ||
7827 | { | ||
7828 | if (OnFetchInventory != null) | ||
7829 | { | ||
7830 | FetchInventoryPacket FetchInventoryx = (FetchInventoryPacket)Pack; | ||
7831 | |||
7832 | #region Packet Session and User Check | ||
7833 | if (m_checkPackets) | ||
7834 | { | ||
7835 | if (FetchInventoryx.AgentData.SessionID != SessionId || | ||
7836 | FetchInventoryx.AgentData.AgentID != AgentId) | ||
7837 | return true; | ||
7838 | } | ||
7839 | #endregion | ||
7840 | |||
7841 | FetchInventory handlerFetchInventory = null; | ||
7842 | |||
7843 | for (int i = 0; i < FetchInventoryx.InventoryData.Length; i++) | ||
7844 | { | ||
7845 | handlerFetchInventory = OnFetchInventory; | ||
7846 | |||
7847 | if (handlerFetchInventory != null) | ||
7848 | { | ||
7849 | OnFetchInventory(this, FetchInventoryx.InventoryData[i].ItemID, | ||
7850 | FetchInventoryx.InventoryData[i].OwnerID); | ||
7851 | } | ||
7852 | } | ||
7853 | } | ||
7854 | return true; | ||
7855 | } | ||
7856 | |||
7857 | private bool HandleFetchInventoryDescendents(IClientAPI sender, Packet Pack) | ||
7858 | { | ||
7859 | FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack; | ||
7860 | |||
7861 | #region Packet Session and User Check | ||
7862 | if (m_checkPackets) | ||
7863 | { | ||
7864 | if (Fetch.AgentData.SessionID != SessionId || | ||
7865 | Fetch.AgentData.AgentID != AgentId) | ||
7866 | return true; | ||
7867 | } | ||
7868 | #endregion | ||
7869 | |||
7870 | FetchInventoryDescendents handlerFetchInventoryDescendents = OnFetchInventoryDescendents; | ||
7871 | if (handlerFetchInventoryDescendents != null) | ||
7872 | { | ||
7873 | handlerFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID, | ||
7874 | Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems, | ||
7875 | Fetch.InventoryData.SortOrder); | ||
7876 | } | ||
7877 | return true; | ||
7878 | } | ||
7879 | |||
7880 | private bool HandlePurgeInventoryDescendents(IClientAPI sender, Packet Pack) | ||
7881 | { | ||
7882 | PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack; | ||
7883 | |||
7884 | #region Packet Session and User Check | ||
7885 | if (m_checkPackets) | ||
7886 | { | ||
7887 | if (Purge.AgentData.SessionID != SessionId || | ||
7888 | Purge.AgentData.AgentID != AgentId) | ||
7889 | return true; | ||
7890 | } | ||
7891 | #endregion | ||
7892 | |||
7893 | PurgeInventoryDescendents handlerPurgeInventoryDescendents = OnPurgeInventoryDescendents; | ||
7894 | if (handlerPurgeInventoryDescendents != null) | ||
7895 | { | ||
7896 | handlerPurgeInventoryDescendents(this, Purge.InventoryData.FolderID); | ||
7897 | } | ||
7898 | return true; | ||
7899 | } | ||
7900 | |||
7901 | private bool HandleUpdateInventoryItem(IClientAPI sender, Packet Pack) | ||
7902 | { | ||
7903 | UpdateInventoryItemPacket inventoryItemUpdate = (UpdateInventoryItemPacket)Pack; | ||
7904 | |||
7905 | #region Packet Session and User Check | ||
7906 | if (m_checkPackets) | ||
7907 | { | ||
7908 | if (inventoryItemUpdate.AgentData.SessionID != SessionId || | ||
7909 | inventoryItemUpdate.AgentData.AgentID != AgentId) | ||
7910 | return true; | ||
7911 | } | ||
7912 | #endregion | ||
7913 | |||
7914 | if (OnUpdateInventoryItem != null) | ||
7915 | { | ||
7916 | UpdateInventoryItem handlerUpdateInventoryItem = null; | ||
7917 | for (int i = 0; i < inventoryItemUpdate.InventoryData.Length; i++) | ||
7918 | { | ||
7919 | handlerUpdateInventoryItem = OnUpdateInventoryItem; | ||
7920 | |||
7921 | if (handlerUpdateInventoryItem != null) | ||
7922 | { | ||
7923 | InventoryItemBase itemUpd = new InventoryItemBase(); | ||
7924 | itemUpd.ID = inventoryItemUpdate.InventoryData[i].ItemID; | ||
7925 | itemUpd.Name = Util.FieldToString(inventoryItemUpdate.InventoryData[i].Name); | ||
7926 | itemUpd.Description = Util.FieldToString(inventoryItemUpdate.InventoryData[i].Description); | ||
7927 | itemUpd.GroupID = inventoryItemUpdate.InventoryData[i].GroupID; | ||
7928 | itemUpd.GroupOwned = inventoryItemUpdate.InventoryData[i].GroupOwned; | ||
7929 | itemUpd.GroupPermissions = inventoryItemUpdate.InventoryData[i].GroupMask; | ||
7930 | itemUpd.NextPermissions = inventoryItemUpdate.InventoryData[i].NextOwnerMask; | ||
7931 | itemUpd.EveryOnePermissions = inventoryItemUpdate.InventoryData[i].EveryoneMask; | ||
7932 | itemUpd.CreationDate = inventoryItemUpdate.InventoryData[i].CreationDate; | ||
7933 | itemUpd.Folder = inventoryItemUpdate.InventoryData[i].FolderID; | ||
7934 | itemUpd.InvType = inventoryItemUpdate.InventoryData[i].InvType; | ||
7935 | itemUpd.SalePrice = inventoryItemUpdate.InventoryData[i].SalePrice; | ||
7936 | itemUpd.SaleType = inventoryItemUpdate.InventoryData[i].SaleType; | ||
7937 | itemUpd.Flags = inventoryItemUpdate.InventoryData[i].Flags; | ||
7938 | |||
7939 | OnUpdateInventoryItem(this, inventoryItemUpdate.InventoryData[i].TransactionID, | ||
7940 | inventoryItemUpdate.InventoryData[i].ItemID, | ||
7941 | itemUpd); | ||
7942 | } | ||
7943 | } | ||
7944 | } | ||
7945 | return true; | ||
7946 | } | ||
7947 | |||
7948 | private bool HandleCopyInventoryItem(IClientAPI sender, Packet Pack) | ||
7949 | { | ||
7950 | CopyInventoryItemPacket copyitem = (CopyInventoryItemPacket)Pack; | ||
7951 | |||
7952 | #region Packet Session and User Check | ||
7953 | if (m_checkPackets) | ||
7954 | { | ||
7955 | if (copyitem.AgentData.SessionID != SessionId || | ||
7956 | copyitem.AgentData.AgentID != AgentId) | ||
7957 | return true; | ||
7958 | } | ||
7959 | #endregion | ||
7960 | |||
7961 | CopyInventoryItem handlerCopyInventoryItem = null; | ||
7962 | if (OnCopyInventoryItem != null) | ||
7963 | { | ||
7964 | foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData) | ||
7965 | { | ||
7966 | handlerCopyInventoryItem = OnCopyInventoryItem; | ||
7967 | if (handlerCopyInventoryItem != null) | ||
7968 | { | ||
7969 | handlerCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID, | ||
7970 | datablock.OldItemID, datablock.NewFolderID, | ||
7971 | Util.FieldToString(datablock.NewName)); | ||
7972 | } | ||
7973 | } | ||
7974 | } | ||
7975 | return true; | ||
7976 | } | ||
7977 | |||
7978 | private bool HandleMoveInventoryItem(IClientAPI sender, Packet Pack) | ||
7979 | { | ||
7980 | MoveInventoryItemPacket moveitem = (MoveInventoryItemPacket)Pack; | ||
7981 | |||
7982 | #region Packet Session and User Check | ||
7983 | if (m_checkPackets) | ||
7984 | { | ||
7985 | if (moveitem.AgentData.SessionID != SessionId || | ||
7986 | moveitem.AgentData.AgentID != AgentId) | ||
7987 | return true; | ||
7988 | } | ||
7989 | #endregion | ||
7990 | |||
7991 | if (OnMoveInventoryItem != null) | ||
7992 | { | ||
7993 | MoveInventoryItem handlerMoveInventoryItem = null; | ||
7994 | InventoryItemBase itm = null; | ||
7995 | List<InventoryItemBase> items = new List<InventoryItemBase>(); | ||
7996 | foreach (MoveInventoryItemPacket.InventoryDataBlock datablock in moveitem.InventoryData) | ||
7997 | { | ||
7998 | itm = new InventoryItemBase(datablock.ItemID, AgentId); | ||
7999 | itm.Folder = datablock.FolderID; | ||
8000 | itm.Name = Util.FieldToString(datablock.NewName); | ||
8001 | // weird, comes out as empty string | ||
8002 | //m_log.DebugFormat("[XXX] new name: {0}", itm.Name); | ||
8003 | items.Add(itm); | ||
8004 | } | ||
8005 | handlerMoveInventoryItem = OnMoveInventoryItem; | ||
8006 | if (handlerMoveInventoryItem != null) | ||
8007 | { | ||
8008 | handlerMoveInventoryItem(this, items); | ||
8009 | } | ||
8010 | } | ||
8011 | return true; | ||
8012 | } | ||
8013 | |||
8014 | private bool HandleRemoveInventoryItem(IClientAPI sender, Packet Pack) | ||
8015 | { | ||
8016 | RemoveInventoryItemPacket removeItem = (RemoveInventoryItemPacket)Pack; | ||
8017 | |||
8018 | #region Packet Session and User Check | ||
8019 | if (m_checkPackets) | ||
8020 | { | ||
8021 | if (removeItem.AgentData.SessionID != SessionId || | ||
8022 | removeItem.AgentData.AgentID != AgentId) | ||
8023 | return true; | ||
8024 | } | ||
8025 | #endregion | ||
8026 | |||
8027 | if (OnRemoveInventoryItem != null) | ||
8028 | { | ||
8029 | RemoveInventoryItem handlerRemoveInventoryItem = null; | ||
8030 | List<UUID> uuids = new List<UUID>(); | ||
8031 | foreach (RemoveInventoryItemPacket.InventoryDataBlock datablock in removeItem.InventoryData) | ||
8032 | { | ||
8033 | uuids.Add(datablock.ItemID); | ||
8034 | } | ||
8035 | handlerRemoveInventoryItem = OnRemoveInventoryItem; | ||
8036 | if (handlerRemoveInventoryItem != null) | ||
8037 | { | ||
8038 | handlerRemoveInventoryItem(this, uuids); | ||
8039 | } | ||
8040 | |||
8041 | } | ||
8042 | return true; | ||
8043 | } | ||
8044 | |||
8045 | private bool HandleRemoveInventoryFolder(IClientAPI sender, Packet Pack) | ||
8046 | { | ||
8047 | RemoveInventoryFolderPacket removeFolder = (RemoveInventoryFolderPacket)Pack; | ||
8048 | |||
8049 | #region Packet Session and User Check | ||
8050 | if (m_checkPackets) | ||
8051 | { | ||
8052 | if (removeFolder.AgentData.SessionID != SessionId || | ||
8053 | removeFolder.AgentData.AgentID != AgentId) | ||
8054 | return true; | ||
8055 | } | ||
8056 | #endregion | ||
8057 | |||
8058 | if (OnRemoveInventoryFolder != null) | ||
8059 | { | ||
8060 | RemoveInventoryFolder handlerRemoveInventoryFolder = null; | ||
8061 | List<UUID> uuids = new List<UUID>(); | ||
8062 | foreach (RemoveInventoryFolderPacket.FolderDataBlock datablock in removeFolder.FolderData) | ||
8063 | { | ||
8064 | uuids.Add(datablock.FolderID); | ||
8065 | } | ||
8066 | handlerRemoveInventoryFolder = OnRemoveInventoryFolder; | ||
8067 | if (handlerRemoveInventoryFolder != null) | ||
8068 | { | ||
8069 | handlerRemoveInventoryFolder(this, uuids); | ||
8070 | } | ||
8071 | } | ||
8072 | return true; | ||
8073 | } | ||
8074 | |||
8075 | private bool HandleRemoveInventoryObjects(IClientAPI sender, Packet Pack) | ||
8076 | { | ||
8077 | RemoveInventoryObjectsPacket removeObject = (RemoveInventoryObjectsPacket)Pack; | ||
8078 | #region Packet Session and User Check | ||
8079 | if (m_checkPackets) | ||
8080 | { | ||
8081 | if (removeObject.AgentData.SessionID != SessionId || | ||
8082 | removeObject.AgentData.AgentID != AgentId) | ||
8083 | return true; | ||
8084 | } | ||
8085 | #endregion | ||
8086 | if (OnRemoveInventoryFolder != null) | ||
8087 | { | ||
8088 | RemoveInventoryFolder handlerRemoveInventoryFolder = null; | ||
8089 | List<UUID> uuids = new List<UUID>(); | ||
8090 | foreach (RemoveInventoryObjectsPacket.FolderDataBlock datablock in removeObject.FolderData) | ||
8091 | { | ||
8092 | uuids.Add(datablock.FolderID); | ||
8093 | } | ||
8094 | handlerRemoveInventoryFolder = OnRemoveInventoryFolder; | ||
8095 | if (handlerRemoveInventoryFolder != null) | ||
8096 | { | ||
8097 | handlerRemoveInventoryFolder(this, uuids); | ||
8098 | } | ||
8099 | } | ||
8100 | |||
8101 | if (OnRemoveInventoryItem != null) | ||
8102 | { | ||
8103 | RemoveInventoryItem handlerRemoveInventoryItem = null; | ||
8104 | List<UUID> uuids = new List<UUID>(); | ||
8105 | foreach (RemoveInventoryObjectsPacket.ItemDataBlock datablock in removeObject.ItemData) | ||
8106 | { | ||
8107 | uuids.Add(datablock.ItemID); | ||
8108 | } | ||
8109 | handlerRemoveInventoryItem = OnRemoveInventoryItem; | ||
8110 | if (handlerRemoveInventoryItem != null) | ||
8111 | { | ||
8112 | handlerRemoveInventoryItem(this, uuids); | ||
8113 | } | ||
8114 | } | ||
8115 | return true; | ||
8116 | } | ||
8117 | |||
8118 | private bool HandleRequestTaskInventory(IClientAPI sender, Packet Pack) | ||
8119 | { | ||
8120 | RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack; | ||
8121 | |||
8122 | #region Packet Session and User Check | ||
8123 | if (m_checkPackets) | ||
8124 | { | ||
8125 | if (requesttask.AgentData.SessionID != SessionId || | ||
8126 | requesttask.AgentData.AgentID != AgentId) | ||
8127 | return true; | ||
8128 | } | ||
8129 | #endregion | ||
8130 | |||
8131 | RequestTaskInventory handlerRequestTaskInventory = OnRequestTaskInventory; | ||
8132 | if (handlerRequestTaskInventory != null) | ||
8133 | { | ||
8134 | handlerRequestTaskInventory(this, requesttask.InventoryData.LocalID); | ||
8135 | } | ||
8136 | return true; | ||
8137 | } | ||
8138 | |||
8139 | private bool HandleUpdateTaskInventory(IClientAPI sender, Packet Pack) | ||
8140 | { | ||
8141 | UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack; | ||
8142 | |||
8143 | #region Packet Session and User Check | ||
8144 | if (m_checkPackets) | ||
8145 | { | ||
8146 | if (updatetask.AgentData.SessionID != SessionId || | ||
8147 | updatetask.AgentData.AgentID != AgentId) | ||
8148 | return true; | ||
8149 | } | ||
8150 | #endregion | ||
8151 | |||
8152 | if (OnUpdateTaskInventory != null) | ||
8153 | { | ||
8154 | if (updatetask.UpdateData.Key == 0) | ||
8155 | { | ||
8156 | UpdateTaskInventory handlerUpdateTaskInventory = OnUpdateTaskInventory; | ||
8157 | if (handlerUpdateTaskInventory != null) | ||
8158 | { | ||
8159 | TaskInventoryItem newTaskItem = new TaskInventoryItem(); | ||
8160 | newTaskItem.ItemID = updatetask.InventoryData.ItemID; | ||
8161 | newTaskItem.ParentID = updatetask.InventoryData.FolderID; | ||
8162 | newTaskItem.CreatorID = updatetask.InventoryData.CreatorID; | ||
8163 | newTaskItem.OwnerID = updatetask.InventoryData.OwnerID; | ||
8164 | newTaskItem.GroupID = updatetask.InventoryData.GroupID; | ||
8165 | newTaskItem.BasePermissions = updatetask.InventoryData.BaseMask; | ||
8166 | newTaskItem.CurrentPermissions = updatetask.InventoryData.OwnerMask; | ||
8167 | newTaskItem.GroupPermissions = updatetask.InventoryData.GroupMask; | ||
8168 | newTaskItem.EveryonePermissions = updatetask.InventoryData.EveryoneMask; | ||
8169 | newTaskItem.NextPermissions = updatetask.InventoryData.NextOwnerMask; | ||
8170 | |||
8171 | // Unused? Clicking share with group sets GroupPermissions instead, so perhaps this is something | ||
8172 | // different | ||
8173 | //newTaskItem.GroupOwned=updatetask.InventoryData.GroupOwned; | ||
8174 | newTaskItem.Type = updatetask.InventoryData.Type; | ||
8175 | newTaskItem.InvType = updatetask.InventoryData.InvType; | ||
8176 | newTaskItem.Flags = updatetask.InventoryData.Flags; | ||
8177 | //newTaskItem.SaleType=updatetask.InventoryData.SaleType; | ||
8178 | //newTaskItem.SalePrice=updatetask.InventoryData.SalePrice; | ||
8179 | newTaskItem.Name = Util.FieldToString(updatetask.InventoryData.Name); | ||
8180 | newTaskItem.Description = Util.FieldToString(updatetask.InventoryData.Description); | ||
8181 | newTaskItem.CreationDate = (uint)updatetask.InventoryData.CreationDate; | ||
8182 | handlerUpdateTaskInventory(this, updatetask.InventoryData.TransactionID, | ||
8183 | newTaskItem, updatetask.UpdateData.LocalID); | ||
8184 | } | ||
8185 | } | ||
8186 | } | ||
8187 | |||
8188 | return true; | ||
8189 | } | ||
8190 | |||
8191 | private bool HandleRemoveTaskInventory(IClientAPI sender, Packet Pack) | ||
8192 | { | ||
8193 | RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket)Pack; | ||
8194 | |||
8195 | #region Packet Session and User Check | ||
8196 | if (m_checkPackets) | ||
8197 | { | ||
8198 | if (removeTask.AgentData.SessionID != SessionId || | ||
8199 | removeTask.AgentData.AgentID != AgentId) | ||
8200 | return true; | ||
8201 | } | ||
8202 | #endregion | ||
8203 | |||
8204 | RemoveTaskInventory handlerRemoveTaskItem = OnRemoveTaskItem; | ||
8205 | |||
8206 | if (handlerRemoveTaskItem != null) | ||
8207 | { | ||
8208 | handlerRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID); | ||
8209 | } | ||
8210 | |||
8211 | return true; | ||
8212 | } | ||
8213 | |||
8214 | private bool HandleMoveTaskInventory(IClientAPI sender, Packet Pack) | ||
8215 | { | ||
8216 | MoveTaskInventoryPacket moveTaskInventoryPacket = (MoveTaskInventoryPacket)Pack; | ||
8217 | |||
8218 | #region Packet Session and User Check | ||
8219 | if (m_checkPackets) | ||
8220 | { | ||
8221 | if (moveTaskInventoryPacket.AgentData.SessionID != SessionId || | ||
8222 | moveTaskInventoryPacket.AgentData.AgentID != AgentId) | ||
8223 | return true; | ||
8224 | } | ||
8225 | #endregion | ||
8226 | |||
8227 | MoveTaskInventory handlerMoveTaskItem = OnMoveTaskItem; | ||
8228 | |||
8229 | if (handlerMoveTaskItem != null) | ||
8230 | { | ||
8231 | handlerMoveTaskItem( | ||
8232 | this, moveTaskInventoryPacket.AgentData.FolderID, | ||
8233 | moveTaskInventoryPacket.InventoryData.LocalID, | ||
8234 | moveTaskInventoryPacket.InventoryData.ItemID); | ||
8235 | } | ||
8236 | |||
8237 | return true; | ||
8238 | } | ||
8239 | |||
8240 | private bool HandleRezScript(IClientAPI sender, Packet Pack) | ||
8241 | { | ||
8242 | //m_log.Debug(Pack.ToString()); | ||
8243 | RezScriptPacket rezScriptx = (RezScriptPacket)Pack; | ||
8244 | |||
8245 | #region Packet Session and User Check | ||
8246 | if (m_checkPackets) | ||
8247 | { | ||
8248 | if (rezScriptx.AgentData.SessionID != SessionId || | ||
8249 | rezScriptx.AgentData.AgentID != AgentId) | ||
8250 | return true; | ||
8251 | } | ||
8252 | #endregion | ||
8253 | |||
8254 | RezScript handlerRezScript = OnRezScript; | ||
8255 | InventoryItemBase item = new InventoryItemBase(); | ||
8256 | item.ID = rezScriptx.InventoryBlock.ItemID; | ||
8257 | item.Folder = rezScriptx.InventoryBlock.FolderID; | ||
8258 | item.CreatorId = rezScriptx.InventoryBlock.CreatorID.ToString(); | ||
8259 | item.Owner = rezScriptx.InventoryBlock.OwnerID; | ||
8260 | item.BasePermissions = rezScriptx.InventoryBlock.BaseMask; | ||
8261 | item.CurrentPermissions = rezScriptx.InventoryBlock.OwnerMask; | ||
8262 | item.EveryOnePermissions = rezScriptx.InventoryBlock.EveryoneMask; | ||
8263 | item.NextPermissions = rezScriptx.InventoryBlock.NextOwnerMask; | ||
8264 | item.GroupPermissions = rezScriptx.InventoryBlock.GroupMask; | ||
8265 | item.GroupOwned = rezScriptx.InventoryBlock.GroupOwned; | ||
8266 | item.GroupID = rezScriptx.InventoryBlock.GroupID; | ||
8267 | item.AssetType = rezScriptx.InventoryBlock.Type; | ||
8268 | item.InvType = rezScriptx.InventoryBlock.InvType; | ||
8269 | item.Flags = rezScriptx.InventoryBlock.Flags; | ||
8270 | item.SaleType = rezScriptx.InventoryBlock.SaleType; | ||
8271 | item.SalePrice = rezScriptx.InventoryBlock.SalePrice; | ||
8272 | item.Name = Util.FieldToString(rezScriptx.InventoryBlock.Name); | ||
8273 | item.Description = Util.FieldToString(rezScriptx.InventoryBlock.Description); | ||
8274 | item.CreationDate = rezScriptx.InventoryBlock.CreationDate; | ||
8275 | |||
8276 | if (handlerRezScript != null) | ||
8277 | { | ||
8278 | handlerRezScript(this, item, rezScriptx.InventoryBlock.TransactionID, rezScriptx.UpdateBlock.ObjectLocalID); | ||
8279 | } | ||
8280 | return true; | ||
8281 | } | ||
8282 | |||
8283 | private bool HandleMapLayerRequest(IClientAPI sender, Packet Pack) | ||
8284 | { | ||
8285 | RequestMapLayer(); | ||
8286 | return true; | ||
8287 | } | ||
8288 | |||
8289 | private bool HandleMapBlockRequest(IClientAPI sender, Packet Pack) | ||
8290 | { | ||
8291 | MapBlockRequestPacket MapRequest = (MapBlockRequestPacket)Pack; | ||
8292 | |||
8293 | #region Packet Session and User Check | ||
8294 | if (m_checkPackets) | ||
8295 | { | ||
8296 | if (MapRequest.AgentData.SessionID != SessionId || | ||
8297 | MapRequest.AgentData.AgentID != AgentId) | ||
8298 | return true; | ||
8299 | } | ||
8300 | #endregion | ||
8301 | |||
8302 | RequestMapBlocks handlerRequestMapBlocks = OnRequestMapBlocks; | ||
8303 | if (handlerRequestMapBlocks != null) | ||
8304 | { | ||
8305 | handlerRequestMapBlocks(this, MapRequest.PositionData.MinX, MapRequest.PositionData.MinY, | ||
8306 | MapRequest.PositionData.MaxX, MapRequest.PositionData.MaxY, MapRequest.AgentData.Flags); | ||
8307 | } | ||
8308 | return true; | ||
8309 | } | ||
8310 | |||
8311 | private bool HandleMapNameRequest(IClientAPI sender, Packet Pack) | ||
8312 | { | ||
8313 | MapNameRequestPacket map = (MapNameRequestPacket)Pack; | ||
8314 | |||
8315 | #region Packet Session and User Check | ||
8316 | if (m_checkPackets) | ||
8317 | { | ||
8318 | if (map.AgentData.SessionID != SessionId || | ||
8319 | map.AgentData.AgentID != AgentId) | ||
8320 | return true; | ||
8321 | } | ||
8322 | #endregion | ||
8323 | |||
8324 | string mapName = Util.UTF8.GetString(map.NameData.Name, 0, | ||
8325 | map.NameData.Name.Length - 1); | ||
8326 | RequestMapName handlerMapNameRequest = OnMapNameRequest; | ||
8327 | if (handlerMapNameRequest != null) | ||
8328 | { | ||
8329 | handlerMapNameRequest(this, mapName); | ||
8330 | } | ||
8331 | return true; | ||
8332 | } | ||
8333 | |||
8334 | private bool HandleTeleportLandmarkRequest(IClientAPI sender, Packet Pack) | ||
8335 | { | ||
8336 | TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack; | ||
8337 | |||
8338 | #region Packet Session and User Check | ||
8339 | if (m_checkPackets) | ||
8340 | { | ||
8341 | if (tpReq.Info.SessionID != SessionId || | ||
8342 | tpReq.Info.AgentID != AgentId) | ||
8343 | return true; | ||
8344 | } | ||
8345 | #endregion | ||
8346 | |||
8347 | UUID lmid = tpReq.Info.LandmarkID; | ||
8348 | AssetLandmark lm; | ||
8349 | if (lmid != UUID.Zero) | ||
8350 | { | ||
8351 | //AssetBase lma = m_assetCache.GetAsset(lmid, false); | ||
8352 | AssetBase lma = m_assetService.Get(lmid.ToString()); | ||
8353 | |||
8354 | if (lma == null) | ||
8355 | { | ||
8356 | // Failed to find landmark | ||
8357 | TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); | ||
8358 | tpCancel.Info.SessionID = tpReq.Info.SessionID; | ||
8359 | tpCancel.Info.AgentID = tpReq.Info.AgentID; | ||
8360 | OutPacket(tpCancel, ThrottleOutPacketType.Task); | ||
8361 | } | ||
8362 | |||
8363 | try | ||
8364 | { | ||
8365 | lm = new AssetLandmark(lma); | ||
8366 | } | ||
8367 | catch (NullReferenceException) | ||
8368 | { | ||
8369 | // asset not found generates null ref inside the assetlandmark constructor. | ||
8370 | TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); | ||
8371 | tpCancel.Info.SessionID = tpReq.Info.SessionID; | ||
8372 | tpCancel.Info.AgentID = tpReq.Info.AgentID; | ||
8373 | OutPacket(tpCancel, ThrottleOutPacketType.Task); | ||
8374 | return true; | ||
8375 | } | ||
8376 | } | ||
8377 | else | ||
8378 | { | ||
8379 | // Teleport home request | ||
8380 | UUIDNameRequest handlerTeleportHomeRequest = OnTeleportHomeRequest; | ||
8381 | if (handlerTeleportHomeRequest != null) | ||
8382 | { | ||
8383 | handlerTeleportHomeRequest(AgentId, this); | ||
8384 | } | ||
8385 | return true; | ||
8386 | } | ||
8387 | |||
8388 | TeleportLandmarkRequest handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest; | ||
8389 | if (handlerTeleportLandmarkRequest != null) | ||
8390 | { | ||
8391 | handlerTeleportLandmarkRequest(this, lm.RegionID, lm.Position); | ||
8392 | } | ||
8393 | else | ||
8394 | { | ||
8395 | //no event handler so cancel request | ||
8396 | |||
8397 | |||
8398 | TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); | ||
8399 | tpCancel.Info.AgentID = tpReq.Info.AgentID; | ||
8400 | tpCancel.Info.SessionID = tpReq.Info.SessionID; | ||
8401 | OutPacket(tpCancel, ThrottleOutPacketType.Task); | ||
8402 | |||
8403 | } | ||
8404 | return true; | ||
8405 | } | ||
8406 | |||
8407 | private bool HandleTeleportLocationRequest(IClientAPI sender, Packet Pack) | ||
8408 | { | ||
8409 | TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack; | ||
8410 | // m_log.Debug(tpLocReq.ToString()); | ||
8411 | |||
8412 | #region Packet Session and User Check | ||
8413 | if (m_checkPackets) | ||
8414 | { | ||
8415 | if (tpLocReq.AgentData.SessionID != SessionId || | ||
8416 | tpLocReq.AgentData.AgentID != AgentId) | ||
8417 | return true; | ||
8418 | } | ||
8419 | #endregion | ||
8420 | |||
8421 | TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest; | ||
8422 | if (handlerTeleportLocationRequest != null) | ||
8423 | { | ||
8424 | handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position, | ||
8425 | tpLocReq.Info.LookAt, 16); | ||
8426 | } | ||
8427 | else | ||
8428 | { | ||
8429 | //no event handler so cancel request | ||
8430 | TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); | ||
8431 | tpCancel.Info.SessionID = tpLocReq.AgentData.SessionID; | ||
8432 | tpCancel.Info.AgentID = tpLocReq.AgentData.AgentID; | ||
8433 | OutPacket(tpCancel, ThrottleOutPacketType.Task); | ||
8434 | } | ||
8435 | return true; | ||
8436 | } | ||
8437 | |||
8438 | #endregion Inventory/Asset/Other related packets | ||
8439 | |||
8440 | private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack) | ||
8441 | { | ||
8442 | UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; | ||
8443 | |||
8444 | foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) | ||
8445 | { | ||
8446 | UUIDNameRequest handlerNameRequest = OnNameFromUUIDRequest; | ||
8447 | if (handlerNameRequest != null) | ||
8448 | { | ||
8449 | handlerNameRequest(UUIDBlock.ID, this); | ||
8450 | } | ||
8451 | } | ||
8452 | return true; | ||
8453 | } | ||
8454 | |||
8455 | #region Parcel related packets | ||
8456 | |||
8457 | private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) | ||
8458 | { | ||
8459 | RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; | ||
8460 | |||
8461 | RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; | ||
8462 | if (handlerRegionHandleRequest != null) | ||
8463 | { | ||
8464 | handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); | ||
8465 | } | ||
8466 | return true; | ||
8467 | } | ||
8468 | |||
8469 | private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) | ||
8470 | { | ||
8471 | ParcelInfoRequestPacket pirPack = (ParcelInfoRequestPacket)Pack; | ||
8472 | |||
8473 | #region Packet Session and User Check | ||
8474 | if (m_checkPackets) | ||
8475 | { | ||
8476 | if (pirPack.AgentData.SessionID != SessionId || | ||
8477 | pirPack.AgentData.AgentID != AgentId) | ||
8478 | return true; | ||
8479 | } | ||
8480 | #endregion | ||
8481 | |||
8482 | ParcelInfoRequest handlerParcelInfoRequest = OnParcelInfoRequest; | ||
8483 | if (handlerParcelInfoRequest != null) | ||
8484 | { | ||
8485 | handlerParcelInfoRequest(this, pirPack.Data.ParcelID); | ||
8486 | } | ||
8487 | return true; | ||
8488 | } | ||
8489 | |||
8490 | private bool HandleParcelAccessListRequest(IClientAPI sender, Packet Pack) | ||
8491 | { | ||
8492 | ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack; | ||
8493 | |||
8494 | #region Packet Session and User Check | ||
8495 | if (m_checkPackets) | ||
8496 | { | ||
8497 | if (requestPacket.AgentData.SessionID != SessionId || | ||
8498 | requestPacket.AgentData.AgentID != AgentId) | ||
8499 | return true; | ||
8500 | } | ||
8501 | #endregion | ||
8502 | |||
8503 | ParcelAccessListRequest handlerParcelAccessListRequest = OnParcelAccessListRequest; | ||
8504 | |||
8505 | if (handlerParcelAccessListRequest != null) | ||
8506 | { | ||
8507 | handlerParcelAccessListRequest(requestPacket.AgentData.AgentID, requestPacket.AgentData.SessionID, | ||
8508 | requestPacket.Data.Flags, requestPacket.Data.SequenceID, | ||
8509 | requestPacket.Data.LocalID, this); | ||
8510 | } | ||
8511 | return true; | ||
8512 | } | ||
8513 | |||
8514 | private bool HandleParcelAccessListUpdate(IClientAPI sender, Packet Pack) | ||
8515 | { | ||
8516 | ParcelAccessListUpdatePacket updatePacket = (ParcelAccessListUpdatePacket)Pack; | ||
8517 | |||
8518 | #region Packet Session and User Check | ||
8519 | if (m_checkPackets) | ||
8520 | { | ||
8521 | if (updatePacket.AgentData.SessionID != SessionId || | ||
8522 | updatePacket.AgentData.AgentID != AgentId) | ||
8523 | return true; | ||
8524 | } | ||
8525 | #endregion | ||
8526 | |||
8527 | List<ParcelManager.ParcelAccessEntry> entries = new List<ParcelManager.ParcelAccessEntry>(); | ||
8528 | foreach (ParcelAccessListUpdatePacket.ListBlock block in updatePacket.List) | ||
8529 | { | ||
8530 | ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); | ||
8531 | entry.AgentID = block.ID; | ||
8532 | entry.Flags = (AccessList)block.Flags; | ||
8533 | entry.Time = Util.ToDateTime(block.Time); | ||
8534 | entries.Add(entry); | ||
8535 | } | ||
8536 | |||
8537 | ParcelAccessListUpdateRequest handlerParcelAccessListUpdateRequest = OnParcelAccessListUpdateRequest; | ||
8538 | if (handlerParcelAccessListUpdateRequest != null) | ||
8539 | { | ||
8540 | handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID, | ||
8541 | updatePacket.Data.Flags, | ||
8542 | updatePacket.Data.LocalID, | ||
8543 | updatePacket.Data.TransactionID, | ||
8544 | updatePacket.Data.SequenceID, | ||
8545 | updatePacket.Data.Sections, | ||
8546 | entries, this); | ||
8547 | } | ||
8548 | return true; | ||
8549 | } | ||
8550 | |||
8551 | private bool HandleParcelPropertiesRequest(IClientAPI sender, Packet Pack) | ||
8552 | { | ||
8553 | ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack; | ||
8554 | |||
8555 | #region Packet Session and User Check | ||
8556 | if (m_checkPackets) | ||
8557 | { | ||
8558 | if (propertiesRequest.AgentData.SessionID != SessionId || | ||
8559 | propertiesRequest.AgentData.AgentID != AgentId) | ||
8560 | return true; | ||
8561 | } | ||
8562 | #endregion | ||
8563 | |||
8564 | ParcelPropertiesRequest handlerParcelPropertiesRequest = OnParcelPropertiesRequest; | ||
8565 | if (handlerParcelPropertiesRequest != null) | ||
8566 | { | ||
8567 | handlerParcelPropertiesRequest((int)Math.Round(propertiesRequest.ParcelData.West), | ||
8568 | (int)Math.Round(propertiesRequest.ParcelData.South), | ||
8569 | (int)Math.Round(propertiesRequest.ParcelData.East), | ||
8570 | (int)Math.Round(propertiesRequest.ParcelData.North), | ||
8571 | propertiesRequest.ParcelData.SequenceID, | ||
8572 | propertiesRequest.ParcelData.SnapSelection, this); | ||
8573 | } | ||
8574 | return true; | ||
8575 | } | ||
8576 | |||
8577 | private bool HandleParcelDivide(IClientAPI sender, Packet Pack) | ||
8578 | { | ||
8579 | ParcelDividePacket landDivide = (ParcelDividePacket)Pack; | ||
8580 | |||
8581 | #region Packet Session and User Check | ||
8582 | if (m_checkPackets) | ||
8583 | { | ||
8584 | if (landDivide.AgentData.SessionID != SessionId || | ||
8585 | landDivide.AgentData.AgentID != AgentId) | ||
8586 | return true; | ||
8587 | } | ||
8588 | #endregion | ||
8589 | |||
8590 | ParcelDivideRequest handlerParcelDivideRequest = OnParcelDivideRequest; | ||
8591 | if (handlerParcelDivideRequest != null) | ||
8592 | { | ||
8593 | handlerParcelDivideRequest((int)Math.Round(landDivide.ParcelData.West), | ||
8594 | (int)Math.Round(landDivide.ParcelData.South), | ||
8595 | (int)Math.Round(landDivide.ParcelData.East), | ||
8596 | (int)Math.Round(landDivide.ParcelData.North), this); | ||
8597 | } | ||
8598 | return true; | ||
8599 | } | ||
8600 | |||
8601 | private bool HandleParcelJoin(IClientAPI sender, Packet Pack) | ||
8602 | { | ||
8603 | ParcelJoinPacket landJoin = (ParcelJoinPacket)Pack; | ||
8604 | |||
8605 | #region Packet Session and User Check | ||
8606 | if (m_checkPackets) | ||
8607 | { | ||
8608 | if (landJoin.AgentData.SessionID != SessionId || | ||
8609 | landJoin.AgentData.AgentID != AgentId) | ||
8610 | return true; | ||
8611 | } | ||
8612 | #endregion | ||
8613 | |||
8614 | ParcelJoinRequest handlerParcelJoinRequest = OnParcelJoinRequest; | ||
8615 | |||
8616 | if (handlerParcelJoinRequest != null) | ||
8617 | { | ||
8618 | handlerParcelJoinRequest((int)Math.Round(landJoin.ParcelData.West), | ||
8619 | (int)Math.Round(landJoin.ParcelData.South), | ||
8620 | (int)Math.Round(landJoin.ParcelData.East), | ||
8621 | (int)Math.Round(landJoin.ParcelData.North), this); | ||
8622 | } | ||
8623 | return true; | ||
8624 | } | ||
8625 | |||
8626 | private bool HandleParcelPropertiesUpdate(IClientAPI sender, Packet Pack) | ||
8627 | { | ||
8628 | ParcelPropertiesUpdatePacket parcelPropertiesPacket = (ParcelPropertiesUpdatePacket)Pack; | ||
8629 | |||
8630 | #region Packet Session and User Check | ||
8631 | if (m_checkPackets) | ||
8632 | { | ||
8633 | if (parcelPropertiesPacket.AgentData.SessionID != SessionId || | ||
8634 | parcelPropertiesPacket.AgentData.AgentID != AgentId) | ||
8635 | return true; | ||
8636 | } | ||
8637 | #endregion | ||
8638 | |||
8639 | ParcelPropertiesUpdateRequest handlerParcelPropertiesUpdateRequest = OnParcelPropertiesUpdateRequest; | ||
8640 | |||
8641 | if (handlerParcelPropertiesUpdateRequest != null) | ||
8642 | { | ||
8643 | LandUpdateArgs args = new LandUpdateArgs(); | ||
8644 | |||
8645 | args.AuthBuyerID = parcelPropertiesPacket.ParcelData.AuthBuyerID; | ||
8646 | args.Category = (ParcelCategory)parcelPropertiesPacket.ParcelData.Category; | ||
8647 | args.Desc = Utils.BytesToString(parcelPropertiesPacket.ParcelData.Desc); | ||
8648 | args.GroupID = parcelPropertiesPacket.ParcelData.GroupID; | ||
8649 | args.LandingType = parcelPropertiesPacket.ParcelData.LandingType; | ||
8650 | args.MediaAutoScale = parcelPropertiesPacket.ParcelData.MediaAutoScale; | ||
8651 | args.MediaID = parcelPropertiesPacket.ParcelData.MediaID; | ||
8652 | args.MediaURL = Utils.BytesToString(parcelPropertiesPacket.ParcelData.MediaURL); | ||
8653 | args.MusicURL = Utils.BytesToString(parcelPropertiesPacket.ParcelData.MusicURL); | ||
8654 | args.Name = Utils.BytesToString(parcelPropertiesPacket.ParcelData.Name); | ||
8655 | args.ParcelFlags = parcelPropertiesPacket.ParcelData.ParcelFlags; | ||
8656 | args.PassHours = parcelPropertiesPacket.ParcelData.PassHours; | ||
8657 | args.PassPrice = parcelPropertiesPacket.ParcelData.PassPrice; | ||
8658 | args.SalePrice = parcelPropertiesPacket.ParcelData.SalePrice; | ||
8659 | args.SnapshotID = parcelPropertiesPacket.ParcelData.SnapshotID; | ||
8660 | args.UserLocation = parcelPropertiesPacket.ParcelData.UserLocation; | ||
8661 | args.UserLookAt = parcelPropertiesPacket.ParcelData.UserLookAt; | ||
8662 | handlerParcelPropertiesUpdateRequest(args, parcelPropertiesPacket.ParcelData.LocalID, this); | ||
8663 | } | ||
8664 | return true; | ||
8665 | } | ||
8666 | |||
8667 | private bool HandleParcelSelectObjects(IClientAPI sender, Packet Pack) | ||
8668 | { | ||
8669 | ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket)Pack; | ||
8670 | |||
8671 | #region Packet Session and User Check | ||
8672 | if (m_checkPackets) | ||
8673 | { | ||
8674 | if (selectPacket.AgentData.SessionID != SessionId || | ||
8675 | selectPacket.AgentData.AgentID != AgentId) | ||
8676 | return true; | ||
8677 | } | ||
8678 | #endregion | ||
8679 | |||
8680 | List<UUID> returnIDs = new List<UUID>(); | ||
8681 | |||
8682 | foreach (ParcelSelectObjectsPacket.ReturnIDsBlock rb in | ||
8683 | selectPacket.ReturnIDs) | ||
8684 | { | ||
8685 | returnIDs.Add(rb.ReturnID); | ||
8686 | } | ||
8687 | |||
8688 | ParcelSelectObjects handlerParcelSelectObjects = OnParcelSelectObjects; | ||
8689 | |||
8690 | if (handlerParcelSelectObjects != null) | ||
8691 | { | ||
8692 | handlerParcelSelectObjects(selectPacket.ParcelData.LocalID, | ||
8693 | Convert.ToInt32(selectPacket.ParcelData.ReturnType), returnIDs, this); | ||
8694 | } | ||
8695 | return true; | ||
8696 | } | ||
8697 | |||
8698 | private bool HandleParcelObjectOwnersRequest(IClientAPI sender, Packet Pack) | ||
8699 | { | ||
8700 | ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket)Pack; | ||
8701 | |||
8702 | #region Packet Session and User Check | ||
8703 | if (m_checkPackets) | ||
8704 | { | ||
8705 | if (reqPacket.AgentData.SessionID != SessionId || | ||
8706 | reqPacket.AgentData.AgentID != AgentId) | ||
8707 | return true; | ||
8708 | } | ||
8709 | #endregion | ||
8710 | |||
8711 | ParcelObjectOwnerRequest handlerParcelObjectOwnerRequest = OnParcelObjectOwnerRequest; | ||
8712 | |||
8713 | if (handlerParcelObjectOwnerRequest != null) | ||
8714 | { | ||
8715 | handlerParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this); | ||
8716 | } | ||
8717 | return true; | ||
8718 | |||
8719 | } | ||
8720 | |||
8721 | private bool HandleParcelGodForceOwner(IClientAPI sender, Packet Pack) | ||
8722 | { | ||
8723 | ParcelGodForceOwnerPacket godForceOwnerPacket = (ParcelGodForceOwnerPacket)Pack; | ||
8724 | |||
8725 | #region Packet Session and User Check | ||
8726 | if (m_checkPackets) | ||
8727 | { | ||
8728 | if (godForceOwnerPacket.AgentData.SessionID != SessionId || | ||
8729 | godForceOwnerPacket.AgentData.AgentID != AgentId) | ||
8730 | return true; | ||
8731 | } | ||
8732 | #endregion | ||
8733 | |||
8734 | ParcelGodForceOwner handlerParcelGodForceOwner = OnParcelGodForceOwner; | ||
8735 | if (handlerParcelGodForceOwner != null) | ||
8736 | { | ||
8737 | handlerParcelGodForceOwner(godForceOwnerPacket.Data.LocalID, godForceOwnerPacket.Data.OwnerID, this); | ||
8738 | } | ||
8739 | return true; | ||
8740 | } | ||
8741 | |||
8742 | private bool HandleParcelRelease(IClientAPI sender, Packet Pack) | ||
8743 | { | ||
8744 | ParcelReleasePacket releasePacket = (ParcelReleasePacket)Pack; | ||
8745 | |||
8746 | #region Packet Session and User Check | ||
8747 | if (m_checkPackets) | ||
8748 | { | ||
8749 | if (releasePacket.AgentData.SessionID != SessionId || | ||
8750 | releasePacket.AgentData.AgentID != AgentId) | ||
8751 | return true; | ||
8752 | } | ||
8753 | #endregion | ||
8754 | |||
8755 | ParcelAbandonRequest handlerParcelAbandonRequest = OnParcelAbandonRequest; | ||
8756 | if (handlerParcelAbandonRequest != null) | ||
8757 | { | ||
8758 | handlerParcelAbandonRequest(releasePacket.Data.LocalID, this); | ||
8759 | } | ||
8760 | return true; | ||
8761 | } | ||
8762 | |||
8763 | private bool HandleParcelReclaim(IClientAPI sender, Packet Pack) | ||
8764 | { | ||
8765 | ParcelReclaimPacket reclaimPacket = (ParcelReclaimPacket)Pack; | ||
8766 | |||
8767 | #region Packet Session and User Check | ||
8768 | if (m_checkPackets) | ||
8769 | { | ||
8770 | if (reclaimPacket.AgentData.SessionID != SessionId || | ||
8771 | reclaimPacket.AgentData.AgentID != AgentId) | ||
8772 | return true; | ||
8773 | } | ||
8774 | #endregion | ||
8775 | |||
8776 | ParcelReclaim handlerParcelReclaim = OnParcelReclaim; | ||
8777 | if (handlerParcelReclaim != null) | ||
8778 | { | ||
8779 | handlerParcelReclaim(reclaimPacket.Data.LocalID, this); | ||
8780 | } | ||
8781 | return true; | ||
8782 | } | ||
8783 | |||
8784 | private bool HandleParcelReturnObjects(IClientAPI sender, Packet Pack) | ||
8785 | { | ||
8786 | ParcelReturnObjectsPacket parcelReturnObjects = (ParcelReturnObjectsPacket)Pack; | ||
8787 | |||
8788 | #region Packet Session and User Check | ||
8789 | if (m_checkPackets) | ||
8790 | { | ||
8791 | if (parcelReturnObjects.AgentData.SessionID != SessionId || | ||
8792 | parcelReturnObjects.AgentData.AgentID != AgentId) | ||
8793 | return true; | ||
8794 | } | ||
8795 | #endregion | ||
8796 | |||
8797 | UUID[] puserselectedOwnerIDs = new UUID[parcelReturnObjects.OwnerIDs.Length]; | ||
8798 | for (int parceliterator = 0; parceliterator < parcelReturnObjects.OwnerIDs.Length; parceliterator++) | ||
8799 | puserselectedOwnerIDs[parceliterator] = parcelReturnObjects.OwnerIDs[parceliterator].OwnerID; | ||
8800 | |||
8801 | UUID[] puserselectedTaskIDs = new UUID[parcelReturnObjects.TaskIDs.Length]; | ||
8802 | |||
8803 | for (int parceliterator = 0; parceliterator < parcelReturnObjects.TaskIDs.Length; parceliterator++) | ||
8804 | puserselectedTaskIDs[parceliterator] = parcelReturnObjects.TaskIDs[parceliterator].TaskID; | ||
8805 | |||
8806 | ParcelReturnObjectsRequest handlerParcelReturnObjectsRequest = OnParcelReturnObjectsRequest; | ||
8807 | if (handlerParcelReturnObjectsRequest != null) | ||
8808 | { | ||
8809 | handlerParcelReturnObjectsRequest(parcelReturnObjects.ParcelData.LocalID, parcelReturnObjects.ParcelData.ReturnType, puserselectedOwnerIDs, puserselectedTaskIDs, this); | ||
8810 | |||
8811 | } | ||
8812 | return true; | ||
8813 | } | ||
8814 | |||
8815 | private bool HandleParcelSetOtherCleanTime(IClientAPI sender, Packet Pack) | ||
8816 | { | ||
8817 | ParcelSetOtherCleanTimePacket parcelSetOtherCleanTimePacket = (ParcelSetOtherCleanTimePacket)Pack; | ||
8818 | |||
8819 | #region Packet Session and User Check | ||
8820 | if (m_checkPackets) | ||
8821 | { | ||
8822 | if (parcelSetOtherCleanTimePacket.AgentData.SessionID != SessionId || | ||
8823 | parcelSetOtherCleanTimePacket.AgentData.AgentID != AgentId) | ||
8824 | return true; | ||
8825 | } | ||
8826 | #endregion | ||
8827 | |||
8828 | ParcelSetOtherCleanTime handlerParcelSetOtherCleanTime = OnParcelSetOtherCleanTime; | ||
8829 | if (handlerParcelSetOtherCleanTime != null) | ||
8830 | { | ||
8831 | handlerParcelSetOtherCleanTime(this, | ||
8832 | parcelSetOtherCleanTimePacket.ParcelData.LocalID, | ||
8833 | parcelSetOtherCleanTimePacket.ParcelData.OtherCleanTime); | ||
8834 | } | ||
8835 | return true; | ||
8836 | } | ||
8837 | |||
8838 | private bool HandleLandStatRequest(IClientAPI sender, Packet Pack) | ||
8839 | { | ||
8840 | LandStatRequestPacket lsrp = (LandStatRequestPacket)Pack; | ||
8841 | |||
8842 | #region Packet Session and User Check | ||
8843 | if (m_checkPackets) | ||
8844 | { | ||
8845 | if (lsrp.AgentData.SessionID != SessionId || | ||
8846 | lsrp.AgentData.AgentID != AgentId) | ||
8847 | return true; | ||
8848 | } | ||
8849 | #endregion | ||
8850 | |||
8851 | GodLandStatRequest handlerLandStatRequest = OnLandStatRequest; | ||
8852 | if (handlerLandStatRequest != null) | ||
8853 | { | ||
8854 | handlerLandStatRequest(lsrp.RequestData.ParcelLocalID, lsrp.RequestData.ReportType, lsrp.RequestData.RequestFlags, Utils.BytesToString(lsrp.RequestData.Filter), this); | ||
8855 | } | ||
8856 | return true; | ||
8857 | } | ||
8858 | |||
8859 | private bool HandleParcelDwellRequest(IClientAPI sender, Packet Pack) | ||
8860 | { | ||
8861 | ParcelDwellRequestPacket dwellrq = | ||
8862 | (ParcelDwellRequestPacket)Pack; | ||
8863 | |||
8864 | #region Packet Session and User Check | ||
8865 | if (m_checkPackets) | ||
8866 | { | ||
8867 | if (dwellrq.AgentData.SessionID != SessionId || | ||
8868 | dwellrq.AgentData.AgentID != AgentId) | ||
8869 | return true; | ||
8870 | } | ||
8871 | #endregion | ||
8872 | |||
8873 | ParcelDwellRequest handlerParcelDwellRequest = OnParcelDwellRequest; | ||
8874 | if (handlerParcelDwellRequest != null) | ||
8875 | { | ||
8876 | handlerParcelDwellRequest(dwellrq.Data.LocalID, this); | ||
8877 | } | ||
8878 | return true; | ||
8879 | } | ||
8880 | |||
8881 | #endregion Parcel related packets | ||
8882 | |||
8883 | #region Estate Packets | ||
8884 | |||
8885 | private bool HandleEstateOwnerMessage(IClientAPI sender, Packet Pack) | ||
8886 | { | ||
8887 | EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; | ||
8888 | //m_log.Debug(messagePacket.ToString()); | ||
8889 | GodLandStatRequest handlerLandStatRequest; | ||
8890 | |||
8891 | #region Packet Session and User Check | ||
8892 | if (m_checkPackets) | ||
8893 | { | ||
8894 | if (messagePacket.AgentData.SessionID != SessionId || | ||
8895 | messagePacket.AgentData.AgentID != AgentId) | ||
8896 | return true; | ||
8897 | } | ||
8898 | #endregion | ||
8899 | |||
8900 | switch (Utils.BytesToString(messagePacket.MethodData.Method)) | ||
8901 | { | ||
8902 | case "getinfo": | ||
8903 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
8904 | { | ||
8905 | OnDetailedEstateDataRequest(this, messagePacket.MethodData.Invoice); | ||
8906 | } | ||
8907 | return true; | ||
8908 | case "setregioninfo": | ||
8909 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
8910 | { | ||
8911 | OnSetEstateFlagsRequest(convertParamStringToBool(messagePacket.ParamList[0].Parameter), convertParamStringToBool(messagePacket.ParamList[1].Parameter), | ||
8912 | convertParamStringToBool(messagePacket.ParamList[2].Parameter), !convertParamStringToBool(messagePacket.ParamList[3].Parameter), | ||
8913 | Convert.ToInt16(Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[4].Parameter), Culture.NumberFormatInfo)), | ||
8914 | (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[5].Parameter), Culture.NumberFormatInfo), | ||
8915 | Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[6].Parameter)), | ||
8916 | convertParamStringToBool(messagePacket.ParamList[7].Parameter), convertParamStringToBool(messagePacket.ParamList[8].Parameter)); | ||
8917 | } | ||
8918 | return true; | ||
8919 | // case "texturebase": | ||
8920 | // if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
8921 | // { | ||
8922 | // foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) | ||
8923 | // { | ||
8924 | // string s = Utils.BytesToString(block.Parameter); | ||
8925 | // string[] splitField = s.Split(' '); | ||
8926 | // if (splitField.Length == 2) | ||
8927 | // { | ||
8928 | // UUID tempUUID = new UUID(splitField[1]); | ||
8929 | // OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID); | ||
8930 | // } | ||
8931 | // } | ||
8932 | // } | ||
8933 | // break; | ||
8934 | case "texturedetail": | ||
8935 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
8936 | { | ||
8937 | foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) | ||
8938 | { | ||
8939 | string s = Utils.BytesToString(block.Parameter); | ||
8940 | string[] splitField = s.Split(' '); | ||
8941 | if (splitField.Length == 2) | ||
8942 | { | ||
8943 | Int16 corner = Convert.ToInt16(splitField[0]); | ||
8944 | UUID textureUUID = new UUID(splitField[1]); | ||
8945 | |||
8946 | OnSetEstateTerrainDetailTexture(this, corner, textureUUID); | ||
8947 | } | ||
8948 | } | ||
8949 | } | ||
8950 | |||
8951 | return true; | ||
8952 | case "textureheights": | ||
8953 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
8954 | { | ||
8955 | foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) | ||
8956 | { | ||
8957 | string s = Utils.BytesToString(block.Parameter); | ||
8958 | string[] splitField = s.Split(' '); | ||
8959 | if (splitField.Length == 3) | ||
8960 | { | ||
8961 | Int16 corner = Convert.ToInt16(splitField[0]); | ||
8962 | float lowValue = (float)Convert.ToDecimal(splitField[1], Culture.NumberFormatInfo); | ||
8963 | float highValue = (float)Convert.ToDecimal(splitField[2], Culture.NumberFormatInfo); | ||
8964 | |||
8965 | OnSetEstateTerrainTextureHeights(this, corner, lowValue, highValue); | ||
8966 | } | ||
8967 | } | ||
8968 | } | ||
8969 | return true; | ||
8970 | case "texturecommit": | ||
8971 | OnCommitEstateTerrainTextureRequest(this); | ||
8972 | return true; | ||
8973 | case "setregionterrain": | ||
8974 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
8975 | { | ||
8976 | if (messagePacket.ParamList.Length != 9) | ||
8977 | { | ||
8978 | m_log.Error("EstateOwnerMessage: SetRegionTerrain method has a ParamList of invalid length"); | ||
8979 | } | ||
8980 | else | ||
8981 | { | ||
8982 | try | ||
8983 | { | ||
8984 | string tmp = Utils.BytesToString(messagePacket.ParamList[0].Parameter); | ||
8985 | if (!tmp.Contains(".")) tmp += ".00"; | ||
8986 | float WaterHeight = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo); | ||
8987 | tmp = Utils.BytesToString(messagePacket.ParamList[1].Parameter); | ||
8988 | if (!tmp.Contains(".")) tmp += ".00"; | ||
8989 | float TerrainRaiseLimit = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo); | ||
8990 | tmp = Utils.BytesToString(messagePacket.ParamList[2].Parameter); | ||
8991 | if (!tmp.Contains(".")) tmp += ".00"; | ||
8992 | float TerrainLowerLimit = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo); | ||
8993 | bool UseEstateSun = convertParamStringToBool(messagePacket.ParamList[3].Parameter); | ||
8994 | bool UseFixedSun = convertParamStringToBool(messagePacket.ParamList[4].Parameter); | ||
8995 | float SunHour = (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[5].Parameter), Culture.NumberFormatInfo); | ||
8996 | bool UseGlobal = convertParamStringToBool(messagePacket.ParamList[6].Parameter); | ||
8997 | bool EstateFixedSun = convertParamStringToBool(messagePacket.ParamList[7].Parameter); | ||
8998 | float EstateSunHour = (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[8].Parameter), Culture.NumberFormatInfo); | ||
8999 | |||
9000 | OnSetRegionTerrainSettings(WaterHeight, TerrainRaiseLimit, TerrainLowerLimit, UseEstateSun, UseFixedSun, SunHour, UseGlobal, EstateFixedSun, EstateSunHour); | ||
9001 | |||
9002 | } | ||
9003 | catch (Exception ex) | ||
9004 | { | ||
9005 | m_log.Error("EstateOwnerMessage: Exception while setting terrain settings: \n" + messagePacket + "\n" + ex); | ||
9006 | } | ||
9007 | } | ||
9008 | } | ||
9009 | |||
9010 | return true; | ||
9011 | case "restart": | ||
9012 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9013 | { | ||
9014 | // There's only 1 block in the estateResetSim.. and that's the number of seconds till restart. | ||
9015 | foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) | ||
9016 | { | ||
9017 | float timeSeconds; | ||
9018 | Utils.TryParseSingle(Utils.BytesToString(block.Parameter), out timeSeconds); | ||
9019 | timeSeconds = (int)timeSeconds; | ||
9020 | OnEstateRestartSimRequest(this, (int)timeSeconds); | ||
9021 | |||
9022 | } | ||
9023 | } | ||
9024 | return true; | ||
9025 | case "estatechangecovenantid": | ||
9026 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9027 | { | ||
9028 | foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) | ||
9029 | { | ||
9030 | UUID newCovenantID = new UUID(Utils.BytesToString(block.Parameter)); | ||
9031 | OnEstateChangeCovenantRequest(this, newCovenantID); | ||
9032 | } | ||
9033 | } | ||
9034 | return true; | ||
9035 | case "estateaccessdelta": // Estate access delta manages the banlist and allow list too. | ||
9036 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9037 | { | ||
9038 | int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter)); | ||
9039 | OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter))); | ||
9040 | |||
9041 | } | ||
9042 | return true; | ||
9043 | case "simulatormessage": | ||
9044 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9045 | { | ||
9046 | UUID invoice = messagePacket.MethodData.Invoice; | ||
9047 | UUID SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)); | ||
9048 | string SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter); | ||
9049 | string Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter); | ||
9050 | UUID sessionID = messagePacket.AgentData.SessionID; | ||
9051 | OnSimulatorBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message); | ||
9052 | } | ||
9053 | return true; | ||
9054 | case "instantmessage": | ||
9055 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9056 | { | ||
9057 | if (messagePacket.ParamList.Length < 2) | ||
9058 | return true; | ||
9059 | |||
9060 | UUID invoice = messagePacket.MethodData.Invoice; | ||
9061 | UUID sessionID = messagePacket.AgentData.SessionID; | ||
9062 | |||
9063 | UUID SenderID; | ||
9064 | string SenderName; | ||
9065 | string Message; | ||
9066 | |||
9067 | if (messagePacket.ParamList.Length < 5) | ||
9068 | { | ||
9069 | SenderID = AgentId; | ||
9070 | SenderName = Utils.BytesToString(messagePacket.ParamList[0].Parameter); | ||
9071 | Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter); | ||
9072 | } | ||
9073 | else | ||
9074 | { | ||
9075 | SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)); | ||
9076 | SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter); | ||
9077 | Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter); | ||
9078 | } | ||
9079 | |||
9080 | OnEstateBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message); | ||
9081 | } | ||
9082 | return true; | ||
9083 | case "setregiondebug": | ||
9084 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9085 | { | ||
9086 | UUID invoice = messagePacket.MethodData.Invoice; | ||
9087 | UUID SenderID = messagePacket.AgentData.AgentID; | ||
9088 | bool scripted = convertParamStringToBool(messagePacket.ParamList[0].Parameter); | ||
9089 | bool collisionEvents = convertParamStringToBool(messagePacket.ParamList[1].Parameter); | ||
9090 | bool physics = convertParamStringToBool(messagePacket.ParamList[2].Parameter); | ||
9091 | |||
9092 | OnEstateDebugRegionRequest(this, invoice, SenderID, scripted, collisionEvents, physics); | ||
9093 | } | ||
9094 | return true; | ||
9095 | case "teleporthomeuser": | ||
9096 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9097 | { | ||
9098 | UUID invoice = messagePacket.MethodData.Invoice; | ||
9099 | UUID SenderID = messagePacket.AgentData.AgentID; | ||
9100 | UUID Prey; | ||
9101 | |||
9102 | UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[1].Parameter), out Prey); | ||
9103 | |||
9104 | OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey); | ||
9105 | } | ||
9106 | return true; | ||
9107 | case "teleporthomeallusers": | ||
9108 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9109 | { | ||
9110 | UUID invoice = messagePacket.MethodData.Invoice; | ||
9111 | UUID SenderID = messagePacket.AgentData.AgentID; | ||
9112 | OnEstateTeleportAllUsersHomeRequest(this, invoice, SenderID); | ||
9113 | } | ||
9114 | return true; | ||
9115 | case "colliders": | ||
9116 | handlerLandStatRequest = OnLandStatRequest; | ||
9117 | if (handlerLandStatRequest != null) | ||
9118 | { | ||
9119 | handlerLandStatRequest(0, 1, 0, "", this); | ||
9120 | } | ||
9121 | return true; | ||
9122 | case "scripts": | ||
9123 | handlerLandStatRequest = OnLandStatRequest; | ||
9124 | if (handlerLandStatRequest != null) | ||
9125 | { | ||
9126 | handlerLandStatRequest(0, 0, 0, "", this); | ||
9127 | } | ||
9128 | return true; | ||
9129 | case "terrain": | ||
9130 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9131 | { | ||
9132 | if (messagePacket.ParamList.Length > 0) | ||
9133 | { | ||
9134 | if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "bake") | ||
9135 | { | ||
9136 | BakeTerrain handlerBakeTerrain = OnBakeTerrain; | ||
9137 | if (handlerBakeTerrain != null) | ||
9138 | { | ||
9139 | handlerBakeTerrain(this); | ||
9140 | } | ||
9141 | } | ||
9142 | if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "download filename") | ||
9143 | { | ||
9144 | if (messagePacket.ParamList.Length > 1) | ||
9145 | { | ||
9146 | RequestTerrain handlerRequestTerrain = OnRequestTerrain; | ||
9147 | if (handlerRequestTerrain != null) | ||
9148 | { | ||
9149 | handlerRequestTerrain(this, Utils.BytesToString(messagePacket.ParamList[1].Parameter)); | ||
9150 | } | ||
9151 | } | ||
9152 | } | ||
9153 | if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "upload filename") | ||
9154 | { | ||
9155 | if (messagePacket.ParamList.Length > 1) | ||
9156 | { | ||
9157 | RequestTerrain handlerUploadTerrain = OnUploadTerrain; | ||
9158 | if (handlerUploadTerrain != null) | ||
9159 | { | ||
9160 | handlerUploadTerrain(this, Utils.BytesToString(messagePacket.ParamList[1].Parameter)); | ||
9161 | } | ||
9162 | } | ||
9163 | } | ||
9164 | |||
9165 | } | ||
9166 | |||
9167 | |||
9168 | } | ||
9169 | return true; | ||
9170 | |||
9171 | case "estatechangeinfo": | ||
9172 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | ||
9173 | { | ||
9174 | UUID invoice = messagePacket.MethodData.Invoice; | ||
9175 | UUID SenderID = messagePacket.AgentData.AgentID; | ||
9176 | UInt32 param1 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[1].Parameter)); | ||
9177 | UInt32 param2 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[2].Parameter)); | ||
9178 | |||
9179 | EstateChangeInfo handlerEstateChangeInfo = OnEstateChangeInfo; | ||
9180 | if (handlerEstateChangeInfo != null) | ||
9181 | { | ||
9182 | handlerEstateChangeInfo(this, invoice, SenderID, param1, param2); | ||
9183 | } | ||
9184 | } | ||
9185 | return true; | ||
9186 | |||
9187 | default: | ||
9188 | m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); | ||
9189 | return true; | ||
9190 | } | ||
9191 | |||
9192 | //int parcelID, uint reportType, uint requestflags, string filter | ||
9193 | |||
9194 | //lsrp.RequestData.ParcelLocalID; | ||
9195 | //lsrp.RequestData.ReportType; // 1 = colliders, 0 = scripts | ||
9196 | //lsrp.RequestData.RequestFlags; | ||
9197 | //lsrp.RequestData.Filter; | ||
9198 | |||
9199 | // return true; | ||
9200 | } | ||
9201 | |||
9202 | private bool HandleRequestRegionInfo(IClientAPI sender, Packet Pack) | ||
9203 | { | ||
9204 | RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData; | ||
9205 | |||
9206 | #region Packet Session and User Check | ||
9207 | if (m_checkPackets) | ||
9208 | { | ||
9209 | if (mPacket.SessionID != SessionId || | ||
9210 | mPacket.AgentID != AgentId) | ||
9211 | return true; | ||
9212 | } | ||
9213 | #endregion | ||
9214 | |||
9215 | RegionInfoRequest handlerRegionInfoRequest = OnRegionInfoRequest; | ||
9216 | if (handlerRegionInfoRequest != null) | ||
9217 | { | ||
9218 | handlerRegionInfoRequest(this); | ||
9219 | } | ||
9220 | return true; | ||
9221 | } | ||
9222 | |||
9223 | private bool HandleEstateCovenantRequest(IClientAPI sender, Packet Pack) | ||
9224 | { | ||
9225 | |||
9226 | //EstateCovenantRequestPacket.AgentDataBlock epack = | ||
9227 | // ((EstateCovenantRequestPacket)Pack).AgentData; | ||
9228 | |||
9229 | EstateCovenantRequest handlerEstateCovenantRequest = OnEstateCovenantRequest; | ||
9230 | if (handlerEstateCovenantRequest != null) | ||
9231 | { | ||
9232 | handlerEstateCovenantRequest(this); | ||
9233 | } | ||
9234 | return true; | ||
9235 | |||
9236 | } | ||
9237 | |||
9238 | #endregion Estate Packets | ||
9239 | |||
9240 | #region GodPackets | ||
9241 | |||
9242 | private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack) | ||
9243 | { | ||
9244 | RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; | ||
9245 | RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock; | ||
9246 | UUID token = rblock.Token; | ||
9247 | |||
9248 | RequestGodlikePowersPacket.AgentDataBlock ablock = rglpPack.AgentData; | ||
9249 | |||
9250 | RequestGodlikePowers handlerReqGodlikePowers = OnRequestGodlikePowers; | ||
9251 | |||
9252 | if (handlerReqGodlikePowers != null) | ||
9253 | { | ||
9254 | handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, this); | ||
9255 | } | ||
9256 | |||
9257 | return true; | ||
9258 | } | ||
9259 | |||
9260 | private bool HandleGodUpdateRegionInfoUpdate(IClientAPI client, Packet Packet) | ||
9261 | { | ||
9262 | GodUpdateRegionInfoPacket GodUpdateRegionInfo = | ||
9263 | (GodUpdateRegionInfoPacket)Packet; | ||
9264 | |||
9265 | GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate; | ||
9266 | if (handlerGodUpdateRegionInfo != null) | ||
9267 | { | ||
9268 | handlerGodUpdateRegionInfo(this, | ||
9269 | GodUpdateRegionInfo.RegionInfo.BillableFactor, | ||
9270 | GodUpdateRegionInfo.RegionInfo.EstateID, | ||
9271 | GodUpdateRegionInfo.RegionInfo.RegionFlags, | ||
9272 | GodUpdateRegionInfo.RegionInfo.SimName, | ||
9273 | GodUpdateRegionInfo.RegionInfo.RedirectGridX, | ||
9274 | GodUpdateRegionInfo.RegionInfo.RedirectGridY); | ||
9275 | return true; | ||
9276 | } | ||
9277 | return false; | ||
9278 | } | ||
9279 | |||
9280 | private bool HandleSimWideDeletes(IClientAPI client, Packet Packet) | ||
9281 | { | ||
9282 | SimWideDeletesPacket SimWideDeletesRequest = | ||
9283 | (SimWideDeletesPacket)Packet; | ||
9284 | SimWideDeletesDelegate handlerSimWideDeletesRequest = OnSimWideDeletes; | ||
9285 | if (handlerSimWideDeletesRequest != null) | ||
9286 | { | ||
9287 | handlerSimWideDeletesRequest(this, SimWideDeletesRequest.AgentData.AgentID,(int)SimWideDeletesRequest.DataBlock.Flags,SimWideDeletesRequest.DataBlock.TargetID); | ||
9288 | return true; | ||
9289 | } | ||
9290 | return false; | ||
9291 | } | ||
9292 | |||
9293 | private bool HandleGodlikeMessage(IClientAPI client, Packet Packet) | ||
9294 | { | ||
9295 | GodlikeMessagePacket GodlikeMessage = | ||
9296 | (GodlikeMessagePacket)Packet; | ||
9297 | |||
9298 | GodlikeMessage handlerGodlikeMessage = onGodlikeMessage; | ||
9299 | if (handlerGodlikeMessage != null) | ||
9300 | { | ||
9301 | handlerGodlikeMessage(this, | ||
9302 | GodlikeMessage.MethodData.Invoice, | ||
9303 | GodlikeMessage.MethodData.Method, | ||
9304 | GodlikeMessage.ParamList[0].Parameter); | ||
9305 | return true; | ||
9306 | } | ||
9307 | return false; | ||
9308 | } | ||
9309 | |||
9310 | private bool HandleSaveStatePacket(IClientAPI client, Packet Packet) | ||
9311 | { | ||
9312 | StateSavePacket SaveStateMessage = | ||
9313 | (StateSavePacket)Packet; | ||
9314 | SaveStateHandler handlerSaveStatePacket = OnSaveState; | ||
9315 | if (handlerSaveStatePacket != null) | ||
9316 | { | ||
9317 | handlerSaveStatePacket(this,SaveStateMessage.AgentData.AgentID); | ||
9318 | return true; | ||
9319 | } | ||
9320 | return false; | ||
9321 | } | ||
9322 | |||
9323 | private bool HandleGodKickUser(IClientAPI sender, Packet Pack) | ||
9324 | { | ||
9325 | GodKickUserPacket gkupack = (GodKickUserPacket)Pack; | ||
9326 | |||
9327 | if (gkupack.UserInfo.GodSessionID == SessionId && AgentId == gkupack.UserInfo.GodID) | ||
9328 | { | ||
9329 | GodKickUser handlerGodKickUser = OnGodKickUser; | ||
9330 | if (handlerGodKickUser != null) | ||
9331 | { | ||
9332 | handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, | ||
9333 | gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason); | ||
9334 | } | ||
9335 | } | ||
9336 | else | ||
9337 | { | ||
9338 | SendAgentAlertMessage("Kick request denied", false); | ||
9339 | } | ||
9340 | //KickUserPacket kupack = new KickUserPacket(); | ||
9341 | //KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo; | ||
9342 | |||
9343 | //kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID; | ||
9344 | //kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID; | ||
9345 | |||
9346 | //kupack.TargetBlock.TargetIP = (uint)0; | ||
9347 | //kupack.TargetBlock.TargetPort = (ushort)0; | ||
9348 | //kupack.UserInfo.Reason = gkupack.UserInfo.Reason; | ||
9349 | |||
9350 | //OutPacket(kupack, ThrottleOutPacketType.Task); | ||
9351 | return true; | ||
9352 | } | ||
9353 | #endregion GodPackets | ||
9354 | |||
9355 | #region Economy/Transaction Packets | ||
9356 | |||
9357 | private bool HandleMoneyBalanceRequest(IClientAPI sender, Packet Pack) | ||
9358 | { | ||
9359 | MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; | ||
9360 | |||
9361 | #region Packet Session and User Check | ||
9362 | if (m_checkPackets) | ||
9363 | { | ||
9364 | if (moneybalancerequestpacket.AgentData.SessionID != SessionId || | ||
9365 | moneybalancerequestpacket.AgentData.AgentID != AgentId) | ||
9366 | return true; | ||
9367 | } | ||
9368 | #endregion | ||
9369 | |||
9370 | MoneyBalanceRequest handlerMoneyBalanceRequest = OnMoneyBalanceRequest; | ||
9371 | |||
9372 | if (handlerMoneyBalanceRequest != null) | ||
9373 | { | ||
9374 | handlerMoneyBalanceRequest(this, moneybalancerequestpacket.AgentData.AgentID, moneybalancerequestpacket.AgentData.SessionID, moneybalancerequestpacket.MoneyData.TransactionID); | ||
9375 | } | ||
9376 | |||
9377 | return true; | ||
9378 | } | ||
9379 | private bool HandleEconomyDataRequest(IClientAPI sender, Packet Pack) | ||
9380 | { | ||
9381 | EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; | ||
9382 | if (handlerEconomoyDataRequest != null) | ||
9383 | { | ||
9384 | handlerEconomoyDataRequest(AgentId); | ||
9385 | } | ||
9386 | return true; | ||
9387 | } | ||
9388 | private bool HandleRequestPayPrice(IClientAPI sender, Packet Pack) | ||
9389 | { | ||
9390 | RequestPayPricePacket requestPayPricePacket = (RequestPayPricePacket)Pack; | ||
9391 | |||
9392 | RequestPayPrice handlerRequestPayPrice = OnRequestPayPrice; | ||
9393 | if (handlerRequestPayPrice != null) | ||
9394 | { | ||
9395 | handlerRequestPayPrice(this, requestPayPricePacket.ObjectData.ObjectID); | ||
9396 | } | ||
9397 | return true; | ||
9398 | } | ||
9399 | private bool HandleObjectSaleInfo(IClientAPI sender, Packet Pack) | ||
9400 | { | ||
9401 | ObjectSaleInfoPacket objectSaleInfoPacket = (ObjectSaleInfoPacket)Pack; | ||
9402 | |||
9403 | #region Packet Session and User Check | ||
9404 | if (m_checkPackets) | ||
9405 | { | ||
9406 | if (objectSaleInfoPacket.AgentData.SessionID != SessionId || | ||
9407 | objectSaleInfoPacket.AgentData.AgentID != AgentId) | ||
9408 | return true; | ||
9409 | } | ||
9410 | #endregion | ||
9411 | |||
9412 | ObjectSaleInfo handlerObjectSaleInfo = OnObjectSaleInfo; | ||
9413 | if (handlerObjectSaleInfo != null) | ||
9414 | { | ||
9415 | foreach (ObjectSaleInfoPacket.ObjectDataBlock d | ||
9416 | in objectSaleInfoPacket.ObjectData) | ||
9417 | { | ||
9418 | handlerObjectSaleInfo(this, | ||
9419 | objectSaleInfoPacket.AgentData.AgentID, | ||
9420 | objectSaleInfoPacket.AgentData.SessionID, | ||
9421 | d.LocalID, | ||
9422 | d.SaleType, | ||
9423 | d.SalePrice); | ||
9424 | } | ||
9425 | } | ||
9426 | return true; | ||
9427 | } | ||
9428 | private bool HandleObjectBuy(IClientAPI sender, Packet Pack) | ||
9429 | { | ||
9430 | ObjectBuyPacket objectBuyPacket = (ObjectBuyPacket)Pack; | ||
9431 | |||
9432 | #region Packet Session and User Check | ||
9433 | if (m_checkPackets) | ||
9434 | { | ||
9435 | if (objectBuyPacket.AgentData.SessionID != SessionId || | ||
9436 | objectBuyPacket.AgentData.AgentID != AgentId) | ||
9437 | return true; | ||
9438 | } | ||
9439 | #endregion | ||
9440 | |||
9441 | ObjectBuy handlerObjectBuy = OnObjectBuy; | ||
9442 | |||
9443 | if (handlerObjectBuy != null) | ||
9444 | { | ||
9445 | foreach (ObjectBuyPacket.ObjectDataBlock d | ||
9446 | in objectBuyPacket.ObjectData) | ||
9447 | { | ||
9448 | handlerObjectBuy(this, | ||
9449 | objectBuyPacket.AgentData.AgentID, | ||
9450 | objectBuyPacket.AgentData.SessionID, | ||
9451 | objectBuyPacket.AgentData.GroupID, | ||
9452 | objectBuyPacket.AgentData.CategoryID, | ||
9453 | d.ObjectLocalID, | ||
9454 | d.SaleType, | ||
9455 | d.SalePrice); | ||
9456 | } | ||
9457 | } | ||
9458 | return true; | ||
9459 | } | ||
9460 | |||
9461 | #endregion Economy/Transaction Packets | ||
9462 | |||
9463 | #region Script Packets | ||
9464 | private bool HandleGetScriptRunning(IClientAPI sender, Packet Pack) | ||
9465 | { | ||
9466 | GetScriptRunningPacket scriptRunning = (GetScriptRunningPacket)Pack; | ||
9467 | |||
9468 | GetScriptRunning handlerGetScriptRunning = OnGetScriptRunning; | ||
9469 | if (handlerGetScriptRunning != null) | ||
9470 | { | ||
9471 | handlerGetScriptRunning(this, scriptRunning.Script.ObjectID, scriptRunning.Script.ItemID); | ||
9472 | } | ||
9473 | return true; | ||
9474 | } | ||
9475 | private bool HandleSetScriptRunning(IClientAPI sender, Packet Pack) | ||
9476 | { | ||
9477 | SetScriptRunningPacket setScriptRunning = (SetScriptRunningPacket)Pack; | ||
9478 | |||
9479 | #region Packet Session and User Check | ||
9480 | if (m_checkPackets) | ||
9481 | { | ||
9482 | if (setScriptRunning.AgentData.SessionID != SessionId || | ||
9483 | setScriptRunning.AgentData.AgentID != AgentId) | ||
9484 | return true; | ||
9485 | } | ||
9486 | #endregion | ||
9487 | |||
9488 | SetScriptRunning handlerSetScriptRunning = OnSetScriptRunning; | ||
9489 | if (handlerSetScriptRunning != null) | ||
9490 | { | ||
9491 | handlerSetScriptRunning(this, setScriptRunning.Script.ObjectID, setScriptRunning.Script.ItemID, setScriptRunning.Script.Running); | ||
9492 | } | ||
9493 | return true; | ||
9494 | } | ||
9495 | |||
9496 | private bool HandleScriptReset(IClientAPI sender, Packet Pack) | ||
9497 | { | ||
9498 | ScriptResetPacket scriptResetPacket = (ScriptResetPacket)Pack; | ||
9499 | |||
9500 | #region Packet Session and User Check | ||
9501 | if (m_checkPackets) | ||
9502 | { | ||
9503 | if (scriptResetPacket.AgentData.SessionID != SessionId || | ||
9504 | scriptResetPacket.AgentData.AgentID != AgentId) | ||
9505 | return true; | ||
9506 | } | ||
9507 | #endregion | ||
9508 | |||
9509 | ScriptReset handlerScriptReset = OnScriptReset; | ||
9510 | if (handlerScriptReset != null) | ||
9511 | { | ||
9512 | handlerScriptReset(this, scriptResetPacket.Script.ObjectID, scriptResetPacket.Script.ItemID); | ||
9513 | } | ||
9514 | return true; | ||
9515 | } | ||
9516 | |||
9517 | #endregion Script Packets | ||
9518 | |||
9519 | #region Gesture Managment | ||
9520 | |||
9521 | private bool HandleActivateGestures(IClientAPI sender, Packet Pack) | ||
9522 | { | ||
9523 | ActivateGesturesPacket activateGesturePacket = (ActivateGesturesPacket)Pack; | ||
9524 | |||
9525 | #region Packet Session and User Check | ||
9526 | if (m_checkPackets) | ||
9527 | { | ||
9528 | if (activateGesturePacket.AgentData.SessionID != SessionId || | ||
9529 | activateGesturePacket.AgentData.AgentID != AgentId) | ||
9530 | return true; | ||
9531 | } | ||
9532 | #endregion | ||
9533 | |||
9534 | ActivateGesture handlerActivateGesture = OnActivateGesture; | ||
9535 | if (handlerActivateGesture != null) | ||
9536 | { | ||
9537 | handlerActivateGesture(this, | ||
9538 | activateGesturePacket.Data[0].AssetID, | ||
9539 | activateGesturePacket.Data[0].ItemID); | ||
9540 | } | ||
9541 | else m_log.Error("Null pointer for activateGesture"); | ||
9542 | |||
9543 | return true; | ||
9544 | } | ||
9545 | private bool HandleDeactivateGestures(IClientAPI sender, Packet Pack) | ||
9546 | { | ||
9547 | DeactivateGesturesPacket deactivateGesturePacket = (DeactivateGesturesPacket)Pack; | ||
9548 | |||
9549 | #region Packet Session and User Check | ||
9550 | if (m_checkPackets) | ||
9551 | { | ||
9552 | if (deactivateGesturePacket.AgentData.SessionID != SessionId || | ||
9553 | deactivateGesturePacket.AgentData.AgentID != AgentId) | ||
9554 | return true; | ||
9555 | } | ||
9556 | #endregion | ||
9557 | |||
9558 | DeactivateGesture handlerDeactivateGesture = OnDeactivateGesture; | ||
9559 | if (handlerDeactivateGesture != null) | ||
9560 | { | ||
9561 | handlerDeactivateGesture(this, deactivateGesturePacket.Data[0].ItemID); | ||
9562 | } | ||
9563 | return true; | ||
9564 | } | ||
9565 | private bool HandleObjectOwner(IClientAPI sender, Packet Pack) | ||
9566 | { | ||
9567 | ObjectOwnerPacket objectOwnerPacket = (ObjectOwnerPacket)Pack; | ||
9568 | |||
9569 | #region Packet Session and User Check | ||
9570 | if (m_checkPackets) | ||
9571 | { | ||
9572 | if (objectOwnerPacket.AgentData.SessionID != SessionId || | ||
9573 | objectOwnerPacket.AgentData.AgentID != AgentId) | ||
9574 | return true; | ||
9575 | } | ||
9576 | #endregion | ||
9577 | |||
9578 | List<uint> localIDs = new List<uint>(); | ||
9579 | |||
9580 | foreach (ObjectOwnerPacket.ObjectDataBlock d in objectOwnerPacket.ObjectData) | ||
9581 | localIDs.Add(d.ObjectLocalID); | ||
9582 | |||
9583 | ObjectOwner handlerObjectOwner = OnObjectOwner; | ||
9584 | if (handlerObjectOwner != null) | ||
9585 | { | ||
9586 | handlerObjectOwner(this, objectOwnerPacket.HeaderData.OwnerID, objectOwnerPacket.HeaderData.GroupID, localIDs); | ||
9587 | } | ||
9588 | return true; | ||
9589 | } | ||
9590 | |||
9591 | #endregion Gesture Managment | ||
9592 | |||
9593 | private bool HandleAgentFOV(IClientAPI sender, Packet Pack) | ||
9594 | { | ||
9595 | AgentFOVPacket fovPacket = (AgentFOVPacket)Pack; | ||
9596 | |||
9597 | if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter) | ||
9598 | { | ||
9599 | m_agentFOVCounter = fovPacket.FOVBlock.GenCounter; | ||
9600 | AgentFOV handlerAgentFOV = OnAgentFOV; | ||
9601 | if (handlerAgentFOV != null) | ||
9602 | { | ||
9603 | handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle); | ||
9604 | } | ||
9605 | } | ||
9606 | return true; | ||
9607 | } | ||
9608 | |||
9609 | #region unimplemented handlers | ||
9610 | |||
9611 | private bool HandleViewerStats(IClientAPI sender, Packet Pack) | ||
9612 | { | ||
9613 | // TODO: handle this packet | ||
9614 | //m_log.Warn("[CLIENT]: unhandled ViewerStats packet"); | ||
9615 | return true; | ||
9616 | } | ||
9617 | |||
9618 | private bool HandleMapItemRequest(IClientAPI sender, Packet Pack) | ||
9619 | { | ||
9620 | MapItemRequestPacket mirpk = (MapItemRequestPacket)Pack; | ||
9621 | |||
9622 | #region Packet Session and User Check | ||
9623 | if (m_checkPackets) | ||
9624 | { | ||
9625 | if (mirpk.AgentData.SessionID != SessionId || | ||
9626 | mirpk.AgentData.AgentID != AgentId) | ||
9627 | return true; | ||
9628 | } | ||
9629 | #endregion | ||
9630 | |||
9631 | //m_log.Debug(mirpk.ToString()); | ||
9632 | MapItemRequest handlerMapItemRequest = OnMapItemRequest; | ||
9633 | if (handlerMapItemRequest != null) | ||
9634 | { | ||
9635 | handlerMapItemRequest(this, mirpk.AgentData.Flags, mirpk.AgentData.EstateID, | ||
9636 | mirpk.AgentData.Godlike, mirpk.RequestData.ItemType, | ||
9637 | mirpk.RequestData.RegionHandle); | ||
9638 | |||
9639 | } | ||
9640 | return true; | ||
9641 | } | ||
9642 | |||
9643 | private bool HandleTransferAbort(IClientAPI sender, Packet Pack) | ||
9644 | { | ||
9645 | return true; | ||
9646 | } | ||
9647 | |||
9648 | private bool HandleMuteListRequest(IClientAPI sender, Packet Pack) | ||
9649 | { | ||
9650 | MuteListRequestPacket muteListRequest = | ||
9651 | (MuteListRequestPacket)Pack; | ||
9652 | |||
9653 | #region Packet Session and User Check | ||
9654 | if (m_checkPackets) | ||
9655 | { | ||
9656 | if (muteListRequest.AgentData.SessionID != SessionId || | ||
9657 | muteListRequest.AgentData.AgentID != AgentId) | ||
9658 | return true; | ||
9659 | } | ||
9660 | #endregion | ||
9661 | |||
9662 | MuteListRequest handlerMuteListRequest = OnMuteListRequest; | ||
9663 | if (handlerMuteListRequest != null) | ||
9664 | { | ||
9665 | handlerMuteListRequest(this, muteListRequest.MuteData.MuteCRC); | ||
9666 | } | ||
9667 | else | ||
9668 | { | ||
9669 | SendUseCachedMuteList(); | ||
9670 | } | ||
9671 | return true; | ||
9672 | } | ||
9673 | |||
9674 | private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet) | ||
9675 | { | ||
9676 | UpdateMuteListEntryPacket UpdateMuteListEntry = | ||
9677 | (UpdateMuteListEntryPacket)Packet; | ||
9678 | MuteListEntryUpdate handlerUpdateMuteListEntry = OnUpdateMuteListEntry; | ||
9679 | if (handlerUpdateMuteListEntry != null) | ||
9680 | { | ||
9681 | handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, | ||
9682 | Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), | ||
9683 | UpdateMuteListEntry.MuteData.MuteType, | ||
9684 | UpdateMuteListEntry.MuteData.MuteFlags); | ||
9685 | return true; | ||
9686 | } | ||
9687 | return false; | ||
9688 | } | ||
9689 | |||
9690 | private bool HandleRemoveMuteListEntry(IClientAPI client, Packet Packet) | ||
9691 | { | ||
9692 | RemoveMuteListEntryPacket RemoveMuteListEntry = | ||
9693 | (RemoveMuteListEntryPacket)Packet; | ||
9694 | MuteListEntryRemove handlerRemoveMuteListEntry = OnRemoveMuteListEntry; | ||
9695 | if (handlerRemoveMuteListEntry != null) | ||
9696 | { | ||
9697 | handlerRemoveMuteListEntry(this, | ||
9698 | RemoveMuteListEntry.MuteData.MuteID, | ||
9699 | Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName)); | ||
9700 | return true; | ||
9701 | } | ||
9702 | return false; | ||
9703 | } | ||
9704 | |||
9705 | private bool HandleUserReport(IClientAPI client, Packet Packet) | ||
9706 | { | ||
9707 | UserReportPacket UserReport = | ||
9708 | (UserReportPacket)Packet; | ||
9709 | |||
9710 | NewUserReport handlerUserReport = OnUserReport; | ||
9711 | if (handlerUserReport != null) | ||
9712 | { | ||
9713 | handlerUserReport(this, | ||
9714 | Utils.BytesToString(UserReport.ReportData.AbuseRegionName), | ||
9715 | UserReport.ReportData.AbuserID, | ||
9716 | UserReport.ReportData.Category, | ||
9717 | UserReport.ReportData.CheckFlags, | ||
9718 | Utils.BytesToString(UserReport.ReportData.Details), | ||
9719 | UserReport.ReportData.ObjectID, | ||
9720 | UserReport.ReportData.Position, | ||
9721 | UserReport.ReportData.ReportType, | ||
9722 | UserReport.ReportData.ScreenshotID, | ||
9723 | Utils.BytesToString(UserReport.ReportData.Summary), | ||
9724 | UserReport.AgentData.AgentID); | ||
9725 | return true; | ||
9726 | } | ||
9727 | return false; | ||
9728 | } | ||
9729 | |||
9730 | private bool HandleSendPostcard(IClientAPI client, Packet packet) | ||
9731 | { | ||
9732 | // SendPostcardPacket SendPostcard = | ||
9733 | // (SendPostcardPacket)packet; | ||
9734 | SendPostcard handlerSendPostcard = OnSendPostcard; | ||
9735 | if (handlerSendPostcard != null) | ||
9736 | { | ||
9737 | handlerSendPostcard(this); | ||
9738 | return true; | ||
9739 | } | ||
9740 | return false; | ||
9741 | } | ||
9742 | |||
9743 | private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) | ||
9744 | { | ||
9745 | return true; | ||
9746 | } | ||
9747 | |||
9748 | private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack) | ||
9749 | { | ||
9750 | CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack; | ||
9751 | |||
9752 | #region Packet Session and User Check | ||
9753 | if (m_checkPackets) | ||
9754 | { | ||
9755 | if (packet.AgentData.SessionID != SessionId || | ||
9756 | packet.AgentData.AgentID != AgentId) | ||
9757 | return true; | ||
9758 | } | ||
9759 | #endregion | ||
9760 | MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null; | ||
9761 | List<InventoryItemBase> items = new List<InventoryItemBase>(); | ||
9762 | foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData) | ||
9763 | { | ||
9764 | InventoryItemBase b = new InventoryItemBase(); | ||
9765 | b.ID = n.OldItemID; | ||
9766 | b.Folder = n.OldFolderID; | ||
9767 | items.Add(b); | ||
9768 | } | ||
9769 | |||
9770 | handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy; | ||
9771 | if (handlerMoveItemsAndLeaveCopy != null) | ||
9772 | { | ||
9773 | handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID); | ||
9774 | } | ||
9775 | |||
9776 | return true; | ||
9777 | } | ||
9778 | |||
9779 | private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) | ||
9780 | { | ||
9781 | return true; | ||
9782 | } | ||
9783 | |||
9784 | private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack) | ||
9785 | { | ||
9786 | return true; | ||
9787 | } | ||
9788 | |||
9789 | #endregion unimplemented handlers | ||
9790 | |||
9791 | #region Dir handlers | ||
9792 | |||
9793 | private bool HandleDirPlacesQuery(IClientAPI sender, Packet Pack) | ||
9794 | { | ||
9795 | DirPlacesQueryPacket dirPlacesQueryPacket = (DirPlacesQueryPacket)Pack; | ||
9796 | //m_log.Debug(dirPlacesQueryPacket.ToString()); | ||
9797 | |||
9798 | #region Packet Session and User Check | ||
9799 | if (m_checkPackets) | ||
9800 | { | ||
9801 | if (dirPlacesQueryPacket.AgentData.SessionID != SessionId || | ||
9802 | dirPlacesQueryPacket.AgentData.AgentID != AgentId) | ||
9803 | return true; | ||
9804 | } | ||
9805 | #endregion | ||
9806 | |||
9807 | DirPlacesQuery handlerDirPlacesQuery = OnDirPlacesQuery; | ||
9808 | if (handlerDirPlacesQuery != null) | ||
9809 | { | ||
9810 | handlerDirPlacesQuery(this, | ||
9811 | dirPlacesQueryPacket.QueryData.QueryID, | ||
9812 | Utils.BytesToString( | ||
9813 | dirPlacesQueryPacket.QueryData.QueryText), | ||
9814 | (int)dirPlacesQueryPacket.QueryData.QueryFlags, | ||
9815 | (int)dirPlacesQueryPacket.QueryData.Category, | ||
9816 | Utils.BytesToString( | ||
9817 | dirPlacesQueryPacket.QueryData.SimName), | ||
9818 | dirPlacesQueryPacket.QueryData.QueryStart); | ||
9819 | } | ||
9820 | return true; | ||
9821 | } | ||
9822 | |||
9823 | private bool HandleDirFindQuery(IClientAPI sender, Packet Pack) | ||
9824 | { | ||
9825 | DirFindQueryPacket dirFindQueryPacket = (DirFindQueryPacket)Pack; | ||
9826 | |||
9827 | #region Packet Session and User Check | ||
9828 | if (m_checkPackets) | ||
9829 | { | ||
9830 | if (dirFindQueryPacket.AgentData.SessionID != SessionId || | ||
9831 | dirFindQueryPacket.AgentData.AgentID != AgentId) | ||
9832 | return true; | ||
9833 | } | ||
9834 | #endregion | ||
9835 | |||
9836 | DirFindQuery handlerDirFindQuery = OnDirFindQuery; | ||
9837 | if (handlerDirFindQuery != null) | ||
9838 | { | ||
9839 | handlerDirFindQuery(this, | ||
9840 | dirFindQueryPacket.QueryData.QueryID, | ||
9841 | Utils.BytesToString( | ||
9842 | dirFindQueryPacket.QueryData.QueryText), | ||
9843 | dirFindQueryPacket.QueryData.QueryFlags, | ||
9844 | dirFindQueryPacket.QueryData.QueryStart); | ||
9845 | } | ||
9846 | return true; | ||
9847 | } | ||
9848 | |||
9849 | private bool HandleDirLandQuery(IClientAPI sender, Packet Pack) | ||
9850 | { | ||
9851 | DirLandQueryPacket dirLandQueryPacket = (DirLandQueryPacket)Pack; | ||
9852 | |||
9853 | #region Packet Session and User Check | ||
9854 | if (m_checkPackets) | ||
9855 | { | ||
9856 | if (dirLandQueryPacket.AgentData.SessionID != SessionId || | ||
9857 | dirLandQueryPacket.AgentData.AgentID != AgentId) | ||
9858 | return true; | ||
9859 | } | ||
9860 | #endregion | ||
9861 | |||
9862 | DirLandQuery handlerDirLandQuery = OnDirLandQuery; | ||
9863 | if (handlerDirLandQuery != null) | ||
9864 | { | ||
9865 | handlerDirLandQuery(this, | ||
9866 | dirLandQueryPacket.QueryData.QueryID, | ||
9867 | dirLandQueryPacket.QueryData.QueryFlags, | ||
9868 | dirLandQueryPacket.QueryData.SearchType, | ||
9869 | dirLandQueryPacket.QueryData.Price, | ||
9870 | dirLandQueryPacket.QueryData.Area, | ||
9871 | dirLandQueryPacket.QueryData.QueryStart); | ||
9872 | } | ||
9873 | return true; | ||
9874 | } | ||
9875 | |||
9876 | private bool HandleDirPopularQuery(IClientAPI sender, Packet Pack) | ||
9877 | { | ||
9878 | DirPopularQueryPacket dirPopularQueryPacket = (DirPopularQueryPacket)Pack; | ||
9879 | |||
9880 | #region Packet Session and User Check | ||
9881 | if (m_checkPackets) | ||
9882 | { | ||
9883 | if (dirPopularQueryPacket.AgentData.SessionID != SessionId || | ||
9884 | dirPopularQueryPacket.AgentData.AgentID != AgentId) | ||
9885 | return true; | ||
9886 | } | ||
9887 | #endregion | ||
9888 | |||
9889 | DirPopularQuery handlerDirPopularQuery = OnDirPopularQuery; | ||
9890 | if (handlerDirPopularQuery != null) | ||
9891 | { | ||
9892 | handlerDirPopularQuery(this, | ||
9893 | dirPopularQueryPacket.QueryData.QueryID, | ||
9894 | dirPopularQueryPacket.QueryData.QueryFlags); | ||
9895 | } | ||
9896 | return true; | ||
9897 | } | ||
9898 | |||
9899 | private bool HandleDirClassifiedQuery(IClientAPI sender, Packet Pack) | ||
9900 | { | ||
9901 | DirClassifiedQueryPacket dirClassifiedQueryPacket = (DirClassifiedQueryPacket)Pack; | ||
9902 | |||
9903 | #region Packet Session and User Check | ||
9904 | if (m_checkPackets) | ||
9905 | { | ||
9906 | if (dirClassifiedQueryPacket.AgentData.SessionID != SessionId || | ||
9907 | dirClassifiedQueryPacket.AgentData.AgentID != AgentId) | ||
9908 | return true; | ||
9909 | } | ||
9910 | #endregion | ||
9911 | |||
9912 | DirClassifiedQuery handlerDirClassifiedQuery = OnDirClassifiedQuery; | ||
9913 | if (handlerDirClassifiedQuery != null) | ||
9914 | { | ||
9915 | handlerDirClassifiedQuery(this, | ||
9916 | dirClassifiedQueryPacket.QueryData.QueryID, | ||
9917 | Utils.BytesToString( | ||
9918 | dirClassifiedQueryPacket.QueryData.QueryText), | ||
9919 | dirClassifiedQueryPacket.QueryData.QueryFlags, | ||
9920 | dirClassifiedQueryPacket.QueryData.Category, | ||
9921 | dirClassifiedQueryPacket.QueryData.QueryStart); | ||
9922 | } | ||
9923 | return true; | ||
9924 | } | ||
9925 | |||
9926 | private bool HandleEventInfoRequest(IClientAPI sender, Packet Pack) | ||
9927 | { | ||
9928 | EventInfoRequestPacket eventInfoRequestPacket = (EventInfoRequestPacket)Pack; | ||
9929 | |||
9930 | #region Packet Session and User Check | ||
9931 | if (m_checkPackets) | ||
9932 | { | ||
9933 | if (eventInfoRequestPacket.AgentData.SessionID != SessionId || | ||
9934 | eventInfoRequestPacket.AgentData.AgentID != AgentId) | ||
9935 | return true; | ||
9936 | } | ||
9937 | #endregion | ||
9938 | |||
9939 | if (OnEventInfoRequest != null) | ||
9940 | { | ||
9941 | OnEventInfoRequest(this, eventInfoRequestPacket.EventData.EventID); | ||
9942 | } | ||
9943 | return true; | ||
9944 | } | ||
9945 | |||
9946 | #endregion | ||
9947 | |||
9948 | #region Calling Card | ||
9949 | |||
9950 | private bool HandleOfferCallingCard(IClientAPI sender, Packet Pack) | ||
9951 | { | ||
9952 | OfferCallingCardPacket offerCallingCardPacket = (OfferCallingCardPacket)Pack; | ||
9953 | |||
9954 | #region Packet Session and User Check | ||
9955 | if (m_checkPackets) | ||
9956 | { | ||
9957 | if (offerCallingCardPacket.AgentData.SessionID != SessionId || | ||
9958 | offerCallingCardPacket.AgentData.AgentID != AgentId) | ||
9959 | return true; | ||
9960 | } | ||
9961 | #endregion | ||
9962 | |||
9963 | if (OnOfferCallingCard != null) | ||
9964 | { | ||
9965 | OnOfferCallingCard(this, | ||
9966 | offerCallingCardPacket.AgentBlock.DestID, | ||
9967 | offerCallingCardPacket.AgentBlock.TransactionID); | ||
9968 | } | ||
9969 | return true; | ||
9970 | } | ||
9971 | |||
9972 | private bool HandleAcceptCallingCard(IClientAPI sender, Packet Pack) | ||
9973 | { | ||
9974 | AcceptCallingCardPacket acceptCallingCardPacket = (AcceptCallingCardPacket)Pack; | ||
9975 | |||
9976 | #region Packet Session and User Check | ||
9977 | if (m_checkPackets) | ||
9978 | { | ||
9979 | if (acceptCallingCardPacket.AgentData.SessionID != SessionId || | ||
9980 | acceptCallingCardPacket.AgentData.AgentID != AgentId) | ||
9981 | return true; | ||
9982 | } | ||
9983 | #endregion | ||
9984 | |||
9985 | // according to http://wiki.secondlife.com/wiki/AcceptCallingCard FolderData should | ||
9986 | // contain exactly one entry | ||
9987 | if (OnAcceptCallingCard != null && acceptCallingCardPacket.FolderData.Length > 0) | ||
9988 | { | ||
9989 | OnAcceptCallingCard(this, | ||
9990 | acceptCallingCardPacket.TransactionBlock.TransactionID, | ||
9991 | acceptCallingCardPacket.FolderData[0].FolderID); | ||
9992 | } | ||
9993 | return true; | ||
9994 | } | ||
9995 | |||
9996 | private bool HandleDeclineCallingCard(IClientAPI sender, Packet Pack) | ||
9997 | { | ||
9998 | DeclineCallingCardPacket declineCallingCardPacket = (DeclineCallingCardPacket)Pack; | ||
9999 | |||
10000 | #region Packet Session and User Check | ||
10001 | if (m_checkPackets) | ||
10002 | { | ||
10003 | if (declineCallingCardPacket.AgentData.SessionID != SessionId || | ||
10004 | declineCallingCardPacket.AgentData.AgentID != AgentId) | ||
10005 | return true; | ||
10006 | } | ||
10007 | #endregion | ||
10008 | |||
10009 | if (OnDeclineCallingCard != null) | ||
10010 | { | ||
10011 | OnDeclineCallingCard(this, | ||
10012 | declineCallingCardPacket.TransactionBlock.TransactionID); | ||
10013 | } | ||
10014 | return true; | ||
10015 | } | ||
10016 | |||
10017 | #endregion Calling Card | ||
10018 | |||
10019 | #region Groups | ||
10020 | |||
10021 | private bool HandleActivateGroup(IClientAPI sender, Packet Pack) | ||
10022 | { | ||
10023 | ActivateGroupPacket activateGroupPacket = (ActivateGroupPacket)Pack; | ||
10024 | |||
10025 | #region Packet Session and User Check | ||
10026 | if (m_checkPackets) | ||
10027 | { | ||
10028 | if (activateGroupPacket.AgentData.SessionID != SessionId || | ||
10029 | activateGroupPacket.AgentData.AgentID != AgentId) | ||
10030 | return true; | ||
10031 | } | ||
10032 | #endregion | ||
10033 | |||
10034 | if (m_GroupsModule != null) | ||
10035 | { | ||
10036 | m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID); | ||
10037 | m_GroupsModule.SendAgentGroupDataUpdate(this); | ||
10038 | } | ||
10039 | return true; | ||
10040 | |||
10041 | } | ||
10042 | |||
10043 | private bool HandleGroupVoteHistoryRequest(IClientAPI client, Packet Packet) | ||
10044 | { | ||
10045 | GroupVoteHistoryRequestPacket GroupVoteHistoryRequest = | ||
10046 | (GroupVoteHistoryRequestPacket)Packet; | ||
10047 | GroupVoteHistoryRequest handlerGroupVoteHistoryRequest = OnGroupVoteHistoryRequest; | ||
10048 | if (handlerGroupVoteHistoryRequest != null) | ||
10049 | { | ||
10050 | handlerGroupVoteHistoryRequest(this, GroupVoteHistoryRequest.AgentData.AgentID,GroupVoteHistoryRequest.AgentData.SessionID,GroupVoteHistoryRequest.GroupData.GroupID,GroupVoteHistoryRequest.TransactionData.TransactionID); | ||
10051 | return true; | ||
10052 | } | ||
10053 | return false; | ||
10054 | } | ||
10055 | |||
10056 | private bool HandleGroupActiveProposalsRequest(IClientAPI client, Packet Packet) | ||
10057 | { | ||
10058 | GroupActiveProposalsRequestPacket GroupActiveProposalsRequest = | ||
10059 | (GroupActiveProposalsRequestPacket)Packet; | ||
10060 | GroupActiveProposalsRequest handlerGroupActiveProposalsRequest = OnGroupActiveProposalsRequest; | ||
10061 | if (handlerGroupActiveProposalsRequest != null) | ||
10062 | { | ||
10063 | handlerGroupActiveProposalsRequest(this, GroupActiveProposalsRequest.AgentData.AgentID,GroupActiveProposalsRequest.AgentData.SessionID,GroupActiveProposalsRequest.GroupData.GroupID,GroupActiveProposalsRequest.TransactionData.TransactionID); | ||
10064 | return true; | ||
10065 | } | ||
10066 | return false; | ||
10067 | } | ||
10068 | |||
10069 | private bool HandleGroupAccountDetailsRequest(IClientAPI client, Packet Packet) | ||
10070 | { | ||
10071 | GroupAccountDetailsRequestPacket GroupAccountDetailsRequest = | ||
10072 | (GroupAccountDetailsRequestPacket)Packet; | ||
10073 | GroupAccountDetailsRequest handlerGroupAccountDetailsRequest = OnGroupAccountDetailsRequest; | ||
10074 | if (handlerGroupAccountDetailsRequest != null) | ||
10075 | { | ||
10076 | handlerGroupAccountDetailsRequest(this, GroupAccountDetailsRequest.AgentData.AgentID,GroupAccountDetailsRequest.AgentData.GroupID,GroupAccountDetailsRequest.MoneyData.RequestID,GroupAccountDetailsRequest.AgentData.SessionID); | ||
10077 | return true; | ||
10078 | } | ||
10079 | return false; | ||
10080 | } | ||
10081 | |||
10082 | private bool HandleGroupAccountSummaryRequest(IClientAPI client, Packet Packet) | ||
10083 | { | ||
10084 | GroupAccountSummaryRequestPacket GroupAccountSummaryRequest = | ||
10085 | (GroupAccountSummaryRequestPacket)Packet; | ||
10086 | GroupAccountSummaryRequest handlerGroupAccountSummaryRequest = OnGroupAccountSummaryRequest; | ||
10087 | if (handlerGroupAccountSummaryRequest != null) | ||
10088 | { | ||
10089 | handlerGroupAccountSummaryRequest(this, GroupAccountSummaryRequest.AgentData.AgentID,GroupAccountSummaryRequest.AgentData.GroupID); | ||
10090 | return true; | ||
10091 | } | ||
10092 | return false; | ||
10093 | } | ||
10094 | |||
10095 | private bool HandleGroupTransactionsDetailsRequest(IClientAPI client, Packet Packet) | ||
10096 | { | ||
10097 | GroupAccountTransactionsRequestPacket GroupAccountTransactionsRequest = | ||
10098 | (GroupAccountTransactionsRequestPacket)Packet; | ||
10099 | GroupAccountTransactionsRequest handlerGroupAccountTransactionsRequest = OnGroupAccountTransactionsRequest; | ||
10100 | if (handlerGroupAccountTransactionsRequest != null) | ||
10101 | { | ||
10102 | handlerGroupAccountTransactionsRequest(this, GroupAccountTransactionsRequest.AgentData.AgentID,GroupAccountTransactionsRequest.AgentData.GroupID,GroupAccountTransactionsRequest.MoneyData.RequestID,GroupAccountTransactionsRequest.AgentData.SessionID); | ||
10103 | return true; | ||
10104 | } | ||
10105 | return false; | ||
10106 | } | ||
10107 | |||
10108 | private bool HandleGroupTitlesRequest(IClientAPI sender, Packet Pack) | ||
10109 | { | ||
10110 | GroupTitlesRequestPacket groupTitlesRequest = | ||
10111 | (GroupTitlesRequestPacket)Pack; | ||
10112 | |||
10113 | #region Packet Session and User Check | ||
10114 | if (m_checkPackets) | ||
10115 | { | ||
10116 | if (groupTitlesRequest.AgentData.SessionID != SessionId || | ||
10117 | groupTitlesRequest.AgentData.AgentID != AgentId) | ||
10118 | return true; | ||
10119 | } | ||
10120 | #endregion | ||
10121 | |||
10122 | if (m_GroupsModule != null) | ||
10123 | { | ||
10124 | GroupTitlesReplyPacket groupTitlesReply = (GroupTitlesReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupTitlesReply); | ||
10125 | |||
10126 | groupTitlesReply.AgentData = | ||
10127 | new GroupTitlesReplyPacket.AgentDataBlock(); | ||
10128 | |||
10129 | groupTitlesReply.AgentData.AgentID = AgentId; | ||
10130 | groupTitlesReply.AgentData.GroupID = | ||
10131 | groupTitlesRequest.AgentData.GroupID; | ||
10132 | |||
10133 | groupTitlesReply.AgentData.RequestID = | ||
10134 | groupTitlesRequest.AgentData.RequestID; | ||
10135 | |||
10136 | List<GroupTitlesData> titles = | ||
10137 | m_GroupsModule.GroupTitlesRequest(this, | ||
10138 | groupTitlesRequest.AgentData.GroupID); | ||
10139 | |||
10140 | groupTitlesReply.GroupData = | ||
10141 | new GroupTitlesReplyPacket.GroupDataBlock[titles.Count]; | ||
10142 | |||
10143 | int i = 0; | ||
10144 | foreach (GroupTitlesData d in titles) | ||
10145 | { | ||
10146 | groupTitlesReply.GroupData[i] = | ||
10147 | new GroupTitlesReplyPacket.GroupDataBlock(); | ||
10148 | |||
10149 | groupTitlesReply.GroupData[i].Title = | ||
10150 | Util.StringToBytes256(d.Name); | ||
10151 | groupTitlesReply.GroupData[i].RoleID = | ||
10152 | d.UUID; | ||
10153 | groupTitlesReply.GroupData[i].Selected = | ||
10154 | d.Selected; | ||
10155 | i++; | ||
10156 | } | ||
10157 | |||
10158 | OutPacket(groupTitlesReply, ThrottleOutPacketType.Task); | ||
10159 | } | ||
10160 | return true; | ||
10161 | } | ||
10162 | private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack) | ||
10163 | { | ||
10164 | GroupProfileRequestPacket groupProfileRequest = | ||
10165 | (GroupProfileRequestPacket)Pack; | ||
10166 | |||
10167 | #region Packet Session and User Check | ||
10168 | if (m_checkPackets) | ||
10169 | { | ||
10170 | if (groupProfileRequest.AgentData.SessionID != SessionId || | ||
10171 | groupProfileRequest.AgentData.AgentID != AgentId) | ||
10172 | return true; | ||
10173 | } | ||
10174 | #endregion | ||
10175 | |||
10176 | if (m_GroupsModule != null) | ||
10177 | { | ||
10178 | GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply); | ||
10179 | |||
10180 | groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock(); | ||
10181 | groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock(); | ||
10182 | groupProfileReply.AgentData.AgentID = AgentId; | ||
10183 | |||
10184 | GroupProfileData d = m_GroupsModule.GroupProfileRequest(this, | ||
10185 | groupProfileRequest.GroupData.GroupID); | ||
10186 | |||
10187 | groupProfileReply.GroupData.GroupID = d.GroupID; | ||
10188 | groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name); | ||
10189 | groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter); | ||
10190 | groupProfileReply.GroupData.ShowInList = d.ShowInList; | ||
10191 | groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle); | ||
10192 | groupProfileReply.GroupData.PowersMask = d.PowersMask; | ||
10193 | groupProfileReply.GroupData.InsigniaID = d.InsigniaID; | ||
10194 | groupProfileReply.GroupData.FounderID = d.FounderID; | ||
10195 | groupProfileReply.GroupData.MembershipFee = d.MembershipFee; | ||
10196 | groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment; | ||
10197 | groupProfileReply.GroupData.Money = d.Money; | ||
10198 | groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount; | ||
10199 | groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount; | ||
10200 | groupProfileReply.GroupData.AllowPublish = d.AllowPublish; | ||
10201 | groupProfileReply.GroupData.MaturePublish = d.MaturePublish; | ||
10202 | groupProfileReply.GroupData.OwnerRole = d.OwnerRole; | ||
10203 | |||
10204 | Scene scene = (Scene)m_scene; | ||
10205 | if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID))) | ||
10206 | { | ||
10207 | ScenePresence p; | ||
10208 | if (scene.TryGetScenePresence(sender.AgentId, out p)) | ||
10209 | { | ||
10210 | if (p.GodLevel >= 200) | ||
10211 | { | ||
10212 | groupProfileReply.GroupData.OpenEnrollment = true; | ||
10213 | groupProfileReply.GroupData.MembershipFee = 0; | ||
10214 | } | ||
10215 | } | ||
10216 | } | ||
10217 | |||
10218 | OutPacket(groupProfileReply, ThrottleOutPacketType.Task); | ||
10219 | } | ||
10220 | return true; | ||
10221 | } | ||
10222 | private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack) | ||
10223 | { | ||
10224 | GroupMembersRequestPacket groupMembersRequestPacket = | ||
10225 | (GroupMembersRequestPacket)Pack; | ||
10226 | |||
10227 | #region Packet Session and User Check | ||
10228 | if (m_checkPackets) | ||
10229 | { | ||
10230 | if (groupMembersRequestPacket.AgentData.SessionID != SessionId || | ||
10231 | groupMembersRequestPacket.AgentData.AgentID != AgentId) | ||
10232 | return true; | ||
10233 | } | ||
10234 | #endregion | ||
10235 | |||
10236 | if (m_GroupsModule != null) | ||
10237 | { | ||
10238 | List<GroupMembersData> members = | ||
10239 | m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID); | ||
10240 | |||
10241 | int memberCount = members.Count; | ||
10242 | |||
10243 | while (true) | ||
10244 | { | ||
10245 | int blockCount = members.Count; | ||
10246 | if (blockCount > 40) | ||
10247 | blockCount = 40; | ||
10248 | |||
10249 | GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply); | ||
10250 | |||
10251 | groupMembersReply.AgentData = | ||
10252 | new GroupMembersReplyPacket.AgentDataBlock(); | ||
10253 | groupMembersReply.GroupData = | ||
10254 | new GroupMembersReplyPacket.GroupDataBlock(); | ||
10255 | groupMembersReply.MemberData = | ||
10256 | new GroupMembersReplyPacket.MemberDataBlock[ | ||
10257 | blockCount]; | ||
10258 | |||
10259 | groupMembersReply.AgentData.AgentID = AgentId; | ||
10260 | groupMembersReply.GroupData.GroupID = | ||
10261 | groupMembersRequestPacket.GroupData.GroupID; | ||
10262 | groupMembersReply.GroupData.RequestID = | ||
10263 | groupMembersRequestPacket.GroupData.RequestID; | ||
10264 | groupMembersReply.GroupData.MemberCount = memberCount; | ||
10265 | |||
10266 | for (int i = 0; i < blockCount; i++) | ||
10267 | { | ||
10268 | GroupMembersData m = members[0]; | ||
10269 | members.RemoveAt(0); | ||
10270 | |||
10271 | groupMembersReply.MemberData[i] = | ||
10272 | new GroupMembersReplyPacket.MemberDataBlock(); | ||
10273 | groupMembersReply.MemberData[i].AgentID = | ||
10274 | m.AgentID; | ||
10275 | groupMembersReply.MemberData[i].Contribution = | ||
10276 | m.Contribution; | ||
10277 | groupMembersReply.MemberData[i].OnlineStatus = | ||
10278 | Util.StringToBytes256(m.OnlineStatus); | ||
10279 | groupMembersReply.MemberData[i].AgentPowers = | ||
10280 | m.AgentPowers; | ||
10281 | groupMembersReply.MemberData[i].Title = | ||
10282 | Util.StringToBytes256(m.Title); | ||
10283 | groupMembersReply.MemberData[i].IsOwner = | ||
10284 | m.IsOwner; | ||
10285 | } | ||
10286 | OutPacket(groupMembersReply, ThrottleOutPacketType.Task); | ||
10287 | if (members.Count == 0) | ||
10288 | return true; | ||
10289 | } | ||
10290 | } | ||
10291 | return true; | ||
10292 | } | ||
10293 | private bool HandleGroupRoleDataRequest(IClientAPI sender, Packet Pack) | ||
10294 | { | ||
10295 | GroupRoleDataRequestPacket groupRolesRequest = | ||
10296 | (GroupRoleDataRequestPacket)Pack; | ||
10297 | |||
10298 | #region Packet Session and User Check | ||
10299 | if (m_checkPackets) | ||
10300 | { | ||
10301 | if (groupRolesRequest.AgentData.SessionID != SessionId || | ||
10302 | groupRolesRequest.AgentData.AgentID != AgentId) | ||
10303 | return true; | ||
10304 | } | ||
10305 | #endregion | ||
10306 | |||
10307 | if (m_GroupsModule != null) | ||
10308 | { | ||
10309 | GroupRoleDataReplyPacket groupRolesReply = (GroupRoleDataReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupRoleDataReply); | ||
10310 | |||
10311 | groupRolesReply.AgentData = | ||
10312 | new GroupRoleDataReplyPacket.AgentDataBlock(); | ||
10313 | |||
10314 | groupRolesReply.AgentData.AgentID = AgentId; | ||
10315 | |||
10316 | groupRolesReply.GroupData = | ||
10317 | new GroupRoleDataReplyPacket.GroupDataBlock(); | ||
10318 | |||
10319 | groupRolesReply.GroupData.GroupID = | ||
10320 | groupRolesRequest.GroupData.GroupID; | ||
10321 | |||
10322 | groupRolesReply.GroupData.RequestID = | ||
10323 | groupRolesRequest.GroupData.RequestID; | ||
10324 | |||
10325 | List<GroupRolesData> titles = | ||
10326 | m_GroupsModule.GroupRoleDataRequest(this, | ||
10327 | groupRolesRequest.GroupData.GroupID); | ||
10328 | |||
10329 | groupRolesReply.GroupData.RoleCount = | ||
10330 | titles.Count; | ||
10331 | |||
10332 | groupRolesReply.RoleData = | ||
10333 | new GroupRoleDataReplyPacket.RoleDataBlock[titles.Count]; | ||
10334 | |||
10335 | int i = 0; | ||
10336 | foreach (GroupRolesData d in titles) | ||
10337 | { | ||
10338 | groupRolesReply.RoleData[i] = | ||
10339 | new GroupRoleDataReplyPacket.RoleDataBlock(); | ||
10340 | |||
10341 | groupRolesReply.RoleData[i].RoleID = | ||
10342 | d.RoleID; | ||
10343 | groupRolesReply.RoleData[i].Name = | ||
10344 | Util.StringToBytes256(d.Name); | ||
10345 | groupRolesReply.RoleData[i].Title = | ||
10346 | Util.StringToBytes256(d.Title); | ||
10347 | groupRolesReply.RoleData[i].Description = | ||
10348 | Util.StringToBytes1024(d.Description); | ||
10349 | groupRolesReply.RoleData[i].Powers = | ||
10350 | d.Powers; | ||
10351 | groupRolesReply.RoleData[i].Members = | ||
10352 | (uint)d.Members; | ||
10353 | |||
10354 | i++; | ||
10355 | } | ||
10356 | |||
10357 | OutPacket(groupRolesReply, ThrottleOutPacketType.Task); | ||
10358 | } | ||
10359 | return true; | ||
10360 | } | ||
10361 | private bool HandleGroupRoleMembersRequest(IClientAPI sender, Packet Pack) | ||
10362 | { | ||
10363 | GroupRoleMembersRequestPacket groupRoleMembersRequest = | ||
10364 | (GroupRoleMembersRequestPacket)Pack; | ||
10365 | |||
10366 | #region Packet Session and User Check | ||
10367 | if (m_checkPackets) | ||
10368 | { | ||
10369 | if (groupRoleMembersRequest.AgentData.SessionID != SessionId || | ||
10370 | groupRoleMembersRequest.AgentData.AgentID != AgentId) | ||
10371 | return true; | ||
10372 | } | ||
10373 | #endregion | ||
10374 | |||
10375 | if (m_GroupsModule != null) | ||
10376 | { | ||
10377 | List<GroupRoleMembersData> mappings = | ||
10378 | m_GroupsModule.GroupRoleMembersRequest(this, | ||
10379 | groupRoleMembersRequest.GroupData.GroupID); | ||
10380 | |||
10381 | int mappingsCount = mappings.Count; | ||
10382 | |||
10383 | while (mappings.Count > 0) | ||
10384 | { | ||
10385 | int pairs = mappings.Count; | ||
10386 | if (pairs > 32) | ||
10387 | pairs = 32; | ||
10388 | |||
10389 | GroupRoleMembersReplyPacket groupRoleMembersReply = (GroupRoleMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupRoleMembersReply); | ||
10390 | groupRoleMembersReply.AgentData = | ||
10391 | new GroupRoleMembersReplyPacket.AgentDataBlock(); | ||
10392 | groupRoleMembersReply.AgentData.AgentID = | ||
10393 | AgentId; | ||
10394 | groupRoleMembersReply.AgentData.GroupID = | ||
10395 | groupRoleMembersRequest.GroupData.GroupID; | ||
10396 | groupRoleMembersReply.AgentData.RequestID = | ||
10397 | groupRoleMembersRequest.GroupData.RequestID; | ||
10398 | |||
10399 | groupRoleMembersReply.AgentData.TotalPairs = | ||
10400 | (uint)mappingsCount; | ||
10401 | |||
10402 | groupRoleMembersReply.MemberData = | ||
10403 | new GroupRoleMembersReplyPacket.MemberDataBlock[pairs]; | ||
10404 | |||
10405 | for (int i = 0; i < pairs; i++) | ||
10406 | { | ||
10407 | GroupRoleMembersData d = mappings[0]; | ||
10408 | mappings.RemoveAt(0); | ||
10409 | |||
10410 | groupRoleMembersReply.MemberData[i] = | ||
10411 | new GroupRoleMembersReplyPacket.MemberDataBlock(); | ||
10412 | |||
10413 | groupRoleMembersReply.MemberData[i].RoleID = | ||
10414 | d.RoleID; | ||
10415 | groupRoleMembersReply.MemberData[i].MemberID = | ||
10416 | d.MemberID; | ||
10417 | } | ||
10418 | |||
10419 | OutPacket(groupRoleMembersReply, ThrottleOutPacketType.Task); | ||
10420 | } | ||
10421 | } | ||
10422 | return true; | ||
10423 | } | ||
10424 | private bool HandleCreateGroupRequest(IClientAPI sender, Packet Pack) | ||
10425 | { | ||
10426 | CreateGroupRequestPacket createGroupRequest = | ||
10427 | (CreateGroupRequestPacket)Pack; | ||
10428 | |||
10429 | #region Packet Session and User Check | ||
10430 | if (m_checkPackets) | ||
10431 | { | ||
10432 | if (createGroupRequest.AgentData.SessionID != SessionId || | ||
10433 | createGroupRequest.AgentData.AgentID != AgentId) | ||
10434 | return true; | ||
10435 | } | ||
10436 | #endregion | ||
10437 | |||
10438 | if (m_GroupsModule != null) | ||
10439 | { | ||
10440 | m_GroupsModule.CreateGroup(this, | ||
10441 | Utils.BytesToString(createGroupRequest.GroupData.Name), | ||
10442 | Utils.BytesToString(createGroupRequest.GroupData.Charter), | ||
10443 | createGroupRequest.GroupData.ShowInList, | ||
10444 | createGroupRequest.GroupData.InsigniaID, | ||
10445 | createGroupRequest.GroupData.MembershipFee, | ||
10446 | createGroupRequest.GroupData.OpenEnrollment, | ||
10447 | createGroupRequest.GroupData.AllowPublish, | ||
10448 | createGroupRequest.GroupData.MaturePublish); | ||
10449 | } | ||
10450 | return true; | ||
10451 | } | ||
10452 | private bool HandleUpdateGroupInfo(IClientAPI sender, Packet Pack) | ||
10453 | { | ||
10454 | UpdateGroupInfoPacket updateGroupInfo = | ||
10455 | (UpdateGroupInfoPacket)Pack; | ||
10456 | |||
10457 | #region Packet Session and User Check | ||
10458 | if (m_checkPackets) | ||
10459 | { | ||
10460 | if (updateGroupInfo.AgentData.SessionID != SessionId || | ||
10461 | updateGroupInfo.AgentData.AgentID != AgentId) | ||
10462 | return true; | ||
10463 | } | ||
10464 | #endregion | ||
10465 | |||
10466 | if (m_GroupsModule != null) | ||
10467 | { | ||
10468 | m_GroupsModule.UpdateGroupInfo(this, | ||
10469 | updateGroupInfo.GroupData.GroupID, | ||
10470 | Utils.BytesToString(updateGroupInfo.GroupData.Charter), | ||
10471 | updateGroupInfo.GroupData.ShowInList, | ||
10472 | updateGroupInfo.GroupData.InsigniaID, | ||
10473 | updateGroupInfo.GroupData.MembershipFee, | ||
10474 | updateGroupInfo.GroupData.OpenEnrollment, | ||
10475 | updateGroupInfo.GroupData.AllowPublish, | ||
10476 | updateGroupInfo.GroupData.MaturePublish); | ||
10477 | } | ||
10478 | |||
10479 | return true; | ||
10480 | } | ||
10481 | private bool HandleSetGroupAcceptNotices(IClientAPI sender, Packet Pack) | ||
10482 | { | ||
10483 | SetGroupAcceptNoticesPacket setGroupAcceptNotices = | ||
10484 | (SetGroupAcceptNoticesPacket)Pack; | ||
10485 | |||
10486 | #region Packet Session and User Check | ||
10487 | if (m_checkPackets) | ||
10488 | { | ||
10489 | if (setGroupAcceptNotices.AgentData.SessionID != SessionId || | ||
10490 | setGroupAcceptNotices.AgentData.AgentID != AgentId) | ||
10491 | return true; | ||
10492 | } | ||
10493 | #endregion | ||
10494 | |||
10495 | if (m_GroupsModule != null) | ||
10496 | { | ||
10497 | m_GroupsModule.SetGroupAcceptNotices(this, | ||
10498 | setGroupAcceptNotices.Data.GroupID, | ||
10499 | setGroupAcceptNotices.Data.AcceptNotices, | ||
10500 | setGroupAcceptNotices.NewData.ListInProfile); | ||
10501 | } | ||
10502 | |||
10503 | return true; | ||
10504 | } | ||
10505 | private bool HandleGroupTitleUpdate(IClientAPI sender, Packet Pack) | ||
10506 | { | ||
10507 | GroupTitleUpdatePacket groupTitleUpdate = | ||
10508 | (GroupTitleUpdatePacket)Pack; | ||
10509 | |||
10510 | #region Packet Session and User Check | ||
10511 | if (m_checkPackets) | ||
10512 | { | ||
10513 | if (groupTitleUpdate.AgentData.SessionID != SessionId || | ||
10514 | groupTitleUpdate.AgentData.AgentID != AgentId) | ||
10515 | return true; | ||
10516 | } | ||
10517 | #endregion | ||
10518 | |||
10519 | if (m_GroupsModule != null) | ||
10520 | { | ||
10521 | m_GroupsModule.GroupTitleUpdate(this, | ||
10522 | groupTitleUpdate.AgentData.GroupID, | ||
10523 | groupTitleUpdate.AgentData.TitleRoleID); | ||
10524 | } | ||
10525 | |||
10526 | return true; | ||
10527 | } | ||
10528 | private bool HandleParcelDeedToGroup(IClientAPI sender, Packet Pack) | ||
10529 | { | ||
10530 | ParcelDeedToGroupPacket parcelDeedToGroup = (ParcelDeedToGroupPacket)Pack; | ||
10531 | if (m_GroupsModule != null) | ||
10532 | { | ||
10533 | ParcelDeedToGroup handlerParcelDeedToGroup = OnParcelDeedToGroup; | ||
10534 | if (handlerParcelDeedToGroup != null) | ||
10535 | { | ||
10536 | handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID, this); | ||
10537 | |||
10538 | } | ||
10539 | } | ||
10540 | |||
10541 | return true; | ||
10542 | } | ||
10543 | private bool HandleGroupNoticesListRequest(IClientAPI sender, Packet Pack) | ||
10544 | { | ||
10545 | GroupNoticesListRequestPacket groupNoticesListRequest = | ||
10546 | (GroupNoticesListRequestPacket)Pack; | ||
10547 | |||
10548 | #region Packet Session and User Check | ||
10549 | if (m_checkPackets) | ||
10550 | { | ||
10551 | if (groupNoticesListRequest.AgentData.SessionID != SessionId || | ||
10552 | groupNoticesListRequest.AgentData.AgentID != AgentId) | ||
10553 | return true; | ||
10554 | } | ||
10555 | #endregion | ||
10556 | |||
10557 | if (m_GroupsModule != null) | ||
10558 | { | ||
10559 | GroupNoticeData[] gn = | ||
10560 | m_GroupsModule.GroupNoticesListRequest(this, | ||
10561 | groupNoticesListRequest.Data.GroupID); | ||
10562 | |||
10563 | GroupNoticesListReplyPacket groupNoticesListReply = (GroupNoticesListReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupNoticesListReply); | ||
10564 | groupNoticesListReply.AgentData = | ||
10565 | new GroupNoticesListReplyPacket.AgentDataBlock(); | ||
10566 | groupNoticesListReply.AgentData.AgentID = AgentId; | ||
10567 | groupNoticesListReply.AgentData.GroupID = groupNoticesListRequest.Data.GroupID; | ||
10568 | |||
10569 | groupNoticesListReply.Data = new GroupNoticesListReplyPacket.DataBlock[gn.Length]; | ||
10570 | |||
10571 | int i = 0; | ||
10572 | foreach (GroupNoticeData g in gn) | ||
10573 | { | ||
10574 | groupNoticesListReply.Data[i] = new GroupNoticesListReplyPacket.DataBlock(); | ||
10575 | groupNoticesListReply.Data[i].NoticeID = | ||
10576 | g.NoticeID; | ||
10577 | groupNoticesListReply.Data[i].Timestamp = | ||
10578 | g.Timestamp; | ||
10579 | groupNoticesListReply.Data[i].FromName = | ||
10580 | Util.StringToBytes256(g.FromName); | ||
10581 | groupNoticesListReply.Data[i].Subject = | ||
10582 | Util.StringToBytes256(g.Subject); | ||
10583 | groupNoticesListReply.Data[i].HasAttachment = | ||
10584 | g.HasAttachment; | ||
10585 | groupNoticesListReply.Data[i].AssetType = | ||
10586 | g.AssetType; | ||
10587 | i++; | ||
10588 | } | ||
10589 | |||
10590 | OutPacket(groupNoticesListReply, ThrottleOutPacketType.Task); | ||
10591 | } | ||
10592 | |||
10593 | return true; | ||
10594 | } | ||
10595 | private bool HandleGroupNoticeRequest(IClientAPI sender, Packet Pack) | ||
10596 | { | ||
10597 | GroupNoticeRequestPacket groupNoticeRequest = | ||
10598 | (GroupNoticeRequestPacket)Pack; | ||
10599 | |||
10600 | #region Packet Session and User Check | ||
10601 | if (m_checkPackets) | ||
10602 | { | ||
10603 | if (groupNoticeRequest.AgentData.SessionID != SessionId || | ||
10604 | groupNoticeRequest.AgentData.AgentID != AgentId) | ||
10605 | return true; | ||
10606 | } | ||
10607 | #endregion | ||
10608 | |||
10609 | if (m_GroupsModule != null) | ||
10610 | { | ||
10611 | m_GroupsModule.GroupNoticeRequest(this, | ||
10612 | groupNoticeRequest.Data.GroupNoticeID); | ||
10613 | } | ||
10614 | return true; | ||
10615 | } | ||
10616 | private bool HandleGroupRoleUpdate(IClientAPI sender, Packet Pack) | ||
10617 | { | ||
10618 | GroupRoleUpdatePacket groupRoleUpdate = | ||
10619 | (GroupRoleUpdatePacket)Pack; | ||
10620 | |||
10621 | #region Packet Session and User Check | ||
10622 | if (m_checkPackets) | ||
10623 | { | ||
10624 | if (groupRoleUpdate.AgentData.SessionID != SessionId || | ||
10625 | groupRoleUpdate.AgentData.AgentID != AgentId) | ||
10626 | return true; | ||
10627 | } | ||
10628 | #endregion | ||
10629 | |||
10630 | if (m_GroupsModule != null) | ||
10631 | { | ||
10632 | foreach (GroupRoleUpdatePacket.RoleDataBlock d in | ||
10633 | groupRoleUpdate.RoleData) | ||
10634 | { | ||
10635 | m_GroupsModule.GroupRoleUpdate(this, | ||
10636 | groupRoleUpdate.AgentData.GroupID, | ||
10637 | d.RoleID, | ||
10638 | Utils.BytesToString(d.Name), | ||
10639 | Utils.BytesToString(d.Description), | ||
10640 | Utils.BytesToString(d.Title), | ||
10641 | d.Powers, | ||
10642 | d.UpdateType); | ||
10643 | } | ||
10644 | m_GroupsModule.NotifyChange(groupRoleUpdate.AgentData.GroupID); | ||
10645 | } | ||
10646 | return true; | ||
10647 | } | ||
10648 | private bool HandleGroupRoleChanges(IClientAPI sender, Packet Pack) | ||
10649 | { | ||
10650 | GroupRoleChangesPacket groupRoleChanges = | ||
10651 | (GroupRoleChangesPacket)Pack; | ||
10652 | |||
10653 | #region Packet Session and User Check | ||
10654 | if (m_checkPackets) | ||
10655 | { | ||
10656 | if (groupRoleChanges.AgentData.SessionID != SessionId || | ||
10657 | groupRoleChanges.AgentData.AgentID != AgentId) | ||
10658 | return true; | ||
10659 | } | ||
10660 | #endregion | ||
10661 | |||
10662 | if (m_GroupsModule != null) | ||
10663 | { | ||
10664 | foreach (GroupRoleChangesPacket.RoleChangeBlock d in | ||
10665 | groupRoleChanges.RoleChange) | ||
10666 | { | ||
10667 | m_GroupsModule.GroupRoleChanges(this, | ||
10668 | groupRoleChanges.AgentData.GroupID, | ||
10669 | d.RoleID, | ||
10670 | d.MemberID, | ||
10671 | d.Change); | ||
10672 | } | ||
10673 | m_GroupsModule.NotifyChange(groupRoleChanges.AgentData.GroupID); | ||
10674 | } | ||
10675 | return true; | ||
10676 | } | ||
10677 | private bool HandleJoinGroupRequest(IClientAPI sender, Packet Pack) | ||
10678 | { | ||
10679 | JoinGroupRequestPacket joinGroupRequest = | ||
10680 | (JoinGroupRequestPacket)Pack; | ||
10681 | |||
10682 | #region Packet Session and User Check | ||
10683 | if (m_checkPackets) | ||
10684 | { | ||
10685 | if (joinGroupRequest.AgentData.SessionID != SessionId || | ||
10686 | joinGroupRequest.AgentData.AgentID != AgentId) | ||
10687 | return true; | ||
10688 | } | ||
10689 | #endregion | ||
10690 | |||
10691 | if (m_GroupsModule != null) | ||
10692 | { | ||
10693 | m_GroupsModule.JoinGroupRequest(this, | ||
10694 | joinGroupRequest.GroupData.GroupID); | ||
10695 | } | ||
10696 | return true; | ||
10697 | } | ||
10698 | private bool HandleLeaveGroupRequest(IClientAPI sender, Packet Pack) | ||
10699 | { | ||
10700 | LeaveGroupRequestPacket leaveGroupRequest = | ||
10701 | (LeaveGroupRequestPacket)Pack; | ||
10702 | |||
10703 | #region Packet Session and User Check | ||
10704 | if (m_checkPackets) | ||
10705 | { | ||
10706 | if (leaveGroupRequest.AgentData.SessionID != SessionId || | ||
10707 | leaveGroupRequest.AgentData.AgentID != AgentId) | ||
10708 | return true; | ||
10709 | } | ||
10710 | #endregion | ||
10711 | |||
10712 | if (m_GroupsModule != null) | ||
10713 | { | ||
10714 | m_GroupsModule.LeaveGroupRequest(this, | ||
10715 | leaveGroupRequest.GroupData.GroupID); | ||
10716 | } | ||
10717 | return true; | ||
10718 | } | ||
10719 | private bool HandleEjectGroupMemberRequest(IClientAPI sender, Packet Pack) | ||
10720 | { | ||
10721 | EjectGroupMemberRequestPacket ejectGroupMemberRequest = | ||
10722 | (EjectGroupMemberRequestPacket)Pack; | ||
10723 | |||
10724 | #region Packet Session and User Check | ||
10725 | if (m_checkPackets) | ||
10726 | { | ||
10727 | if (ejectGroupMemberRequest.AgentData.SessionID != SessionId || | ||
10728 | ejectGroupMemberRequest.AgentData.AgentID != AgentId) | ||
10729 | return true; | ||
10730 | } | ||
10731 | #endregion | ||
10732 | |||
10733 | if (m_GroupsModule != null) | ||
10734 | { | ||
10735 | foreach (EjectGroupMemberRequestPacket.EjectDataBlock e | ||
10736 | in ejectGroupMemberRequest.EjectData) | ||
10737 | { | ||
10738 | m_GroupsModule.EjectGroupMemberRequest(this, | ||
10739 | ejectGroupMemberRequest.GroupData.GroupID, | ||
10740 | e.EjecteeID); | ||
10741 | } | ||
10742 | } | ||
10743 | return true; | ||
10744 | } | ||
10745 | private bool HandleInviteGroupRequest(IClientAPI sender, Packet Pack) | ||
10746 | { | ||
10747 | InviteGroupRequestPacket inviteGroupRequest = | ||
10748 | (InviteGroupRequestPacket)Pack; | ||
10749 | |||
10750 | #region Packet Session and User Check | ||
10751 | if (m_checkPackets) | ||
10752 | { | ||
10753 | if (inviteGroupRequest.AgentData.SessionID != SessionId || | ||
10754 | inviteGroupRequest.AgentData.AgentID != AgentId) | ||
10755 | return true; | ||
10756 | } | ||
10757 | #endregion | ||
10758 | |||
10759 | if (m_GroupsModule != null) | ||
10760 | { | ||
10761 | foreach (InviteGroupRequestPacket.InviteDataBlock b in | ||
10762 | inviteGroupRequest.InviteData) | ||
10763 | { | ||
10764 | m_GroupsModule.InviteGroupRequest(this, | ||
10765 | inviteGroupRequest.GroupData.GroupID, | ||
10766 | b.InviteeID, | ||
10767 | b.RoleID); | ||
10768 | } | ||
10769 | } | ||
10770 | return true; | ||
10771 | } | ||
10772 | |||
10773 | #endregion Groups | ||
10774 | |||
10775 | private bool HandleStartLure(IClientAPI sender, Packet Pack) | ||
10776 | { | ||
10777 | StartLurePacket startLureRequest = (StartLurePacket)Pack; | ||
10778 | |||
10779 | #region Packet Session and User Check | ||
10780 | if (m_checkPackets) | ||
10781 | { | ||
10782 | if (startLureRequest.AgentData.SessionID != SessionId || | ||
10783 | startLureRequest.AgentData.AgentID != AgentId) | ||
10784 | return true; | ||
10785 | } | ||
10786 | #endregion | ||
10787 | |||
10788 | StartLure handlerStartLure = OnStartLure; | ||
10789 | if (handlerStartLure != null) | ||
10790 | { | ||
10791 | for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++) | ||
10792 | { | ||
10793 | handlerStartLure(startLureRequest.Info.LureType, | ||
10794 | Utils.BytesToString( | ||
10795 | startLureRequest.Info.Message), | ||
10796 | startLureRequest.TargetData[i].TargetID, | ||
10797 | this); | ||
10798 | } | ||
10799 | } | ||
10800 | return true; | ||
10801 | } | ||
10802 | private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) | ||
10803 | { | ||
10804 | TeleportLureRequestPacket teleportLureRequest = | ||
10805 | (TeleportLureRequestPacket)Pack; | ||
10806 | |||
10807 | #region Packet Session and User Check | ||
10808 | if (m_checkPackets) | ||
10809 | { | ||
10810 | if (teleportLureRequest.Info.SessionID != SessionId || | ||
10811 | teleportLureRequest.Info.AgentID != AgentId) | ||
10812 | return true; | ||
10813 | } | ||
10814 | #endregion | ||
10815 | |||
10816 | TeleportLureRequest handlerTeleportLureRequest = OnTeleportLureRequest; | ||
10817 | if (handlerTeleportLureRequest != null) | ||
10818 | handlerTeleportLureRequest( | ||
10819 | teleportLureRequest.Info.LureID, | ||
10820 | teleportLureRequest.Info.TeleportFlags, | ||
10821 | this); | ||
10822 | return true; | ||
10823 | } | ||
10824 | private bool HandleClassifiedInfoRequest(IClientAPI sender, Packet Pack) | ||
10825 | { | ||
10826 | ClassifiedInfoRequestPacket classifiedInfoRequest = | ||
10827 | (ClassifiedInfoRequestPacket)Pack; | ||
10828 | |||
10829 | #region Packet Session and User Check | ||
10830 | if (m_checkPackets) | ||
10831 | { | ||
10832 | if (classifiedInfoRequest.AgentData.SessionID != SessionId || | ||
10833 | classifiedInfoRequest.AgentData.AgentID != AgentId) | ||
10834 | return true; | ||
10835 | } | ||
10836 | #endregion | ||
10837 | |||
10838 | ClassifiedInfoRequest handlerClassifiedInfoRequest = OnClassifiedInfoRequest; | ||
10839 | if (handlerClassifiedInfoRequest != null) | ||
10840 | handlerClassifiedInfoRequest( | ||
10841 | classifiedInfoRequest.Data.ClassifiedID, | ||
10842 | this); | ||
10843 | return true; | ||
10844 | } | ||
10845 | private bool HandleClassifiedInfoUpdate(IClientAPI sender, Packet Pack) | ||
10846 | { | ||
10847 | ClassifiedInfoUpdatePacket classifiedInfoUpdate = | ||
10848 | (ClassifiedInfoUpdatePacket)Pack; | ||
10849 | |||
10850 | #region Packet Session and User Check | ||
10851 | if (m_checkPackets) | ||
10852 | { | ||
10853 | if (classifiedInfoUpdate.AgentData.SessionID != SessionId || | ||
10854 | classifiedInfoUpdate.AgentData.AgentID != AgentId) | ||
10855 | return true; | ||
10856 | } | ||
10857 | #endregion | ||
10858 | |||
10859 | ClassifiedInfoUpdate handlerClassifiedInfoUpdate = OnClassifiedInfoUpdate; | ||
10860 | if (handlerClassifiedInfoUpdate != null) | ||
10861 | handlerClassifiedInfoUpdate( | ||
10862 | classifiedInfoUpdate.Data.ClassifiedID, | ||
10863 | classifiedInfoUpdate.Data.Category, | ||
10864 | Utils.BytesToString( | ||
10865 | classifiedInfoUpdate.Data.Name), | ||
10866 | Utils.BytesToString( | ||
10867 | classifiedInfoUpdate.Data.Desc), | ||
10868 | classifiedInfoUpdate.Data.ParcelID, | ||
10869 | classifiedInfoUpdate.Data.ParentEstate, | ||
10870 | classifiedInfoUpdate.Data.SnapshotID, | ||
10871 | new Vector3( | ||
10872 | classifiedInfoUpdate.Data.PosGlobal), | ||
10873 | classifiedInfoUpdate.Data.ClassifiedFlags, | ||
10874 | classifiedInfoUpdate.Data.PriceForListing, | ||
10875 | this); | ||
10876 | return true; | ||
10877 | } | ||
10878 | private bool HandleClassifiedDelete(IClientAPI sender, Packet Pack) | ||
10879 | { | ||
10880 | ClassifiedDeletePacket classifiedDelete = | ||
10881 | (ClassifiedDeletePacket)Pack; | ||
10882 | |||
10883 | #region Packet Session and User Check | ||
10884 | if (m_checkPackets) | ||
10885 | { | ||
10886 | if (classifiedDelete.AgentData.SessionID != SessionId || | ||
10887 | classifiedDelete.AgentData.AgentID != AgentId) | ||
10888 | return true; | ||
10889 | } | ||
10890 | #endregion | ||
10891 | |||
10892 | ClassifiedDelete handlerClassifiedDelete = OnClassifiedDelete; | ||
10893 | if (handlerClassifiedDelete != null) | ||
10894 | handlerClassifiedDelete( | ||
10895 | classifiedDelete.Data.ClassifiedID, | ||
10896 | this); | ||
10897 | return true; | ||
10898 | } | ||
10899 | private bool HandleClassifiedGodDelete(IClientAPI sender, Packet Pack) | ||
10900 | { | ||
10901 | ClassifiedGodDeletePacket classifiedGodDelete = | ||
10902 | (ClassifiedGodDeletePacket)Pack; | ||
10903 | |||
10904 | #region Packet Session and User Check | ||
10905 | if (m_checkPackets) | ||
10906 | { | ||
10907 | if (classifiedGodDelete.AgentData.SessionID != SessionId || | ||
10908 | classifiedGodDelete.AgentData.AgentID != AgentId) | ||
10909 | return true; | ||
10910 | } | ||
10911 | #endregion | ||
10912 | |||
10913 | ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; | ||
10914 | if (handlerClassifiedGodDelete != null) | ||
10915 | handlerClassifiedGodDelete( | ||
10916 | classifiedGodDelete.Data.ClassifiedID, | ||
10917 | classifiedGodDelete.Data.QueryID, | ||
10918 | this); | ||
10919 | return true; | ||
10920 | } | ||
10921 | private bool HandleEventGodDelete(IClientAPI sender, Packet Pack) | ||
10922 | { | ||
10923 | EventGodDeletePacket eventGodDelete = | ||
10924 | (EventGodDeletePacket)Pack; | ||
10925 | |||
10926 | #region Packet Session and User Check | ||
10927 | if (m_checkPackets) | ||
10928 | { | ||
10929 | if (eventGodDelete.AgentData.SessionID != SessionId || | ||
10930 | eventGodDelete.AgentData.AgentID != AgentId) | ||
10931 | return true; | ||
10932 | } | ||
10933 | #endregion | ||
10934 | |||
10935 | EventGodDelete handlerEventGodDelete = OnEventGodDelete; | ||
10936 | if (handlerEventGodDelete != null) | ||
10937 | handlerEventGodDelete( | ||
10938 | eventGodDelete.EventData.EventID, | ||
10939 | eventGodDelete.QueryData.QueryID, | ||
10940 | Utils.BytesToString( | ||
10941 | eventGodDelete.QueryData.QueryText), | ||
10942 | eventGodDelete.QueryData.QueryFlags, | ||
10943 | eventGodDelete.QueryData.QueryStart, | ||
10944 | this); | ||
10945 | return true; | ||
10946 | } | ||
10947 | private bool HandleEventNotificationAddRequest(IClientAPI sender, Packet Pack) | ||
10948 | { | ||
10949 | EventNotificationAddRequestPacket eventNotificationAdd = | ||
10950 | (EventNotificationAddRequestPacket)Pack; | ||
10951 | |||
10952 | #region Packet Session and User Check | ||
10953 | if (m_checkPackets) | ||
10954 | { | ||
10955 | if (eventNotificationAdd.AgentData.SessionID != SessionId || | ||
10956 | eventNotificationAdd.AgentData.AgentID != AgentId) | ||
10957 | return true; | ||
10958 | } | ||
10959 | #endregion | ||
10960 | |||
10961 | EventNotificationAddRequest handlerEventNotificationAddRequest = OnEventNotificationAddRequest; | ||
10962 | if (handlerEventNotificationAddRequest != null) | ||
10963 | handlerEventNotificationAddRequest( | ||
10964 | eventNotificationAdd.EventData.EventID, this); | ||
10965 | return true; | ||
10966 | } | ||
10967 | private bool HandleEventNotificationRemoveRequest(IClientAPI sender, Packet Pack) | ||
10968 | { | ||
10969 | EventNotificationRemoveRequestPacket eventNotificationRemove = | ||
10970 | (EventNotificationRemoveRequestPacket)Pack; | ||
10971 | |||
10972 | #region Packet Session and User Check | ||
10973 | if (m_checkPackets) | ||
10974 | { | ||
10975 | if (eventNotificationRemove.AgentData.SessionID != SessionId || | ||
10976 | eventNotificationRemove.AgentData.AgentID != AgentId) | ||
10977 | return true; | ||
10978 | } | ||
10979 | #endregion | ||
10980 | |||
10981 | EventNotificationRemoveRequest handlerEventNotificationRemoveRequest = OnEventNotificationRemoveRequest; | ||
10982 | if (handlerEventNotificationRemoveRequest != null) | ||
10983 | handlerEventNotificationRemoveRequest( | ||
10984 | eventNotificationRemove.EventData.EventID, this); | ||
10985 | return true; | ||
10986 | } | ||
10987 | private bool HandleRetrieveInstantMessages(IClientAPI sender, Packet Pack) | ||
10988 | { | ||
10989 | RetrieveInstantMessagesPacket rimpInstantMessagePack = (RetrieveInstantMessagesPacket)Pack; | ||
10990 | |||
10991 | #region Packet Session and User Check | ||
10992 | if (m_checkPackets) | ||
10993 | { | ||
10994 | if (rimpInstantMessagePack.AgentData.SessionID != SessionId || | ||
10995 | rimpInstantMessagePack.AgentData.AgentID != AgentId) | ||
10996 | return true; | ||
10997 | } | ||
10998 | #endregion | ||
10999 | |||
11000 | RetrieveInstantMessages handlerRetrieveInstantMessages = OnRetrieveInstantMessages; | ||
11001 | if (handlerRetrieveInstantMessages != null) | ||
11002 | handlerRetrieveInstantMessages(this); | ||
11003 | return true; | ||
11004 | } | ||
11005 | private bool HandlePickDelete(IClientAPI sender, Packet Pack) | ||
11006 | { | ||
11007 | PickDeletePacket pickDelete = | ||
11008 | (PickDeletePacket)Pack; | ||
11009 | |||
11010 | #region Packet Session and User Check | ||
11011 | if (m_checkPackets) | ||
11012 | { | ||
11013 | if (pickDelete.AgentData.SessionID != SessionId || | ||
11014 | pickDelete.AgentData.AgentID != AgentId) | ||
11015 | return true; | ||
11016 | } | ||
11017 | #endregion | ||
11018 | |||
11019 | PickDelete handlerPickDelete = OnPickDelete; | ||
11020 | if (handlerPickDelete != null) | ||
11021 | handlerPickDelete(this, pickDelete.Data.PickID); | ||
11022 | return true; | ||
11023 | } | ||
11024 | private bool HandlePickGodDelete(IClientAPI sender, Packet Pack) | ||
11025 | { | ||
11026 | PickGodDeletePacket pickGodDelete = | ||
11027 | (PickGodDeletePacket)Pack; | ||
11028 | |||
11029 | #region Packet Session and User Check | ||
11030 | if (m_checkPackets) | ||
11031 | { | ||
11032 | if (pickGodDelete.AgentData.SessionID != SessionId || | ||
11033 | pickGodDelete.AgentData.AgentID != AgentId) | ||
11034 | return true; | ||
11035 | } | ||
11036 | #endregion | ||
11037 | |||
11038 | PickGodDelete handlerPickGodDelete = OnPickGodDelete; | ||
11039 | if (handlerPickGodDelete != null) | ||
11040 | handlerPickGodDelete(this, | ||
11041 | pickGodDelete.AgentData.AgentID, | ||
11042 | pickGodDelete.Data.PickID, | ||
11043 | pickGodDelete.Data.QueryID); | ||
11044 | return true; | ||
11045 | } | ||
11046 | private bool HandlePickInfoUpdate(IClientAPI sender, Packet Pack) | ||
11047 | { | ||
11048 | PickInfoUpdatePacket pickInfoUpdate = | ||
11049 | (PickInfoUpdatePacket)Pack; | ||
11050 | |||
11051 | #region Packet Session and User Check | ||
11052 | if (m_checkPackets) | ||
11053 | { | ||
11054 | if (pickInfoUpdate.AgentData.SessionID != SessionId || | ||
11055 | pickInfoUpdate.AgentData.AgentID != AgentId) | ||
11056 | return true; | ||
11057 | } | ||
11058 | #endregion | ||
11059 | |||
11060 | PickInfoUpdate handlerPickInfoUpdate = OnPickInfoUpdate; | ||
11061 | if (handlerPickInfoUpdate != null) | ||
11062 | handlerPickInfoUpdate(this, | ||
11063 | pickInfoUpdate.Data.PickID, | ||
11064 | pickInfoUpdate.Data.CreatorID, | ||
11065 | pickInfoUpdate.Data.TopPick, | ||
11066 | Utils.BytesToString(pickInfoUpdate.Data.Name), | ||
11067 | Utils.BytesToString(pickInfoUpdate.Data.Desc), | ||
11068 | pickInfoUpdate.Data.SnapshotID, | ||
11069 | pickInfoUpdate.Data.SortOrder, | ||
11070 | pickInfoUpdate.Data.Enabled); | ||
11071 | return true; | ||
11072 | } | ||
11073 | private bool HandleAvatarNotesUpdate(IClientAPI sender, Packet Pack) | ||
11074 | { | ||
11075 | AvatarNotesUpdatePacket avatarNotesUpdate = | ||
11076 | (AvatarNotesUpdatePacket)Pack; | ||
11077 | |||
11078 | #region Packet Session and User Check | ||
11079 | if (m_checkPackets) | ||
11080 | { | ||
11081 | if (avatarNotesUpdate.AgentData.SessionID != SessionId || | ||
11082 | avatarNotesUpdate.AgentData.AgentID != AgentId) | ||
11083 | return true; | ||
11084 | } | ||
11085 | #endregion | ||
11086 | |||
11087 | AvatarNotesUpdate handlerAvatarNotesUpdate = OnAvatarNotesUpdate; | ||
11088 | if (handlerAvatarNotesUpdate != null) | ||
11089 | handlerAvatarNotesUpdate(this, | ||
11090 | avatarNotesUpdate.Data.TargetID, | ||
11091 | Utils.BytesToString(avatarNotesUpdate.Data.Notes)); | ||
11092 | return true; | ||
11093 | } | ||
11094 | private bool HandleAvatarInterestsUpdate(IClientAPI sender, Packet Pack) | ||
11095 | { | ||
11096 | AvatarInterestsUpdatePacket avatarInterestUpdate = | ||
11097 | (AvatarInterestsUpdatePacket)Pack; | ||
11098 | |||
11099 | #region Packet Session and User Check | ||
11100 | if (m_checkPackets) | ||
11101 | { | ||
11102 | if (avatarInterestUpdate.AgentData.SessionID != SessionId || | ||
11103 | avatarInterestUpdate.AgentData.AgentID != AgentId) | ||
11104 | return true; | ||
11105 | } | ||
11106 | #endregion | ||
11107 | |||
11108 | AvatarInterestUpdate handlerAvatarInterestUpdate = OnAvatarInterestUpdate; | ||
11109 | if (handlerAvatarInterestUpdate != null) | ||
11110 | handlerAvatarInterestUpdate(this, | ||
11111 | avatarInterestUpdate.PropertiesData.WantToMask, | ||
11112 | Utils.BytesToString(avatarInterestUpdate.PropertiesData.WantToText), | ||
11113 | avatarInterestUpdate.PropertiesData.SkillsMask, | ||
11114 | Utils.BytesToString(avatarInterestUpdate.PropertiesData.SkillsText), | ||
11115 | Utils.BytesToString(avatarInterestUpdate.PropertiesData.LanguagesText)); | ||
11116 | return true; | ||
11117 | } | ||
11118 | private bool HandleGrantUserRights(IClientAPI sender, Packet Pack) | ||
11119 | { | ||
11120 | GrantUserRightsPacket GrantUserRights = | ||
11121 | (GrantUserRightsPacket)Pack; | ||
11122 | #region Packet Session and User Check | ||
11123 | if (m_checkPackets) | ||
11124 | { | ||
11125 | if (GrantUserRights.AgentData.SessionID != SessionId || | ||
11126 | GrantUserRights.AgentData.AgentID != AgentId) | ||
11127 | return true; | ||
11128 | } | ||
11129 | #endregion | ||
11130 | GrantUserFriendRights GrantUserRightsHandler = OnGrantUserRights; | ||
11131 | if (GrantUserRightsHandler != null) | ||
11132 | GrantUserRightsHandler(this, | ||
11133 | GrantUserRights.AgentData.AgentID, | ||
11134 | GrantUserRights.Rights[0].AgentRelated, | ||
11135 | GrantUserRights.Rights[0].RelatedRights); | ||
11136 | return true; | ||
11137 | } | ||
11138 | private bool HandlePlacesQuery(IClientAPI sender, Packet Pack) | ||
11139 | { | ||
11140 | PlacesQueryPacket placesQueryPacket = | ||
11141 | (PlacesQueryPacket)Pack; | ||
11142 | |||
11143 | PlacesQuery handlerPlacesQuery = OnPlacesQuery; | ||
11144 | |||
11145 | if (handlerPlacesQuery != null) | ||
11146 | handlerPlacesQuery(placesQueryPacket.AgentData.QueryID, | ||
11147 | placesQueryPacket.TransactionData.TransactionID, | ||
11148 | Utils.BytesToString( | ||
11149 | placesQueryPacket.QueryData.QueryText), | ||
11150 | placesQueryPacket.QueryData.QueryFlags, | ||
11151 | (byte)placesQueryPacket.QueryData.Category, | ||
11152 | Utils.BytesToString( | ||
11153 | placesQueryPacket.QueryData.SimName), | ||
11154 | this); | ||
11155 | return true; | ||
11156 | } | ||
11157 | |||
11158 | #endregion Packet Handlers | ||
11159 | |||
11160 | public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question) | ||
11161 | { | ||
11162 | ScriptQuestionPacket scriptQuestion = (ScriptQuestionPacket)PacketPool.Instance.GetPacket(PacketType.ScriptQuestion); | ||
11163 | scriptQuestion.Data = new ScriptQuestionPacket.DataBlock(); | ||
11164 | // TODO: don't create new blocks if recycling an old packet | ||
11165 | scriptQuestion.Data.TaskID = taskID; | ||
11166 | scriptQuestion.Data.ItemID = itemID; | ||
11167 | scriptQuestion.Data.Questions = question; | ||
11168 | scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName); | ||
11169 | scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName); | ||
11170 | |||
11171 | OutPacket(scriptQuestion, ThrottleOutPacketType.Task); | ||
11172 | } | ||
11173 | |||
11174 | private void InitDefaultAnimations() | ||
11175 | { | ||
11176 | using (XmlTextReader reader = new XmlTextReader("data/avataranimations.xml")) | ||
11177 | { | ||
11178 | XmlDocument doc = new XmlDocument(); | ||
11179 | doc.Load(reader); | ||
11180 | if (doc.DocumentElement != null) | ||
11181 | foreach (XmlNode nod in doc.DocumentElement.ChildNodes) | ||
11182 | { | ||
11183 | if (nod.Attributes["name"] != null) | ||
11184 | { | ||
11185 | string name = nod.Attributes["name"].Value.ToLower(); | ||
11186 | string id = nod.InnerText; | ||
11187 | m_defaultAnimations.Add(name, (UUID)id); | ||
11188 | } | ||
11189 | } | ||
11190 | } | ||
11191 | } | ||
11192 | |||
11193 | public UUID GetDefaultAnimation(string name) | ||
11194 | { | ||
11195 | if (m_defaultAnimations.ContainsKey(name)) | ||
11196 | return m_defaultAnimations[name]; | ||
11197 | return UUID.Zero; | ||
11198 | } | ||
11199 | |||
11200 | /// <summary> | ||
11201 | /// Handler called when we receive a logout packet. | ||
11202 | /// </summary> | ||
11203 | /// <param name="client"></param> | ||
11204 | /// <param name="packet"></param> | ||
11205 | /// <returns></returns> | ||
11206 | protected virtual bool HandleLogout(IClientAPI client, Packet packet) | ||
11207 | { | ||
11208 | if (packet.Type == PacketType.LogoutRequest) | ||
11209 | { | ||
11210 | if (((LogoutRequestPacket)packet).AgentData.SessionID != SessionId) return false; | ||
11211 | } | ||
11212 | |||
11213 | return Logout(client); | ||
11214 | } | ||
11215 | |||
11216 | /// <summary> | ||
11217 | /// | ||
11218 | /// </summary> | ||
11219 | /// <param name="client"></param> | ||
11220 | /// <returns></returns> | ||
11221 | protected virtual bool Logout(IClientAPI client) | ||
11222 | { | ||
11223 | m_log.InfoFormat("[CLIENT]: Got a logout request for {0} in {1}", Name, Scene.RegionInfo.RegionName); | ||
11224 | |||
11225 | Action<IClientAPI> handlerLogout = OnLogout; | ||
11226 | |||
11227 | if (handlerLogout != null) | ||
11228 | { | ||
11229 | handlerLogout(client); | ||
11230 | } | ||
11231 | |||
11232 | return true; | ||
11233 | } | ||
11234 | |||
11235 | /// <summary> | ||
11236 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
11237 | /// its appearance texture cached. | ||
11238 | /// | ||
11239 | /// At the moment, we always reply that there is no cached texture. | ||
11240 | /// </summary> | ||
11241 | /// <param name="simclient"></param> | ||
11242 | /// <param name="packet"></param> | ||
11243 | /// <returns></returns> | ||
11244 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | ||
11245 | { | ||
11246 | //m_log.Debug("texture cached: " + packet.ToString()); | ||
11247 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | ||
11248 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | ||
11249 | |||
11250 | if (cachedtex.AgentData.SessionID != SessionId) return false; | ||
11251 | |||
11252 | // TODO: don't create new blocks if recycling an old packet | ||
11253 | cachedresp.AgentData.AgentID = AgentId; | ||
11254 | cachedresp.AgentData.SessionID = m_sessionId; | ||
11255 | cachedresp.AgentData.SerialNum = m_cachedTextureSerial; | ||
11256 | m_cachedTextureSerial++; | ||
11257 | cachedresp.WearableData = | ||
11258 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; | ||
11259 | |||
11260 | for (int i = 0; i < cachedtex.WearableData.Length; i++) | ||
11261 | { | ||
11262 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
11263 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11264 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11265 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11266 | } | ||
11267 | |||
11268 | cachedresp.Header.Zerocoded = true; | ||
11269 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | ||
11270 | |||
11271 | return true; | ||
11272 | } | ||
11273 | |||
11274 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | ||
11275 | { | ||
11276 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | ||
11277 | if (multipleupdate.AgentData.SessionID != SessionId) return false; | ||
11278 | // m_log.Debug("new multi update packet " + multipleupdate.ToString()); | ||
11279 | Scene tScene = (Scene)m_scene; | ||
11280 | |||
11281 | for (int i = 0; i < multipleupdate.ObjectData.Length; i++) | ||
11282 | { | ||
11283 | MultipleObjectUpdatePacket.ObjectDataBlock block = multipleupdate.ObjectData[i]; | ||
11284 | |||
11285 | // Can't act on Null Data | ||
11286 | if (block.Data != null) | ||
11287 | { | ||
11288 | uint localId = block.ObjectLocalID; | ||
11289 | SceneObjectPart part = tScene.GetSceneObjectPart(localId); | ||
11290 | |||
11291 | if (part == null) | ||
11292 | { | ||
11293 | // It's a ghost! tell the client to delete it from view. | ||
11294 | simClient.SendKillObject(Scene.RegionInfo.RegionHandle, | ||
11295 | new List<uint>() { localId }); | ||
11296 | } | ||
11297 | else | ||
11298 | { | ||
11299 | // UUID partId = part.UUID; | ||
11300 | UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; | ||
11301 | |||
11302 | switch (block.Type) | ||
11303 | { | ||
11304 | case 1: | ||
11305 | Vector3 pos1 = new Vector3(block.Data, 0); | ||
11306 | |||
11307 | UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | ||
11308 | if (handlerUpdatePrimSinglePosition != null) | ||
11309 | { | ||
11310 | // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | ||
11311 | handlerUpdatePrimSinglePosition(localId, pos1, this); | ||
11312 | } | ||
11313 | break; | ||
11314 | case 2: | ||
11315 | Quaternion rot1 = new Quaternion(block.Data, 0, true); | ||
11316 | |||
11317 | UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; | ||
11318 | if (handlerUpdatePrimSingleRotation != null) | ||
11319 | { | ||
11320 | // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W); | ||
11321 | handlerUpdatePrimSingleRotation(localId, rot1, this); | ||
11322 | } | ||
11323 | break; | ||
11324 | case 3: | ||
11325 | Vector3 rotPos = new Vector3(block.Data, 0); | ||
11326 | Quaternion rot2 = new Quaternion(block.Data, 12, true); | ||
11327 | |||
11328 | UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; | ||
11329 | if (handlerUpdatePrimSingleRotationPosition != null) | ||
11330 | { | ||
11331 | // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z); | ||
11332 | // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W); | ||
11333 | handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); | ||
11334 | } | ||
11335 | break; | ||
11336 | case 4: | ||
11337 | case 20: | ||
11338 | Vector3 scale4 = new Vector3(block.Data, 0); | ||
11339 | |||
11340 | UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; | ||
11341 | if (handlerUpdatePrimScale != null) | ||
11342 | { | ||
11343 | // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z); | ||
11344 | handlerUpdatePrimScale(localId, scale4, this); | ||
11345 | } | ||
11346 | break; | ||
11347 | case 5: | ||
11348 | |||
11349 | Vector3 scale1 = new Vector3(block.Data, 12); | ||
11350 | Vector3 pos11 = new Vector3(block.Data, 0); | ||
11351 | |||
11352 | handlerUpdatePrimScale = OnUpdatePrimScale; | ||
11353 | if (handlerUpdatePrimScale != null) | ||
11354 | { | ||
11355 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
11356 | handlerUpdatePrimScale(localId, scale1, this); | ||
11357 | |||
11358 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | ||
11359 | if (handlerUpdatePrimSinglePosition != null) | ||
11360 | { | ||
11361 | handlerUpdatePrimSinglePosition(localId, pos11, this); | ||
11362 | } | ||
11363 | } | ||
11364 | break; | ||
11365 | case 9: | ||
11366 | Vector3 pos2 = new Vector3(block.Data, 0); | ||
11367 | |||
11368 | UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; | ||
11369 | |||
11370 | if (handlerUpdateVector != null) | ||
11371 | { | ||
11372 | |||
11373 | handlerUpdateVector(localId, pos2, this); | ||
11374 | } | ||
11375 | break; | ||
11376 | case 10: | ||
11377 | Quaternion rot3 = new Quaternion(block.Data, 0, true); | ||
11378 | |||
11379 | UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; | ||
11380 | if (handlerUpdatePrimRotation != null) | ||
11381 | { | ||
11382 | // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W); | ||
11383 | handlerUpdatePrimRotation(localId, rot3, this); | ||
11384 | } | ||
11385 | break; | ||
11386 | case 11: | ||
11387 | Vector3 pos3 = new Vector3(block.Data, 0); | ||
11388 | Quaternion rot4 = new Quaternion(block.Data, 12, true); | ||
11389 | |||
11390 | handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; | ||
11391 | if (handlerUpdatePrimGroupRotation != null) | ||
11392 | { | ||
11393 | // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | ||
11394 | // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W); | ||
11395 | handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); | ||
11396 | } | ||
11397 | break; | ||
11398 | case 12: | ||
11399 | case 28: | ||
11400 | Vector3 scale7 = new Vector3(block.Data, 0); | ||
11401 | |||
11402 | UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; | ||
11403 | if (handlerUpdatePrimGroupScale != null) | ||
11404 | { | ||
11405 | // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z); | ||
11406 | handlerUpdatePrimGroupScale(localId, scale7, this); | ||
11407 | } | ||
11408 | break; | ||
11409 | case 13: | ||
11410 | Vector3 scale2 = new Vector3(block.Data, 12); | ||
11411 | Vector3 pos4 = new Vector3(block.Data, 0); | ||
11412 | |||
11413 | handlerUpdatePrimScale = OnUpdatePrimScale; | ||
11414 | if (handlerUpdatePrimScale != null) | ||
11415 | { | ||
11416 | //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
11417 | handlerUpdatePrimScale(localId, scale2, this); | ||
11418 | |||
11419 | // Change the position based on scale (for bug number 246) | ||
11420 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | ||
11421 | // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | ||
11422 | if (handlerUpdatePrimSinglePosition != null) | ||
11423 | { | ||
11424 | handlerUpdatePrimSinglePosition(localId, pos4, this); | ||
11425 | } | ||
11426 | } | ||
11427 | break; | ||
11428 | case 29: | ||
11429 | Vector3 scale5 = new Vector3(block.Data, 12); | ||
11430 | Vector3 pos5 = new Vector3(block.Data, 0); | ||
11431 | |||
11432 | handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; | ||
11433 | if (handlerUpdatePrimGroupScale != null) | ||
11434 | { | ||
11435 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
11436 | handlerUpdatePrimGroupScale(localId, scale5, this); | ||
11437 | handlerUpdateVector = OnUpdatePrimGroupPosition; | ||
11438 | |||
11439 | if (handlerUpdateVector != null) | ||
11440 | { | ||
11441 | handlerUpdateVector(localId, pos5, this); | ||
11442 | } | ||
11443 | } | ||
11444 | break; | ||
11445 | case 21: | ||
11446 | Vector3 scale6 = new Vector3(block.Data, 12); | ||
11447 | Vector3 pos6 = new Vector3(block.Data, 0); | ||
11448 | |||
11449 | handlerUpdatePrimScale = OnUpdatePrimScale; | ||
11450 | if (handlerUpdatePrimScale != null) | ||
11451 | { | ||
11452 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
11453 | handlerUpdatePrimScale(localId, scale6, this); | ||
11454 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | ||
11455 | if (handlerUpdatePrimSinglePosition != null) | ||
11456 | { | ||
11457 | handlerUpdatePrimSinglePosition(localId, pos6, this); | ||
11458 | } | ||
11459 | } | ||
11460 | break; | ||
11461 | default: | ||
11462 | m_log.Debug("[CLIENT] MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); | ||
11463 | break; | ||
11464 | } | ||
11465 | } | ||
11466 | } | ||
11467 | } | ||
11468 | return true; | ||
11469 | } | ||
11470 | |||
11471 | public void RequestMapLayer() | ||
11472 | { | ||
11473 | //should be getting the map layer from the grid server | ||
11474 | //send a layer covering the 800,800 - 1200,1200 area (should be covering the requested area) | ||
11475 | MapLayerReplyPacket mapReply = (MapLayerReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapLayerReply); | ||
11476 | // TODO: don't create new blocks if recycling an old packet | ||
11477 | mapReply.AgentData.AgentID = AgentId; | ||
11478 | mapReply.AgentData.Flags = 0; | ||
11479 | mapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1]; | ||
11480 | mapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock(); | ||
11481 | mapReply.LayerData[0].Bottom = 0; | ||
11482 | mapReply.LayerData[0].Left = 0; | ||
11483 | mapReply.LayerData[0].Top = 30000; | ||
11484 | mapReply.LayerData[0].Right = 30000; | ||
11485 | mapReply.LayerData[0].ImageID = new UUID("00000000-0000-1111-9999-000000000006"); | ||
11486 | mapReply.Header.Zerocoded = true; | ||
11487 | OutPacket(mapReply, ThrottleOutPacketType.Land); | ||
11488 | } | ||
11489 | |||
11490 | public void RequestMapBlocksX(int minX, int minY, int maxX, int maxY) | ||
11491 | { | ||
11492 | /* | ||
11493 | IList simMapProfiles = m_gridServer.RequestMapBlocks(minX, minY, maxX, maxY); | ||
11494 | MapBlockReplyPacket mbReply = new MapBlockReplyPacket(); | ||
11495 | mbReply.AgentData.AgentId = AgentId; | ||
11496 | int len; | ||
11497 | if (simMapProfiles == null) | ||
11498 | len = 0; | ||
11499 | else | ||
11500 | len = simMapProfiles.Count; | ||
11501 | |||
11502 | mbReply.Data = new MapBlockReplyPacket.DataBlock[len]; | ||
11503 | int iii; | ||
11504 | for (iii = 0; iii < len; iii++) | ||
11505 | { | ||
11506 | Hashtable mp = (Hashtable)simMapProfiles[iii]; | ||
11507 | mbReply.Data[iii] = new MapBlockReplyPacket.DataBlock(); | ||
11508 | mbReply.Data[iii].Name = Util.UTF8.GetBytes((string)mp["name"]); | ||
11509 | mbReply.Data[iii].Access = System.Convert.ToByte(mp["access"]); | ||
11510 | mbReply.Data[iii].Agents = System.Convert.ToByte(mp["agents"]); | ||
11511 | mbReply.Data[iii].MapImageID = new UUID((string)mp["map-image-id"]); | ||
11512 | mbReply.Data[iii].RegionFlags = System.Convert.ToUInt32(mp["region-flags"]); | ||
11513 | mbReply.Data[iii].WaterHeight = System.Convert.ToByte(mp["water-height"]); | ||
11514 | mbReply.Data[iii].X = System.Convert.ToUInt16(mp["x"]); | ||
11515 | mbReply.Data[iii].Y = System.Convert.ToUInt16(mp["y"]); | ||
11516 | } | ||
11517 | this.OutPacket(mbReply, ThrottleOutPacketType.Land); | ||
11518 | */ | ||
11519 | } | ||
11520 | |||
11521 | /// <summary> | ||
11522 | /// Sets the throttles from values supplied by the client | ||
11523 | /// </summary> | ||
11524 | /// <param name="throttles"></param> | ||
11525 | public void SetChildAgentThrottle(byte[] throttles) | ||
11526 | { | ||
11527 | m_udpClient.SetThrottles(throttles); | ||
11528 | } | ||
11529 | |||
11530 | /// <summary> | ||
11531 | /// Get the current throttles for this client as a packed byte array | ||
11532 | /// </summary> | ||
11533 | /// <param name="multiplier">Unused</param> | ||
11534 | /// <returns></returns> | ||
11535 | public byte[] GetThrottlesPacked(float multiplier) | ||
11536 | { | ||
11537 | return m_udpClient.GetThrottlesPacked(multiplier); | ||
11538 | } | ||
11539 | |||
11540 | /// <summary> | ||
11541 | /// Cruft? | ||
11542 | /// </summary> | ||
11543 | public virtual void InPacket(object NewPack) | ||
11544 | { | ||
11545 | throw new NotImplementedException(); | ||
11546 | } | ||
11547 | |||
11548 | /// <summary> | ||
11549 | /// This is the starting point for sending a simulator packet out to the client | ||
11550 | /// </summary> | ||
11551 | /// <param name="packet">Packet to send</param> | ||
11552 | /// <param name="throttlePacketType">Throttling category for the packet</param> | ||
11553 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType) | ||
11554 | { | ||
11555 | #region BinaryStats | ||
11556 | LLUDPServer.LogPacketHeader(false, m_circuitCode, 0, packet.Type, (ushort)packet.Length); | ||
11557 | #endregion BinaryStats | ||
11558 | |||
11559 | OutPacket(packet, throttlePacketType, true); | ||
11560 | } | ||
11561 | |||
11562 | /// <summary> | ||
11563 | /// This is the starting point for sending a simulator packet out to the client | ||
11564 | /// </summary> | ||
11565 | /// <param name="packet">Packet to send</param> | ||
11566 | /// <param name="throttlePacketType">Throttling category for the packet</param> | ||
11567 | /// <param name="doAutomaticSplitting">True to automatically split oversized | ||
11568 | /// packets (the default), or false to disable splitting if the calling code | ||
11569 | /// handles splitting manually</param> | ||
11570 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) | ||
11571 | { | ||
11572 | OutPacket(packet, throttlePacketType, doAutomaticSplitting, null); | ||
11573 | } | ||
11574 | |||
11575 | /// <summary> | ||
11576 | /// This is the starting point for sending a simulator packet out to the client | ||
11577 | /// </summary> | ||
11578 | /// <param name="packet">Packet to send</param> | ||
11579 | /// <param name="throttlePacketType">Throttling category for the packet</param> | ||
11580 | /// <param name="doAutomaticSplitting">True to automatically split oversized | ||
11581 | /// packets (the default), or false to disable splitting if the calling code | ||
11582 | /// handles splitting manually</param> | ||
11583 | /// <param name="method">The method to be called in the event this packet is reliable | ||
11584 | /// and unacknowledged. The server will provide normal resend capability if you do not | ||
11585 | /// provide your own method.</param> | ||
11586 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) | ||
11587 | { | ||
11588 | if (m_debugPacketLevel > 0) | ||
11589 | { | ||
11590 | bool logPacket = true; | ||
11591 | |||
11592 | if (m_debugPacketLevel <= 255 | ||
11593 | && (packet.Type == PacketType.SimStats || packet.Type == PacketType.SimulatorViewerTimeMessage)) | ||
11594 | logPacket = false; | ||
11595 | |||
11596 | if (m_debugPacketLevel <= 200 | ||
11597 | && (packet.Type == PacketType.ImagePacket | ||
11598 | || packet.Type == PacketType.ImageData | ||
11599 | || packet.Type == PacketType.LayerData | ||
11600 | || packet.Type == PacketType.CoarseLocationUpdate)) | ||
11601 | logPacket = false; | ||
11602 | |||
11603 | if (m_debugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect)) | ||
11604 | logPacket = false; | ||
11605 | |||
11606 | if (m_debugPacketLevel <= 50 && packet.Type == PacketType.ImprovedTerseObjectUpdate) | ||
11607 | logPacket = false; | ||
11608 | |||
11609 | if (logPacket) | ||
11610 | m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); | ||
11611 | } | ||
11612 | |||
11613 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); | ||
11614 | } | ||
11615 | |||
11616 | public bool AddMoney(int debit) | ||
11617 | { | ||
11618 | if (m_moneyBalance + debit >= 0) | ||
11619 | { | ||
11620 | m_moneyBalance += debit; | ||
11621 | SendMoneyBalance(UUID.Zero, true, Util.StringToBytes256("Poof Poof!"), m_moneyBalance); | ||
11622 | return true; | ||
11623 | } | ||
11624 | return false; | ||
11625 | } | ||
11626 | |||
11627 | /// <summary> | ||
11628 | /// Breaks down the genericMessagePacket into specific events | ||
11629 | /// </summary> | ||
11630 | /// <param name="gmMethod"></param> | ||
11631 | /// <param name="gmInvoice"></param> | ||
11632 | /// <param name="gmParams"></param> | ||
11633 | public void DecipherGenericMessage(string gmMethod, UUID gmInvoice, GenericMessagePacket.ParamListBlock[] gmParams) | ||
11634 | { | ||
11635 | switch (gmMethod) | ||
11636 | { | ||
11637 | case "autopilot": | ||
11638 | float locx; | ||
11639 | float locy; | ||
11640 | float locz; | ||
11641 | |||
11642 | try | ||
11643 | { | ||
11644 | uint regionX; | ||
11645 | uint regionY; | ||
11646 | Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY); | ||
11647 | locx = Convert.ToSingle(Utils.BytesToString(gmParams[0].Parameter)) - regionX; | ||
11648 | locy = Convert.ToSingle(Utils.BytesToString(gmParams[1].Parameter)) - regionY; | ||
11649 | locz = Convert.ToSingle(Utils.BytesToString(gmParams[2].Parameter)); | ||
11650 | } | ||
11651 | catch (InvalidCastException) | ||
11652 | { | ||
11653 | m_log.Error("[CLIENT]: Invalid autopilot request"); | ||
11654 | return; | ||
11655 | } | ||
11656 | |||
11657 | UpdateVector handlerAutoPilotGo = OnAutoPilotGo; | ||
11658 | if (handlerAutoPilotGo != null) | ||
11659 | { | ||
11660 | handlerAutoPilotGo(0, new Vector3(locx, locy, locz), this); | ||
11661 | } | ||
11662 | m_log.InfoFormat("[CLIENT]: Client Requests autopilot to position <{0},{1},{2}>", locx, locy, locz); | ||
11663 | |||
11664 | |||
11665 | break; | ||
11666 | default: | ||
11667 | m_log.Debug("[CLIENT]: Unknown Generic Message, Method: " + gmMethod + ". Invoice: " + gmInvoice + ". Dumping Params:"); | ||
11668 | for (int hi = 0; hi < gmParams.Length; hi++) | ||
11669 | { | ||
11670 | Console.WriteLine(gmParams[hi].ToString()); | ||
11671 | } | ||
11672 | //gmpack.MethodData. | ||
11673 | break; | ||
11674 | |||
11675 | } | ||
11676 | } | ||
11677 | |||
11678 | /// <summary> | ||
11679 | /// Entryway from the client to the simulator. All UDP packets from the client will end up here | ||
11680 | /// </summary> | ||
11681 | /// <param name="Pack">OpenMetaverse.packet</param> | ||
11682 | public void ProcessInPacket(Packet packet) | ||
11683 | { | ||
11684 | if (m_debugPacketLevel >= 255) | ||
11685 | m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type); | ||
11686 | |||
11687 | if (!ProcessPacketMethod(packet)) | ||
11688 | m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); | ||
11689 | |||
11690 | PacketPool.Instance.ReturnPacket(packet); | ||
11691 | } | ||
11692 | |||
11693 | private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) | ||
11694 | { | ||
11695 | PrimitiveBaseShape shape = new PrimitiveBaseShape(); | ||
11696 | |||
11697 | shape.PCode = addPacket.ObjectData.PCode; | ||
11698 | shape.State = addPacket.ObjectData.State; | ||
11699 | shape.PathBegin = addPacket.ObjectData.PathBegin; | ||
11700 | shape.PathEnd = addPacket.ObjectData.PathEnd; | ||
11701 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; | ||
11702 | shape.PathScaleY = addPacket.ObjectData.PathScaleY; | ||
11703 | shape.PathShearX = addPacket.ObjectData.PathShearX; | ||
11704 | shape.PathShearY = addPacket.ObjectData.PathShearY; | ||
11705 | shape.PathSkew = addPacket.ObjectData.PathSkew; | ||
11706 | shape.ProfileBegin = addPacket.ObjectData.ProfileBegin; | ||
11707 | shape.ProfileEnd = addPacket.ObjectData.ProfileEnd; | ||
11708 | shape.Scale = addPacket.ObjectData.Scale; | ||
11709 | shape.PathCurve = addPacket.ObjectData.PathCurve; | ||
11710 | shape.ProfileCurve = addPacket.ObjectData.ProfileCurve; | ||
11711 | shape.ProfileHollow = addPacket.ObjectData.ProfileHollow; | ||
11712 | shape.PathRadiusOffset = addPacket.ObjectData.PathRadiusOffset; | ||
11713 | shape.PathRevolutions = addPacket.ObjectData.PathRevolutions; | ||
11714 | shape.PathTaperX = addPacket.ObjectData.PathTaperX; | ||
11715 | shape.PathTaperY = addPacket.ObjectData.PathTaperY; | ||
11716 | shape.PathTwist = addPacket.ObjectData.PathTwist; | ||
11717 | shape.PathTwistBegin = addPacket.ObjectData.PathTwistBegin; | ||
11718 | Primitive.TextureEntry ntex = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f")); | ||
11719 | shape.TextureEntry = ntex.GetBytes(); | ||
11720 | //shape.Textures = ntex; | ||
11721 | return shape; | ||
11722 | } | ||
11723 | |||
11724 | public ClientInfo GetClientInfo() | ||
11725 | { | ||
11726 | ClientInfo info = m_udpClient.GetClientInfo(); | ||
11727 | |||
11728 | info.userEP = m_userEndPoint; | ||
11729 | info.proxyEP = null; | ||
11730 | info.agentcircuit = RequestClientInfo(); | ||
11731 | |||
11732 | return info; | ||
11733 | } | ||
11734 | |||
11735 | public void SetClientInfo(ClientInfo info) | ||
11736 | { | ||
11737 | m_udpClient.SetClientInfo(info); | ||
11738 | } | ||
11739 | |||
11740 | public EndPoint GetClientEP() | ||
11741 | { | ||
11742 | return m_userEndPoint; | ||
11743 | } | ||
11744 | |||
11745 | #region Media Parcel Members | ||
11746 | |||
11747 | public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time) | ||
11748 | { | ||
11749 | ParcelMediaCommandMessagePacket commandMessagePacket = new ParcelMediaCommandMessagePacket(); | ||
11750 | commandMessagePacket.CommandBlock.Flags = flags; | ||
11751 | commandMessagePacket.CommandBlock.Command = (uint)command; | ||
11752 | commandMessagePacket.CommandBlock.Time = time; | ||
11753 | |||
11754 | OutPacket(commandMessagePacket, ThrottleOutPacketType.Task); | ||
11755 | } | ||
11756 | |||
11757 | public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID, | ||
11758 | byte autoScale, string mediaType, string mediaDesc, int mediaWidth, int mediaHeight, | ||
11759 | byte mediaLoop) | ||
11760 | { | ||
11761 | ParcelMediaUpdatePacket updatePacket = new ParcelMediaUpdatePacket(); | ||
11762 | updatePacket.DataBlock.MediaURL = Util.StringToBytes256(mediaUrl); | ||
11763 | updatePacket.DataBlock.MediaID = mediaTextureID; | ||
11764 | updatePacket.DataBlock.MediaAutoScale = autoScale; | ||
11765 | |||
11766 | updatePacket.DataBlockExtended.MediaType = Util.StringToBytes256(mediaType); | ||
11767 | updatePacket.DataBlockExtended.MediaDesc = Util.StringToBytes256(mediaDesc); | ||
11768 | updatePacket.DataBlockExtended.MediaWidth = mediaWidth; | ||
11769 | updatePacket.DataBlockExtended.MediaHeight = mediaHeight; | ||
11770 | updatePacket.DataBlockExtended.MediaLoop = mediaLoop; | ||
11771 | |||
11772 | OutPacket(updatePacket, ThrottleOutPacketType.Task); | ||
11773 | } | ||
11774 | |||
11775 | #endregion | ||
11776 | |||
11777 | #region Camera | ||
11778 | |||
11779 | public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters) | ||
11780 | { | ||
11781 | SetFollowCamPropertiesPacket packet = (SetFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.SetFollowCamProperties); | ||
11782 | packet.ObjectData.ObjectID = objectID; | ||
11783 | SetFollowCamPropertiesPacket.CameraPropertyBlock[] camPropBlock = new SetFollowCamPropertiesPacket.CameraPropertyBlock[parameters.Count]; | ||
11784 | uint idx = 0; | ||
11785 | foreach (KeyValuePair<int, float> pair in parameters) | ||
11786 | { | ||
11787 | SetFollowCamPropertiesPacket.CameraPropertyBlock block = new SetFollowCamPropertiesPacket.CameraPropertyBlock(); | ||
11788 | block.Type = pair.Key; | ||
11789 | block.Value = pair.Value; | ||
11790 | |||
11791 | camPropBlock[idx++] = block; | ||
11792 | } | ||
11793 | packet.CameraProperty = camPropBlock; | ||
11794 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
11795 | } | ||
11796 | |||
11797 | public void SendClearFollowCamProperties(UUID objectID) | ||
11798 | { | ||
11799 | ClearFollowCamPropertiesPacket packet = (ClearFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ClearFollowCamProperties); | ||
11800 | packet.ObjectData.ObjectID = objectID; | ||
11801 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
11802 | } | ||
11803 | |||
11804 | #endregion | ||
11805 | |||
11806 | public void SetClientOption(string option, string value) | ||
11807 | { | ||
11808 | switch (option) | ||
11809 | { | ||
11810 | default: | ||
11811 | break; | ||
11812 | } | ||
11813 | } | ||
11814 | |||
11815 | public string GetClientOption(string option) | ||
11816 | { | ||
11817 | switch (option) | ||
11818 | { | ||
11819 | default: | ||
11820 | break; | ||
11821 | } | ||
11822 | return string.Empty; | ||
11823 | } | ||
11824 | |||
11825 | public void KillEndDone() | ||
11826 | { | ||
11827 | } | ||
11828 | |||
11829 | #region IClientCore | ||
11830 | |||
11831 | private readonly Dictionary<Type, object> m_clientInterfaces = new Dictionary<Type, object>(); | ||
11832 | |||
11833 | /// <summary> | ||
11834 | /// Register an interface on this client, should only be called in the constructor. | ||
11835 | /// </summary> | ||
11836 | /// <typeparam name="T"></typeparam> | ||
11837 | /// <param name="iface"></param> | ||
11838 | protected void RegisterInterface<T>(T iface) | ||
11839 | { | ||
11840 | lock (m_clientInterfaces) | ||
11841 | { | ||
11842 | if (!m_clientInterfaces.ContainsKey(typeof(T))) | ||
11843 | { | ||
11844 | m_clientInterfaces.Add(typeof(T), iface); | ||
11845 | } | ||
11846 | } | ||
11847 | } | ||
11848 | |||
11849 | public bool TryGet<T>(out T iface) | ||
11850 | { | ||
11851 | if (m_clientInterfaces.ContainsKey(typeof(T))) | ||
11852 | { | ||
11853 | iface = (T)m_clientInterfaces[typeof(T)]; | ||
11854 | return true; | ||
11855 | } | ||
11856 | iface = default(T); | ||
11857 | return false; | ||
11858 | } | ||
11859 | |||
11860 | public T Get<T>() | ||
11861 | { | ||
11862 | return (T)m_clientInterfaces[typeof(T)]; | ||
11863 | } | ||
11864 | |||
11865 | public void Disconnect(string reason) | ||
11866 | { | ||
11867 | Kick(reason); | ||
11868 | Thread.Sleep(1000); | ||
11869 | Close(); | ||
11870 | } | ||
11871 | |||
11872 | public void Disconnect() | ||
11873 | { | ||
11874 | Close(); | ||
11875 | } | ||
11876 | |||
11877 | #endregion | ||
11878 | |||
11879 | public void RefreshGroupMembership() | ||
11880 | { | ||
11881 | if (m_GroupsModule != null) | ||
11882 | { | ||
11883 | GroupMembershipData[] GroupMembership = | ||
11884 | m_GroupsModule.GetMembershipData(AgentId); | ||
11885 | |||
11886 | m_groupPowers.Clear(); | ||
11887 | |||
11888 | if (GroupMembership != null) | ||
11889 | { | ||
11890 | for (int i = 0; i < GroupMembership.Length; i++) | ||
11891 | { | ||
11892 | m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers; | ||
11893 | } | ||
11894 | } | ||
11895 | } | ||
11896 | } | ||
11897 | |||
11898 | public string Report() | ||
11899 | { | ||
11900 | return m_udpClient.GetStats(); | ||
11901 | } | ||
11902 | |||
11903 | public string XReport(string uptime, string version) | ||
11904 | { | ||
11905 | return String.Empty; | ||
11906 | } | ||
11907 | |||
11908 | /// <summary> | ||
11909 | /// Make an asset request to the asset service in response to a client request. | ||
11910 | /// </summary> | ||
11911 | /// <param name="transferRequest"></param> | ||
11912 | /// <param name="taskID"></param> | ||
11913 | protected void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID) | ||
11914 | { | ||
11915 | UUID requestID = UUID.Zero; | ||
11916 | if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) | ||
11917 | { | ||
11918 | requestID = new UUID(transferRequest.TransferInfo.Params, 0); | ||
11919 | } | ||
11920 | else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | ||
11921 | { | ||
11922 | requestID = new UUID(transferRequest.TransferInfo.Params, 80); | ||
11923 | } | ||
11924 | |||
11925 | // m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); | ||
11926 | |||
11927 | |||
11928 | //Note, the bool returned from the below function is useless since it is always false. | ||
11929 | m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); | ||
11930 | |||
11931 | } | ||
11932 | |||
11933 | /// <summary> | ||
11934 | /// When we get a reply back from the asset service in response to a client request, send back the data. | ||
11935 | /// </summary> | ||
11936 | /// <param name="id"></param> | ||
11937 | /// <param name="sender"></param> | ||
11938 | /// <param name="asset"></param> | ||
11939 | protected void AssetReceived(string id, Object sender, AssetBase asset) | ||
11940 | { | ||
11941 | if (asset == null) | ||
11942 | return; | ||
11943 | |||
11944 | TransferRequestPacket transferRequest = (TransferRequestPacket)sender; | ||
11945 | |||
11946 | UUID requestID = UUID.Zero; | ||
11947 | byte source = (byte)SourceType.Asset; | ||
11948 | |||
11949 | if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) | ||
11950 | { | ||
11951 | requestID = new UUID(transferRequest.TransferInfo.Params, 0); | ||
11952 | } | ||
11953 | else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | ||
11954 | { | ||
11955 | requestID = new UUID(transferRequest.TransferInfo.Params, 80); | ||
11956 | source = (byte)SourceType.SimInventoryItem; | ||
11957 | //m_log.Debug("asset request " + requestID); | ||
11958 | } | ||
11959 | |||
11960 | // Scripts cannot be retrieved by direct request | ||
11961 | if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset && asset.Type == 10) | ||
11962 | return; | ||
11963 | |||
11964 | // The asset is known to exist and is in our cache, so add it to the AssetRequests list | ||
11965 | AssetRequestToClient req = new AssetRequestToClient(); | ||
11966 | req.AssetInf = asset; | ||
11967 | req.AssetRequestSource = source; | ||
11968 | req.IsTextureRequest = false; | ||
11969 | req.NumPackets = CalculateNumPackets(asset.Data); | ||
11970 | req.Params = transferRequest.TransferInfo.Params; | ||
11971 | req.RequestAssetID = requestID; | ||
11972 | req.TransferRequestID = transferRequest.TransferInfo.TransferID; | ||
11973 | |||
11974 | SendAsset(req); | ||
11975 | } | ||
11976 | |||
11977 | /// <summary> | ||
11978 | /// Calculate the number of packets required to send the asset to the client. | ||
11979 | /// </summary> | ||
11980 | /// <param name="data"></param> | ||
11981 | /// <returns></returns> | ||
11982 | private static int CalculateNumPackets(byte[] data) | ||
11983 | { | ||
11984 | const uint m_maxPacketSize = 600; | ||
11985 | int numPackets = 1; | ||
11986 | |||
11987 | if (data == null) | ||
11988 | return 0; | ||
11989 | |||
11990 | if (data.LongLength > m_maxPacketSize) | ||
11991 | { | ||
11992 | // over max number of bytes so split up file | ||
11993 | long restData = data.LongLength - m_maxPacketSize; | ||
11994 | int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize); | ||
11995 | numPackets += restPackets; | ||
11996 | } | ||
11997 | |||
11998 | return numPackets; | ||
11999 | } | ||
12000 | |||
12001 | #region IClientIPEndpoint Members | ||
12002 | |||
12003 | public IPAddress EndPoint | ||
12004 | { | ||
12005 | get | ||
12006 | { | ||
12007 | if (m_userEndPoint is IPEndPoint) | ||
12008 | { | ||
12009 | IPEndPoint ep = (IPEndPoint)m_userEndPoint; | ||
12010 | |||
12011 | return ep.Address; | ||
12012 | } | ||
12013 | return null; | ||
12014 | } | ||
12015 | } | ||
12016 | |||
12017 | #endregion | ||
12018 | |||
12019 | public void SendRebakeAvatarTextures(UUID textureID) | ||
12020 | { | ||
12021 | RebakeAvatarTexturesPacket pack = | ||
12022 | (RebakeAvatarTexturesPacket)PacketPool.Instance.GetPacket(PacketType.RebakeAvatarTextures); | ||
12023 | |||
12024 | pack.TextureData = new RebakeAvatarTexturesPacket.TextureDataBlock(); | ||
12025 | pack.TextureData.TextureID = textureID; | ||
12026 | OutPacket(pack, ThrottleOutPacketType.Task); | ||
12027 | } | ||
12028 | |||
12029 | public struct PacketProcessor | ||
12030 | { | ||
12031 | public PacketMethod method; | ||
12032 | public bool Async; | ||
12033 | } | ||
12034 | |||
12035 | public class AsyncPacketProcess | ||
12036 | { | ||
12037 | public bool result = false; | ||
12038 | public readonly LLClientView ClientView = null; | ||
12039 | public readonly Packet Pack = null; | ||
12040 | public readonly PacketMethod Method = null; | ||
12041 | public AsyncPacketProcess(LLClientView pClientview, PacketMethod pMethod, Packet pPack) | ||
12042 | { | ||
12043 | ClientView = pClientview; | ||
12044 | Method = pMethod; | ||
12045 | Pack = pPack; | ||
12046 | } | ||
12047 | } | ||
12048 | |||
12049 | public static OSD BuildEvent(string eventName, OSD eventBody) | ||
12050 | { | ||
12051 | OSDMap osdEvent = new OSDMap(2); | ||
12052 | osdEvent.Add("message", new OSDString(eventName)); | ||
12053 | osdEvent.Add("body", eventBody); | ||
12054 | |||
12055 | return osdEvent; | ||
12056 | } | ||
12057 | |||
12058 | public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages) | ||
12059 | { | ||
12060 | AvatarInterestsReplyPacket packet = (AvatarInterestsReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarInterestsReply); | ||
12061 | |||
12062 | packet.AgentData = new AvatarInterestsReplyPacket.AgentDataBlock(); | ||
12063 | packet.AgentData.AgentID = AgentId; | ||
12064 | packet.AgentData.AvatarID = avatarID; | ||
12065 | |||
12066 | packet.PropertiesData = new AvatarInterestsReplyPacket.PropertiesDataBlock(); | ||
12067 | packet.PropertiesData.WantToMask = wantMask; | ||
12068 | packet.PropertiesData.WantToText = Utils.StringToBytes(wantText); | ||
12069 | packet.PropertiesData.SkillsMask = skillsMask; | ||
12070 | packet.PropertiesData.SkillsText = Utils.StringToBytes(skillsText); | ||
12071 | packet.PropertiesData.LanguagesText = Utils.StringToBytes(languages); | ||
12072 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
12073 | } | ||
12074 | |||
12075 | public void SendChangeUserRights(UUID agentID, UUID friendID, int rights) | ||
12076 | { | ||
12077 | ChangeUserRightsPacket packet = (ChangeUserRightsPacket)PacketPool.Instance.GetPacket(PacketType.ChangeUserRights); | ||
12078 | |||
12079 | packet.AgentData = new ChangeUserRightsPacket.AgentDataBlock(); | ||
12080 | packet.AgentData.AgentID = agentID; | ||
12081 | |||
12082 | packet.Rights = new ChangeUserRightsPacket.RightsBlock[1]; | ||
12083 | packet.Rights[0] = new ChangeUserRightsPacket.RightsBlock(); | ||
12084 | packet.Rights[0].AgentRelated = friendID; | ||
12085 | packet.Rights[0].RelatedRights = rights; | ||
12086 | |||
12087 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
12088 | } | ||
12089 | |||
12090 | public void SendTextBoxRequest(string message, int chatChannel, string objectname, string ownerFirstName, string ownerLastName, UUID objectId) | ||
12091 | { | ||
12092 | ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); | ||
12093 | dialog.Data.ObjectID = objectId; | ||
12094 | dialog.Data.ChatChannel = chatChannel; | ||
12095 | dialog.Data.ImageID = UUID.Zero; | ||
12096 | dialog.Data.ObjectName = Util.StringToBytes256(objectname); | ||
12097 | // this is the username of the *owner* | ||
12098 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); | ||
12099 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); | ||
12100 | dialog.Data.Message = Util.StringToBytes256(message); | ||
12101 | |||
12102 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1]; | ||
12103 | buttons[0] = new ScriptDialogPacket.ButtonsBlock(); | ||
12104 | buttons[0].ButtonLabel = Util.StringToBytes256("!!llTextBox!!"); | ||
12105 | dialog.Buttons = buttons; | ||
12106 | OutPacket(dialog, ThrottleOutPacketType.Task); | ||
12107 | } | ||
12108 | |||
12109 | public void StopFlying(ISceneEntity p) | ||
12110 | { | ||
12111 | if (p is ScenePresence) | ||
12112 | { | ||
12113 | ScenePresence presence = p as ScenePresence; | ||
12114 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities | ||
12115 | // There's no explicit message to send the client to tell it to stop flying.. it relies on the | ||
12116 | // velocity, collision plane and avatar height | ||
12117 | |||
12118 | // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air | ||
12119 | // when the avatar stands up | ||
12120 | |||
12121 | Vector3 pos = presence.AbsolutePosition; | ||
12122 | |||
12123 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12124 | pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f)); | ||
12125 | else | ||
12126 | pos += new Vector3(0f, 0f, (1.56f/6f)); | ||
12127 | |||
12128 | presence.AbsolutePosition = pos; | ||
12129 | |||
12130 | // attach a suitable collision plane regardless of the actual situation to force the LLClient to land. | ||
12131 | // Collision plane below the avatar's position a 6th of the avatar's height is suitable. | ||
12132 | // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a | ||
12133 | // certain amount.. because the LLClient wouldn't land in that situation anyway. | ||
12134 | |||
12135 | // why are we still testing for this really old height value default??? | ||
12136 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12137 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f); | ||
12138 | else | ||
12139 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f)); | ||
12140 | |||
12141 | |||
12142 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = | ||
12143 | CreateImprovedTerseBlock(p, false); | ||
12144 | |||
12145 | const float TIME_DILATION = 1.0f; | ||
12146 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | ||
12147 | |||
12148 | |||
12149 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); | ||
12150 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
12151 | packet.RegionData.TimeDilation = timeDilation; | ||
12152 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; | ||
12153 | |||
12154 | packet.ObjectData[0] = block; | ||
12155 | |||
12156 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
12157 | } | ||
12158 | |||
12159 | //ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, | ||
12160 | // AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient))); | ||
12161 | } | ||
12162 | |||
12163 | public void SendPlacesReply(UUID queryID, UUID transactionID, | ||
12164 | PlacesReplyData[] data) | ||
12165 | { | ||
12166 | PlacesReplyPacket reply = null; | ||
12167 | PlacesReplyPacket.QueryDataBlock[] dataBlocks = | ||
12168 | new PlacesReplyPacket.QueryDataBlock[0]; | ||
12169 | |||
12170 | for (int i = 0 ; i < data.Length ; i++) | ||
12171 | { | ||
12172 | PlacesReplyPacket.QueryDataBlock block = | ||
12173 | new PlacesReplyPacket.QueryDataBlock(); | ||
12174 | |||
12175 | block.OwnerID = data[i].OwnerID; | ||
12176 | block.Name = Util.StringToBytes256(data[i].Name); | ||
12177 | block.Desc = Util.StringToBytes1024(data[i].Desc); | ||
12178 | block.ActualArea = data[i].ActualArea; | ||
12179 | block.BillableArea = data[i].BillableArea; | ||
12180 | block.Flags = data[i].Flags; | ||
12181 | block.GlobalX = data[i].GlobalX; | ||
12182 | block.GlobalY = data[i].GlobalY; | ||
12183 | block.GlobalZ = data[i].GlobalZ; | ||
12184 | block.SimName = Util.StringToBytes256(data[i].SimName); | ||
12185 | block.SnapshotID = data[i].SnapshotID; | ||
12186 | block.Dwell = data[i].Dwell; | ||
12187 | block.Price = data[i].Price; | ||
12188 | |||
12189 | if (reply != null && reply.Length + block.Length > 1400) | ||
12190 | { | ||
12191 | OutPacket(reply, ThrottleOutPacketType.Task); | ||
12192 | |||
12193 | reply = null; | ||
12194 | dataBlocks = new PlacesReplyPacket.QueryDataBlock[0]; | ||
12195 | } | ||
12196 | |||
12197 | if (reply == null) | ||
12198 | { | ||
12199 | reply = (PlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.PlacesReply); | ||
12200 | reply.AgentData = new PlacesReplyPacket.AgentDataBlock(); | ||
12201 | reply.AgentData.AgentID = AgentId; | ||
12202 | reply.AgentData.QueryID = queryID; | ||
12203 | |||
12204 | reply.TransactionData = new PlacesReplyPacket.TransactionDataBlock(); | ||
12205 | reply.TransactionData.TransactionID = transactionID; | ||
12206 | |||
12207 | reply.QueryData = dataBlocks; | ||
12208 | } | ||
12209 | |||
12210 | Array.Resize(ref dataBlocks, dataBlocks.Length + 1); | ||
12211 | dataBlocks[dataBlocks.Length - 1] = block; | ||
12212 | reply.QueryData = dataBlocks; | ||
12213 | } | ||
12214 | if (reply != null) | ||
12215 | OutPacket(reply, ThrottleOutPacketType.Task); | ||
12216 | } | ||
12217 | } | ||
12218 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs new file mode 100644 index 0000000..9e0db12 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs | |||
@@ -0,0 +1,257 @@ | |||
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.Threading; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Reflection; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.Imaging; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Services.Interfaces; | ||
38 | using log4net; | ||
39 | |||
40 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
41 | { | ||
42 | public class LLImageManager | ||
43 | { | ||
44 | private sealed class J2KImageComparer : IComparer<J2KImage> | ||
45 | { | ||
46 | public int Compare(J2KImage x, J2KImage y) | ||
47 | { | ||
48 | return x.Priority.CompareTo(y.Priority); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | private bool m_shuttingdown; | ||
54 | private AssetBase m_missingImage; | ||
55 | private LLClientView m_client; //Client we're assigned to | ||
56 | private IAssetService m_assetCache; //Asset Cache | ||
57 | private IJ2KDecoder m_j2kDecodeModule; //Our J2K module | ||
58 | private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); | ||
59 | private object m_syncRoot = new object(); | ||
60 | |||
61 | public LLClientView Client { get { return m_client; } } | ||
62 | public AssetBase MissingImage { get { return m_missingImage; } } | ||
63 | |||
64 | public LLImageManager(LLClientView client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule) | ||
65 | { | ||
66 | m_client = client; | ||
67 | m_assetCache = pAssetCache; | ||
68 | |||
69 | if (pAssetCache != null) | ||
70 | m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f"); | ||
71 | |||
72 | if (m_missingImage == null) | ||
73 | m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); | ||
74 | |||
75 | m_j2kDecodeModule = pJ2kDecodeModule; | ||
76 | } | ||
77 | |||
78 | /// <summary> | ||
79 | /// Handles an incoming texture request or update to an existing texture request | ||
80 | /// </summary> | ||
81 | /// <param name="newRequest"></param> | ||
82 | public void EnqueueReq(TextureRequestArgs newRequest) | ||
83 | { | ||
84 | //Make sure we're not shutting down.. | ||
85 | if (!m_shuttingdown) | ||
86 | { | ||
87 | J2KImage imgrequest; | ||
88 | |||
89 | // Do a linear search for this texture download | ||
90 | lock (m_syncRoot) | ||
91 | m_priorityQueue.Find(delegate(J2KImage img) { return img.TextureID == newRequest.RequestedAssetID; }, out imgrequest); | ||
92 | |||
93 | if (imgrequest != null) | ||
94 | { | ||
95 | if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f) | ||
96 | { | ||
97 | //m_log.Debug("[TEX]: (CAN) ID=" + newRequest.RequestedAssetID); | ||
98 | |||
99 | try | ||
100 | { | ||
101 | lock (m_syncRoot) | ||
102 | m_priorityQueue.Delete(imgrequest.PriorityQueueHandle); | ||
103 | } | ||
104 | catch (Exception) { } | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | //m_log.DebugFormat("[TEX]: (UPD) ID={0}: D={1}, S={2}, P={3}", | ||
109 | // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority); | ||
110 | |||
111 | //Check the packet sequence to make sure this isn't older than | ||
112 | //one we've already received | ||
113 | if (newRequest.requestSequence > imgrequest.LastSequence) | ||
114 | { | ||
115 | //Update the sequence number of the last RequestImage packet | ||
116 | imgrequest.LastSequence = newRequest.requestSequence; | ||
117 | |||
118 | //Update the requested discard level | ||
119 | imgrequest.DiscardLevel = newRequest.DiscardLevel; | ||
120 | |||
121 | //Update the requested packet number | ||
122 | imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); | ||
123 | |||
124 | //Update the requested priority | ||
125 | imgrequest.Priority = newRequest.Priority; | ||
126 | UpdateImageInQueue(imgrequest); | ||
127 | |||
128 | //Run an update | ||
129 | imgrequest.RunUpdate(); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f) | ||
136 | { | ||
137 | //m_log.DebugFormat("[TEX]: (IGN) ID={0}: D={1}, S={2}, P={3}", | ||
138 | // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority); | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | //m_log.DebugFormat("[TEX]: (NEW) ID={0}: D={1}, S={2}, P={3}", | ||
143 | // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority); | ||
144 | |||
145 | imgrequest = new J2KImage(this); | ||
146 | imgrequest.J2KDecoder = m_j2kDecodeModule; | ||
147 | imgrequest.AssetService = m_assetCache; | ||
148 | imgrequest.AgentID = m_client.AgentId; | ||
149 | imgrequest.InventoryAccessModule = m_client.Scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
150 | imgrequest.DiscardLevel = newRequest.DiscardLevel; | ||
151 | imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); | ||
152 | imgrequest.Priority = newRequest.Priority; | ||
153 | imgrequest.TextureID = newRequest.RequestedAssetID; | ||
154 | imgrequest.Priority = newRequest.Priority; | ||
155 | |||
156 | //Add this download to the priority queue | ||
157 | AddImageToQueue(imgrequest); | ||
158 | |||
159 | //Run an update | ||
160 | imgrequest.RunUpdate(); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | public bool ProcessImageQueue(int packetsToSend) | ||
167 | { | ||
168 | int packetsSent = 0; | ||
169 | |||
170 | while (packetsSent < packetsToSend) | ||
171 | { | ||
172 | J2KImage image = GetHighestPriorityImage(); | ||
173 | |||
174 | // If null was returned, the texture priority queue is currently empty | ||
175 | if (image == null) | ||
176 | return false; | ||
177 | |||
178 | if (image.IsDecoded) | ||
179 | { | ||
180 | int sent; | ||
181 | bool imageDone = image.SendPackets(m_client, packetsToSend - packetsSent, out sent); | ||
182 | packetsSent += sent; | ||
183 | |||
184 | // If the send is complete, destroy any knowledge of this transfer | ||
185 | if (imageDone) | ||
186 | RemoveImageFromQueue(image); | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | // TODO: This is a limitation of how LLImageManager is currently | ||
191 | // written. Undecoded textures should not be going into the priority | ||
192 | // queue, because a high priority undecoded texture will clog up the | ||
193 | // pipeline for a client | ||
194 | return true; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return m_priorityQueue.Count > 0; | ||
199 | } | ||
200 | |||
201 | /// <summary> | ||
202 | /// Faux destructor | ||
203 | /// </summary> | ||
204 | public void Close() | ||
205 | { | ||
206 | m_shuttingdown = true; | ||
207 | } | ||
208 | |||
209 | #region Priority Queue Helpers | ||
210 | |||
211 | J2KImage GetHighestPriorityImage() | ||
212 | { | ||
213 | J2KImage image = null; | ||
214 | |||
215 | lock (m_syncRoot) | ||
216 | { | ||
217 | if (m_priorityQueue.Count > 0) | ||
218 | { | ||
219 | try { image = m_priorityQueue.FindMax(); } | ||
220 | catch (Exception) { } | ||
221 | } | ||
222 | } | ||
223 | return image; | ||
224 | } | ||
225 | |||
226 | void AddImageToQueue(J2KImage image) | ||
227 | { | ||
228 | image.PriorityQueueHandle = null; | ||
229 | |||
230 | lock (m_syncRoot) | ||
231 | try { m_priorityQueue.Add(ref image.PriorityQueueHandle, image); } | ||
232 | catch (Exception) { } | ||
233 | } | ||
234 | |||
235 | void RemoveImageFromQueue(J2KImage image) | ||
236 | { | ||
237 | lock (m_syncRoot) | ||
238 | try { m_priorityQueue.Delete(image.PriorityQueueHandle); } | ||
239 | catch (Exception) { } | ||
240 | } | ||
241 | |||
242 | void UpdateImageInQueue(J2KImage image) | ||
243 | { | ||
244 | lock (m_syncRoot) | ||
245 | { | ||
246 | try { m_priorityQueue.Replace(image.PriorityQueueHandle, image); } | ||
247 | catch (Exception) | ||
248 | { | ||
249 | image.PriorityQueueHandle = null; | ||
250 | m_priorityQueue.Add(ref image.PriorityQueueHandle, image); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | |||
255 | #endregion Priority Queue Helpers | ||
256 | } | ||
257 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs new file mode 100644 index 0000000..95a8e23 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -0,0 +1,707 @@ | |||
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.Generic; | ||
30 | using System.Net; | ||
31 | using System.Threading; | ||
32 | using log4net; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.Packets; | ||
36 | |||
37 | using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; | ||
38 | |||
39 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
40 | { | ||
41 | #region Delegates | ||
42 | |||
43 | /// <summary> | ||
44 | /// Fired when updated networking stats are produced for this client | ||
45 | /// </summary> | ||
46 | /// <param name="inPackets">Number of incoming packets received since this | ||
47 | /// event was last fired</param> | ||
48 | /// <param name="outPackets">Number of outgoing packets sent since this | ||
49 | /// event was last fired</param> | ||
50 | /// <param name="unAckedBytes">Current total number of bytes in packets we | ||
51 | /// are waiting on ACKs for</param> | ||
52 | public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); | ||
53 | /// <summary> | ||
54 | /// Fired when the queue for one or more packet categories is empty. This | ||
55 | /// event can be hooked to put more data on the empty queues | ||
56 | /// </summary> | ||
57 | /// <param name="category">Categories of the packet queues that are empty</param> | ||
58 | public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories); | ||
59 | |||
60 | #endregion Delegates | ||
61 | |||
62 | /// <summary> | ||
63 | /// Tracks state for a client UDP connection and provides client-specific methods | ||
64 | /// </summary> | ||
65 | public sealed class LLUDPClient | ||
66 | { | ||
67 | // TODO: Make this a config setting | ||
68 | /// <summary>Percentage of the task throttle category that is allocated to avatar and prim | ||
69 | /// state updates</summary> | ||
70 | const float STATE_TASK_PERCENTAGE = 0.8f; | ||
71 | |||
72 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
73 | |||
74 | /// <summary>The number of packet categories to throttle on. If a throttle category is added | ||
75 | /// or removed, this number must also change</summary> | ||
76 | const int THROTTLE_CATEGORY_COUNT = 8; | ||
77 | |||
78 | /// <summary>Fired when updated networking stats are produced for this client</summary> | ||
79 | public event PacketStats OnPacketStats; | ||
80 | /// <summary>Fired when the queue for a packet category is empty. This event can be | ||
81 | /// hooked to put more data on the empty queue</summary> | ||
82 | public event QueueEmpty OnQueueEmpty; | ||
83 | |||
84 | /// <summary>AgentID for this client</summary> | ||
85 | public readonly UUID AgentID; | ||
86 | /// <summary>The remote address of the connected client</summary> | ||
87 | public readonly IPEndPoint RemoteEndPoint; | ||
88 | /// <summary>Circuit code that this client is connected on</summary> | ||
89 | public readonly uint CircuitCode; | ||
90 | /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> | ||
91 | public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); | ||
92 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | ||
93 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | ||
94 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | ||
95 | public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); | ||
96 | |||
97 | /// <summary>Current packet sequence number</summary> | ||
98 | public int CurrentSequence; | ||
99 | /// <summary>Current ping sequence number</summary> | ||
100 | public byte CurrentPingSequence; | ||
101 | /// <summary>True when this connection is alive, otherwise false</summary> | ||
102 | public bool IsConnected = true; | ||
103 | /// <summary>True when this connection is paused, otherwise false</summary> | ||
104 | public bool IsPaused; | ||
105 | /// <summary>Environment.TickCount when the last packet was received for this client</summary> | ||
106 | public int TickLastPacketReceived; | ||
107 | |||
108 | /// <summary>Smoothed round-trip time. A smoothed average of the round-trip time for sending a | ||
109 | /// reliable packet to the client and receiving an ACK</summary> | ||
110 | public float SRTT; | ||
111 | /// <summary>Round-trip time variance. Measures the consistency of round-trip times</summary> | ||
112 | public float RTTVAR; | ||
113 | /// <summary>Retransmission timeout. Packets that have not been acknowledged in this number of | ||
114 | /// milliseconds or longer will be resent</summary> | ||
115 | /// <remarks>Calculated from <seealso cref="SRTT"/> and <seealso cref="RTTVAR"/> using the | ||
116 | /// guidelines in RFC 2988</remarks> | ||
117 | public int RTO; | ||
118 | /// <summary>Number of bytes received since the last acknowledgement was sent out. This is used | ||
119 | /// to loosely follow the TCP delayed ACK algorithm in RFC 1122 (4.2.3.2)</summary> | ||
120 | public int BytesSinceLastACK; | ||
121 | /// <summary>Number of packets received from this client</summary> | ||
122 | public int PacketsReceived; | ||
123 | /// <summary>Number of packets sent to this client</summary> | ||
124 | public int PacketsSent; | ||
125 | /// <summary>Number of packets resent to this client</summary> | ||
126 | public int PacketsResent; | ||
127 | /// <summary>Total byte count of unacked packets sent to this client</summary> | ||
128 | public int UnackedBytes; | ||
129 | |||
130 | /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary> | ||
131 | private int m_packetsReceivedReported; | ||
132 | /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> | ||
133 | private int m_packetsSentReported; | ||
134 | /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary> | ||
135 | private int m_nextOnQueueEmpty = 1; | ||
136 | |||
137 | /// <summary>Throttle bucket for this agent's connection</summary> | ||
138 | private readonly AdaptiveTokenBucket m_throttleClient; | ||
139 | public AdaptiveTokenBucket FlowThrottle | ||
140 | { | ||
141 | get { return m_throttleClient; } | ||
142 | } | ||
143 | |||
144 | /// <summary>Throttle bucket for this agent's connection</summary> | ||
145 | private readonly TokenBucket m_throttleCategory; | ||
146 | /// <summary>Throttle buckets for each packet category</summary> | ||
147 | private readonly TokenBucket[] m_throttleCategories; | ||
148 | /// <summary>Outgoing queues for throttled packets</summary> | ||
149 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | ||
150 | /// <summary>A container that can hold one packet for each outbox, used to store | ||
151 | /// dequeued packets that are being held for throttling</summary> | ||
152 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | ||
153 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | ||
154 | private readonly LLUDPServer m_udpServer; | ||
155 | |||
156 | /// <summary>Caches packed throttle information</summary> | ||
157 | private byte[] m_packedThrottles; | ||
158 | |||
159 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC | ||
160 | private int m_maxRTO = 60000; | ||
161 | public bool m_deliverPackets = true; | ||
162 | |||
163 | /// <summary> | ||
164 | /// Default constructor | ||
165 | /// </summary> | ||
166 | /// <param name="server">Reference to the UDP server this client is connected to</param> | ||
167 | /// <param name="rates">Default throttling rates and maximum throttle limits</param> | ||
168 | /// <param name="parentThrottle">Parent HTB (hierarchical token bucket) | ||
169 | /// that the child throttles will be governed by</param> | ||
170 | /// <param name="circuitCode">Circuit code for this connection</param> | ||
171 | /// <param name="agentID">AgentID for the connected agent</param> | ||
172 | /// <param name="remoteEndPoint">Remote endpoint for this connection</param> | ||
173 | public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO) | ||
174 | { | ||
175 | AgentID = agentID; | ||
176 | RemoteEndPoint = remoteEndPoint; | ||
177 | CircuitCode = circuitCode; | ||
178 | m_udpServer = server; | ||
179 | if (defaultRTO != 0) | ||
180 | m_defaultRTO = defaultRTO; | ||
181 | if (maxRTO != 0) | ||
182 | m_maxRTO = maxRTO; | ||
183 | |||
184 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | ||
185 | m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); | ||
186 | // Create a token bucket throttle for the total categary with the client bucket as a throttle | ||
187 | m_throttleCategory = new TokenBucket(m_throttleClient, 0); | ||
188 | // Create an array of token buckets for this clients different throttle categories | ||
189 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | ||
190 | |||
191 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
192 | { | ||
193 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | ||
194 | |||
195 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | ||
196 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | ||
197 | // Initialize the token buckets that control the throttling for each category | ||
198 | m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); | ||
199 | } | ||
200 | |||
201 | // Default the retransmission timeout to three seconds | ||
202 | RTO = m_defaultRTO; | ||
203 | |||
204 | // Initialize this to a sane value to prevent early disconnects | ||
205 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; | ||
206 | } | ||
207 | |||
208 | /// <summary> | ||
209 | /// Shuts down this client connection | ||
210 | /// </summary> | ||
211 | public void Shutdown() | ||
212 | { | ||
213 | IsConnected = false; | ||
214 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
215 | { | ||
216 | m_packetOutboxes[i].Clear(); | ||
217 | m_nextPackets[i] = null; | ||
218 | } | ||
219 | |||
220 | // pull the throttle out of the scene throttle | ||
221 | m_throttleClient.Parent.UnregisterRequest(m_throttleClient); | ||
222 | OnPacketStats = null; | ||
223 | OnQueueEmpty = null; | ||
224 | } | ||
225 | |||
226 | /// <summary> | ||
227 | /// Gets information about this client connection | ||
228 | /// </summary> | ||
229 | /// <returns>Information about the client connection</returns> | ||
230 | public ClientInfo GetClientInfo() | ||
231 | { | ||
232 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | ||
233 | // of pending and needed ACKs for every client every time some method wants information about | ||
234 | // this connection is a recipe for poor performance | ||
235 | ClientInfo info = new ClientInfo(); | ||
236 | info.pendingAcks = new Dictionary<uint, uint>(); | ||
237 | info.needAck = new Dictionary<uint, byte[]>(); | ||
238 | |||
239 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | ||
240 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | ||
241 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | ||
242 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | ||
243 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | ||
244 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | ||
245 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | ||
246 | info.totalThrottle = (int)m_throttleCategory.DripRate; | ||
247 | |||
248 | return info; | ||
249 | } | ||
250 | |||
251 | /// <summary> | ||
252 | /// Modifies the UDP throttles | ||
253 | /// </summary> | ||
254 | /// <param name="info">New throttling values</param> | ||
255 | public void SetClientInfo(ClientInfo info) | ||
256 | { | ||
257 | // TODO: Allowing throttles to be manually set from this function seems like a reasonable | ||
258 | // idea. On the other hand, letting external code manipulate our ACK accounting is not | ||
259 | // going to happen | ||
260 | throw new NotImplementedException(); | ||
261 | } | ||
262 | |||
263 | /// <summary> | ||
264 | /// Return statistics information about client packet queues. | ||
265 | /// </summary> | ||
266 | /// | ||
267 | /// FIXME: This should really be done in a more sensible manner rather than sending back a formatted string. | ||
268 | /// | ||
269 | /// <returns></returns> | ||
270 | public string GetStats() | ||
271 | { | ||
272 | return string.Format( | ||
273 | "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}", | ||
274 | PacketsReceived, | ||
275 | PacketsSent, | ||
276 | PacketsResent, | ||
277 | UnackedBytes, | ||
278 | m_packetOutboxes[(int)ThrottleOutPacketType.Resend].Count, | ||
279 | m_packetOutboxes[(int)ThrottleOutPacketType.Land].Count, | ||
280 | m_packetOutboxes[(int)ThrottleOutPacketType.Wind].Count, | ||
281 | m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count, | ||
282 | m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count, | ||
283 | m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count, | ||
284 | m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count, | ||
285 | m_packetOutboxes[(int)ThrottleOutPacketType.State].Count); | ||
286 | } | ||
287 | |||
288 | public void SendPacketStats() | ||
289 | { | ||
290 | PacketStats callback = OnPacketStats; | ||
291 | if (callback != null) | ||
292 | { | ||
293 | int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; | ||
294 | int newPacketsSent = PacketsSent - m_packetsSentReported; | ||
295 | |||
296 | callback(newPacketsReceived, newPacketsSent, UnackedBytes); | ||
297 | |||
298 | m_packetsReceivedReported += newPacketsReceived; | ||
299 | m_packetsSentReported += newPacketsSent; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | public void SetThrottles(byte[] throttleData) | ||
304 | { | ||
305 | byte[] adjData; | ||
306 | int pos = 0; | ||
307 | |||
308 | if (!BitConverter.IsLittleEndian) | ||
309 | { | ||
310 | byte[] newData = new byte[7 * 4]; | ||
311 | Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4); | ||
312 | |||
313 | for (int i = 0; i < 7; i++) | ||
314 | Array.Reverse(newData, i * 4, 4); | ||
315 | |||
316 | adjData = newData; | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | adjData = throttleData; | ||
321 | } | ||
322 | |||
323 | // 0.125f converts from bits to bytes | ||
324 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
325 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
326 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
327 | int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
328 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
329 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
330 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
331 | // State is a subcategory of task that we allocate a percentage to | ||
332 | int state = 0; | ||
333 | |||
334 | // Make sure none of the throttles are set below our packet MTU, | ||
335 | // otherwise a throttle could become permanently clogged | ||
336 | resend = Math.Max(resend, LLUDPServer.MTU); | ||
337 | land = Math.Max(land, LLUDPServer.MTU); | ||
338 | wind = Math.Max(wind, LLUDPServer.MTU); | ||
339 | cloud = Math.Max(cloud, LLUDPServer.MTU); | ||
340 | task = Math.Max(task, LLUDPServer.MTU); | ||
341 | texture = Math.Max(texture, LLUDPServer.MTU); | ||
342 | asset = Math.Max(asset, LLUDPServer.MTU); | ||
343 | |||
344 | //int total = resend + land + wind + cloud + task + texture + asset; | ||
345 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", | ||
346 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); | ||
347 | |||
348 | // Update the token buckets with new throttle values | ||
349 | TokenBucket bucket; | ||
350 | |||
351 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; | ||
352 | bucket.RequestedDripRate = resend; | ||
353 | |||
354 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | ||
355 | bucket.RequestedDripRate = land; | ||
356 | |||
357 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | ||
358 | bucket.RequestedDripRate = wind; | ||
359 | |||
360 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | ||
361 | bucket.RequestedDripRate = cloud; | ||
362 | |||
363 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | ||
364 | bucket.RequestedDripRate = asset; | ||
365 | |||
366 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | ||
367 | bucket.RequestedDripRate = task; | ||
368 | |||
369 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; | ||
370 | bucket.RequestedDripRate = state; | ||
371 | |||
372 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | ||
373 | bucket.RequestedDripRate = texture; | ||
374 | |||
375 | // Reset the packed throttles cached data | ||
376 | m_packedThrottles = null; | ||
377 | } | ||
378 | |||
379 | public byte[] GetThrottlesPacked(float multiplier) | ||
380 | { | ||
381 | byte[] data = m_packedThrottles; | ||
382 | |||
383 | if (data == null) | ||
384 | { | ||
385 | float rate; | ||
386 | |||
387 | data = new byte[7 * 4]; | ||
388 | int i = 0; | ||
389 | |||
390 | // multiply by 8 to convert bytes back to bits | ||
391 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; | ||
392 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
393 | |||
394 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; | ||
395 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
396 | |||
397 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; | ||
398 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
399 | |||
400 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; | ||
401 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
402 | |||
403 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; | ||
404 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
405 | |||
406 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; | ||
407 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
408 | |||
409 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; | ||
410 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | ||
411 | |||
412 | m_packedThrottles = data; | ||
413 | } | ||
414 | |||
415 | return data; | ||
416 | } | ||
417 | |||
418 | /// <summary> | ||
419 | /// Queue an outgoing packet if appropriate. | ||
420 | /// </summary> | ||
421 | /// <param name="packet"></param> | ||
422 | /// <param name="forceQueue">Always queue the packet if at all possible.</param> | ||
423 | /// <returns> | ||
424 | /// true if the packet has been queued, | ||
425 | /// false if the packet has not been queued and should be sent immediately. | ||
426 | /// </returns> | ||
427 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) | ||
428 | { | ||
429 | int category = (int)packet.Category; | ||
430 | |||
431 | if (category >= 0 && category < m_packetOutboxes.Length) | ||
432 | { | ||
433 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; | ||
434 | |||
435 | if (m_deliverPackets == false) | ||
436 | { | ||
437 | queue.Enqueue(packet); | ||
438 | return true; | ||
439 | } | ||
440 | |||
441 | TokenBucket bucket = m_throttleCategories[category]; | ||
442 | |||
443 | // Don't send this packet if there is already a packet waiting in the queue | ||
444 | // even if we have the tokens to send it, tokens should go to the already | ||
445 | // queued packets | ||
446 | if (queue.Count > 0) | ||
447 | { | ||
448 | queue.Enqueue(packet); | ||
449 | return true; | ||
450 | } | ||
451 | |||
452 | |||
453 | if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
454 | { | ||
455 | // Enough tokens were removed from the bucket, the packet will not be queued | ||
456 | return false; | ||
457 | } | ||
458 | else | ||
459 | { | ||
460 | // Force queue specified or not enough tokens in the bucket, queue this packet | ||
461 | queue.Enqueue(packet); | ||
462 | return true; | ||
463 | } | ||
464 | } | ||
465 | else | ||
466 | { | ||
467 | // We don't have a token bucket for this category, so it will not be queued | ||
468 | return false; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | /// <summary> | ||
473 | /// Loops through all of the packet queues for this client and tries to send | ||
474 | /// an outgoing packet from each, obeying the throttling bucket limits | ||
475 | /// </summary> | ||
476 | /// | ||
477 | /// <remarks> | ||
478 | /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower | ||
479 | /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have | ||
480 | /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the | ||
481 | /// wind queue). | ||
482 | /// | ||
483 | /// This function is only called from a synchronous loop in the | ||
484 | /// UDPServer so we don't need to bother making this thread safe | ||
485 | /// </remarks> | ||
486 | /// | ||
487 | /// <returns>True if any packets were sent, otherwise false</returns> | ||
488 | public bool DequeueOutgoing() | ||
489 | { | ||
490 | if (m_deliverPackets == false) return false; | ||
491 | |||
492 | OutgoingPacket packet; | ||
493 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; | ||
494 | TokenBucket bucket; | ||
495 | bool packetSent = false; | ||
496 | ThrottleOutPacketTypeFlags emptyCategories = 0; | ||
497 | |||
498 | //string queueDebugOutput = String.Empty; // Serious debug business | ||
499 | |||
500 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
501 | { | ||
502 | bucket = m_throttleCategories[i]; | ||
503 | //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business | ||
504 | |||
505 | if (m_nextPackets[i] != null) | ||
506 | { | ||
507 | // This bucket was empty the last time we tried to send a packet, | ||
508 | // leaving a dequeued packet still waiting to be sent out. Try to | ||
509 | // send it again | ||
510 | OutgoingPacket nextPacket = m_nextPackets[i]; | ||
511 | if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) | ||
512 | { | ||
513 | // Send the packet | ||
514 | m_udpServer.SendPacketFinal(nextPacket); | ||
515 | m_nextPackets[i] = null; | ||
516 | packetSent = true; | ||
517 | } | ||
518 | } | ||
519 | else | ||
520 | { | ||
521 | // No dequeued packet waiting to be sent, try to pull one off | ||
522 | // this queue | ||
523 | queue = m_packetOutboxes[i]; | ||
524 | if (queue.Dequeue(out packet)) | ||
525 | { | ||
526 | // A packet was pulled off the queue. See if we have | ||
527 | // enough tokens in the bucket to send it out | ||
528 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
529 | { | ||
530 | // Send the packet | ||
531 | m_udpServer.SendPacketFinal(packet); | ||
532 | packetSent = true; | ||
533 | } | ||
534 | else | ||
535 | { | ||
536 | // Save the dequeued packet for the next iteration | ||
537 | m_nextPackets[i] = packet; | ||
538 | } | ||
539 | |||
540 | // If the queue is empty after this dequeue, fire the queue | ||
541 | // empty callback now so it has a chance to fill before we | ||
542 | // get back here | ||
543 | if (queue.Count == 0) | ||
544 | emptyCategories |= CategoryToFlag(i); | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | // No packets in this queue. Fire the queue empty callback | ||
549 | // if it has not been called recently | ||
550 | emptyCategories |= CategoryToFlag(i); | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | |||
555 | if (emptyCategories != 0) | ||
556 | BeginFireQueueEmpty(emptyCategories); | ||
557 | |||
558 | //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business | ||
559 | return packetSent; | ||
560 | } | ||
561 | |||
562 | /// <summary> | ||
563 | /// Called when an ACK packet is received and a round-trip time for a | ||
564 | /// packet is calculated. This is used to calculate the smoothed | ||
565 | /// round-trip time, round trip time variance, and finally the | ||
566 | /// retransmission timeout | ||
567 | /// </summary> | ||
568 | /// <param name="r">Round-trip time of a single packet and its | ||
569 | /// acknowledgement</param> | ||
570 | public void UpdateRoundTrip(float r) | ||
571 | { | ||
572 | const float ALPHA = 0.125f; | ||
573 | const float BETA = 0.25f; | ||
574 | const float K = 4.0f; | ||
575 | |||
576 | if (RTTVAR == 0.0f) | ||
577 | { | ||
578 | // First RTT measurement | ||
579 | SRTT = r; | ||
580 | RTTVAR = r * 0.5f; | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | // Subsequence RTT measurement | ||
585 | RTTVAR = (1.0f - BETA) * RTTVAR + BETA * Math.Abs(SRTT - r); | ||
586 | SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; | ||
587 | } | ||
588 | |||
589 | int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); | ||
590 | |||
591 | // Clamp the retransmission timeout to manageable values | ||
592 | rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO); | ||
593 | |||
594 | RTO = rto; | ||
595 | |||
596 | //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + | ||
597 | // RTTVAR + " based on new RTT of " + r + "ms"); | ||
598 | } | ||
599 | |||
600 | /// <summary> | ||
601 | /// Exponential backoff of the retransmission timeout, per section 5.5 | ||
602 | /// of RFC 2988 | ||
603 | /// </summary> | ||
604 | public void BackoffRTO() | ||
605 | { | ||
606 | // Reset SRTT and RTTVAR, we assume they are bogus since things | ||
607 | // didn't work out and we're backing off the timeout | ||
608 | SRTT = 0.0f; | ||
609 | RTTVAR = 0.0f; | ||
610 | |||
611 | // Double the retransmission timeout | ||
612 | RTO = Math.Min(RTO * 2, m_maxRTO); | ||
613 | } | ||
614 | |||
615 | /// <summary> | ||
616 | /// Does an early check to see if this queue empty callback is already | ||
617 | /// running, then asynchronously firing the event | ||
618 | /// </summary> | ||
619 | /// <param name="throttleIndex">Throttle category to fire the callback | ||
620 | /// for</param> | ||
621 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) | ||
622 | { | ||
623 | if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | ||
624 | { | ||
625 | // Use a value of 0 to signal that FireQueueEmpty is running | ||
626 | m_nextOnQueueEmpty = 0; | ||
627 | // Asynchronously run the callback | ||
628 | Util.FireAndForget(FireQueueEmpty, categories); | ||
629 | } | ||
630 | } | ||
631 | |||
632 | /// <summary> | ||
633 | /// Fires the OnQueueEmpty callback and sets the minimum time that it | ||
634 | /// can be called again | ||
635 | /// </summary> | ||
636 | /// <param name="o">Throttle categories to fire the callback for, | ||
637 | /// stored as an object to match the WaitCallback delegate | ||
638 | /// signature</param> | ||
639 | private void FireQueueEmpty(object o) | ||
640 | { | ||
641 | const int MIN_CALLBACK_MS = 30; | ||
642 | |||
643 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | ||
644 | QueueEmpty callback = OnQueueEmpty; | ||
645 | |||
646 | int start = Environment.TickCount & Int32.MaxValue; | ||
647 | |||
648 | if (callback != null) | ||
649 | { | ||
650 | try { callback(categories); } | ||
651 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | ||
652 | } | ||
653 | |||
654 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
655 | if (m_nextOnQueueEmpty == 0) | ||
656 | m_nextOnQueueEmpty = 1; | ||
657 | } | ||
658 | |||
659 | /// <summary> | ||
660 | /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a | ||
661 | /// flag value | ||
662 | /// </summary> | ||
663 | /// <param name="i">Throttle category to convert</param> | ||
664 | /// <returns>Flag representation of the throttle category</returns> | ||
665 | private static ThrottleOutPacketTypeFlags CategoryToFlag(int i) | ||
666 | { | ||
667 | ThrottleOutPacketType category = (ThrottleOutPacketType)i; | ||
668 | |||
669 | /* | ||
670 | * Land = 1, | ||
671 | /// <summary>Wind data</summary> | ||
672 | Wind = 2, | ||
673 | /// <summary>Cloud data</summary> | ||
674 | Cloud = 3, | ||
675 | /// <summary>Any packets that do not fit into the other throttles</summary> | ||
676 | Task = 4, | ||
677 | /// <summary>Texture assets</summary> | ||
678 | Texture = 5, | ||
679 | /// <summary>Non-texture assets</summary> | ||
680 | Asset = 6, | ||
681 | /// <summary>Avatar and primitive data</summary> | ||
682 | /// <remarks>This is a sub-category of Task</remarks> | ||
683 | State = 7, | ||
684 | */ | ||
685 | |||
686 | switch (category) | ||
687 | { | ||
688 | case ThrottleOutPacketType.Land: | ||
689 | return ThrottleOutPacketTypeFlags.Land; | ||
690 | case ThrottleOutPacketType.Wind: | ||
691 | return ThrottleOutPacketTypeFlags.Wind; | ||
692 | case ThrottleOutPacketType.Cloud: | ||
693 | return ThrottleOutPacketTypeFlags.Cloud; | ||
694 | case ThrottleOutPacketType.Task: | ||
695 | return ThrottleOutPacketTypeFlags.Task; | ||
696 | case ThrottleOutPacketType.Texture: | ||
697 | return ThrottleOutPacketTypeFlags.Texture; | ||
698 | case ThrottleOutPacketType.Asset: | ||
699 | return ThrottleOutPacketTypeFlags.Asset; | ||
700 | case ThrottleOutPacketType.State: | ||
701 | return ThrottleOutPacketTypeFlags.State; | ||
702 | default: | ||
703 | return 0; | ||
704 | } | ||
705 | } | ||
706 | } | ||
707 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs new file mode 100644 index 0000000..ab6674d --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -0,0 +1,1276 @@ | |||
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.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Net.Sockets; | ||
34 | using System.Reflection; | ||
35 | using System.Threading; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using OpenMetaverse.Packets; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Statistics; | ||
41 | using OpenSim.Region.Framework.Scenes; | ||
42 | using OpenMetaverse; | ||
43 | |||
44 | using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; | ||
45 | |||
46 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
47 | { | ||
48 | /// <summary> | ||
49 | /// A shim around LLUDPServer that implements the IClientNetworkServer interface | ||
50 | /// </summary> | ||
51 | public sealed class LLUDPServerShim : IClientNetworkServer | ||
52 | { | ||
53 | LLUDPServer m_udpServer; | ||
54 | |||
55 | public LLUDPServerShim() | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | ||
60 | { | ||
61 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | ||
62 | } | ||
63 | |||
64 | public void NetworkStop() | ||
65 | { | ||
66 | m_udpServer.Stop(); | ||
67 | } | ||
68 | |||
69 | public void AddScene(IScene scene) | ||
70 | { | ||
71 | m_udpServer.AddScene(scene); | ||
72 | } | ||
73 | |||
74 | public bool HandlesRegion(Location x) | ||
75 | { | ||
76 | return m_udpServer.HandlesRegion(x); | ||
77 | } | ||
78 | |||
79 | public void Start() | ||
80 | { | ||
81 | m_udpServer.Start(); | ||
82 | } | ||
83 | |||
84 | public void Stop() | ||
85 | { | ||
86 | m_udpServer.Stop(); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /// <summary> | ||
91 | /// The LLUDP server for a region. This handles incoming and outgoing | ||
92 | /// packets for all UDP connections to the region | ||
93 | /// </summary> | ||
94 | public class LLUDPServer : OpenSimUDPBase | ||
95 | { | ||
96 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | ||
97 | public const int MTU = 1400; | ||
98 | |||
99 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
100 | |||
101 | /// <summary>The measured resolution of Environment.TickCount</summary> | ||
102 | public readonly float TickCountResolution; | ||
103 | /// <summary>Number of prim updates to put on the queue each time the | ||
104 | /// OnQueueEmpty event is triggered for updates</summary> | ||
105 | public readonly int PrimUpdatesPerCallback; | ||
106 | /// <summary>Number of texture packets to put on the queue each time the | ||
107 | /// OnQueueEmpty event is triggered for textures</summary> | ||
108 | public readonly int TextureSendLimit; | ||
109 | |||
110 | /// <summary>Handlers for incoming packets</summary> | ||
111 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | ||
112 | /// <summary>Incoming packets that are awaiting handling</summary> | ||
113 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | ||
114 | /// <summary></summary> | ||
115 | //private UDPClientCollection m_clients = new UDPClientCollection(); | ||
116 | /// <summary>Bandwidth throttle for this UDP server</summary> | ||
117 | protected TokenBucket m_throttle; | ||
118 | |||
119 | /// <summary>Bandwidth throttle rates for this UDP server</summary> | ||
120 | public ThrottleRates ThrottleRates { get; private set; } | ||
121 | |||
122 | /// <summary>Manages authentication for agent circuits</summary> | ||
123 | private AgentCircuitManager m_circuitManager; | ||
124 | /// <summary>Reference to the scene this UDP server is attached to</summary> | ||
125 | protected Scene m_scene; | ||
126 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> | ||
127 | private Location m_location; | ||
128 | /// <summary>The size of the receive buffer for the UDP socket. This value | ||
129 | /// is passed up to the operating system and used in the system networking | ||
130 | /// stack. Use zero to leave this value as the default</summary> | ||
131 | private int m_recvBufferSize; | ||
132 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
133 | private bool m_asyncPacketHandling; | ||
134 | /// <summary>Tracks whether or not a packet was sent each round so we know | ||
135 | /// whether or not to sleep</summary> | ||
136 | private bool m_packetSent; | ||
137 | |||
138 | /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> | ||
139 | private int m_elapsedMSSinceLastStatReport = 0; | ||
140 | /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> | ||
141 | private int m_tickLastOutgoingPacketHandler; | ||
142 | /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> | ||
143 | private int m_elapsedMSOutgoingPacketHandler; | ||
144 | /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> | ||
145 | private int m_elapsed100MSOutgoingPacketHandler; | ||
146 | /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> | ||
147 | private int m_elapsed500MSOutgoingPacketHandler; | ||
148 | |||
149 | /// <summary>Flag to signal when clients should check for resends</summary> | ||
150 | private bool m_resendUnacked; | ||
151 | /// <summary>Flag to signal when clients should send ACKs</summary> | ||
152 | private bool m_sendAcks; | ||
153 | /// <summary>Flag to signal when clients should send pings</summary> | ||
154 | private bool m_sendPing; | ||
155 | |||
156 | private int m_defaultRTO = 0; | ||
157 | private int m_maxRTO = 0; | ||
158 | |||
159 | private bool m_disableFacelights = false; | ||
160 | |||
161 | public Socket Server { get { return null; } } | ||
162 | |||
163 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | ||
164 | : base(listenIP, (int)port) | ||
165 | { | ||
166 | #region Environment.TickCount Measurement | ||
167 | |||
168 | // Measure the resolution of Environment.TickCount | ||
169 | TickCountResolution = 0f; | ||
170 | for (int i = 0; i < 5; i++) | ||
171 | { | ||
172 | int start = Environment.TickCount; | ||
173 | int now = start; | ||
174 | while (now == start) | ||
175 | now = Environment.TickCount; | ||
176 | TickCountResolution += (float)(now - start) * 0.2f; | ||
177 | } | ||
178 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | ||
179 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); | ||
180 | |||
181 | #endregion Environment.TickCount Measurement | ||
182 | |||
183 | m_circuitManager = circuitManager; | ||
184 | int sceneThrottleBps = 0; | ||
185 | |||
186 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; | ||
187 | if (config != null) | ||
188 | { | ||
189 | m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true); | ||
190 | m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); | ||
191 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); | ||
192 | |||
193 | PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100); | ||
194 | TextureSendLimit = config.GetInt("TextureSendLimit", 20); | ||
195 | |||
196 | m_defaultRTO = config.GetInt("DefaultRTO", 0); | ||
197 | m_maxRTO = config.GetInt("MaxRTO", 0); | ||
198 | m_disableFacelights = config.GetBoolean("DisableFacelights", false); | ||
199 | } | ||
200 | else | ||
201 | { | ||
202 | PrimUpdatesPerCallback = 100; | ||
203 | TextureSendLimit = 20; | ||
204 | } | ||
205 | |||
206 | #region BinaryStats | ||
207 | config = configSource.Configs["Statistics.Binary"]; | ||
208 | m_shouldCollectStats = false; | ||
209 | if (config != null) | ||
210 | { | ||
211 | if (config.Contains("enabled") && config.GetBoolean("enabled")) | ||
212 | { | ||
213 | if (config.Contains("collect_packet_headers")) | ||
214 | m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); | ||
215 | if (config.Contains("packet_headers_period_seconds")) | ||
216 | { | ||
217 | binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds")); | ||
218 | } | ||
219 | if (config.Contains("stats_dir")) | ||
220 | { | ||
221 | binStatsDir = config.GetString("stats_dir"); | ||
222 | } | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | m_shouldCollectStats = false; | ||
227 | } | ||
228 | } | ||
229 | #endregion BinaryStats | ||
230 | |||
231 | m_throttle = new TokenBucket(null, sceneThrottleBps); | ||
232 | ThrottleRates = new ThrottleRates(configSource); | ||
233 | } | ||
234 | |||
235 | public void Start() | ||
236 | { | ||
237 | if (m_scene == null) | ||
238 | throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); | ||
239 | |||
240 | m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode"); | ||
241 | |||
242 | base.Start(m_recvBufferSize, m_asyncPacketHandling); | ||
243 | |||
244 | // Start the packet processing threads | ||
245 | Watchdog.StartThread(IncomingPacketHandler, "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false); | ||
246 | Watchdog.StartThread(OutgoingPacketHandler, "Outgoing Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false); | ||
247 | m_elapsedMSSinceLastStatReport = Environment.TickCount; | ||
248 | } | ||
249 | |||
250 | public new void Stop() | ||
251 | { | ||
252 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); | ||
253 | base.Stop(); | ||
254 | } | ||
255 | |||
256 | public void AddScene(IScene scene) | ||
257 | { | ||
258 | if (m_scene != null) | ||
259 | { | ||
260 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | if (!(scene is Scene)) | ||
265 | { | ||
266 | m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType()); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | m_scene = (Scene)scene; | ||
271 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | ||
272 | } | ||
273 | |||
274 | public bool HandlesRegion(Location x) | ||
275 | { | ||
276 | return x == m_location; | ||
277 | } | ||
278 | |||
279 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | ||
280 | { | ||
281 | // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way | ||
282 | if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) | ||
283 | allowSplitting = false; | ||
284 | |||
285 | if (allowSplitting && packet.HasVariableBlocks) | ||
286 | { | ||
287 | byte[][] datas = packet.ToBytesMultiple(); | ||
288 | int packetCount = datas.Length; | ||
289 | |||
290 | if (packetCount < 1) | ||
291 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | ||
292 | |||
293 | for (int i = 0; i < packetCount; i++) | ||
294 | { | ||
295 | byte[] data = datas[i]; | ||
296 | m_scene.ForEachClient( | ||
297 | delegate(IClientAPI client) | ||
298 | { | ||
299 | if (client is LLClientView) | ||
300 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | ||
301 | } | ||
302 | ); | ||
303 | } | ||
304 | } | ||
305 | else | ||
306 | { | ||
307 | byte[] data = packet.ToBytes(); | ||
308 | m_scene.ForEachClient( | ||
309 | delegate(IClientAPI client) | ||
310 | { | ||
311 | if (client is LLClientView) | ||
312 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | ||
313 | } | ||
314 | ); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | /// <summary> | ||
319 | /// Start the process of sending a packet to the client. | ||
320 | /// </summary> | ||
321 | /// <param name="udpClient"></param> | ||
322 | /// <param name="packet"></param> | ||
323 | /// <param name="category"></param> | ||
324 | /// <param name="allowSplitting"></param> | ||
325 | public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method) | ||
326 | { | ||
327 | // CoarseLocationUpdate packets cannot be split in an automated way | ||
328 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | ||
329 | allowSplitting = false; | ||
330 | |||
331 | if (allowSplitting && packet.HasVariableBlocks) | ||
332 | { | ||
333 | byte[][] datas = packet.ToBytesMultiple(); | ||
334 | int packetCount = datas.Length; | ||
335 | |||
336 | if (packetCount < 1) | ||
337 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | ||
338 | |||
339 | for (int i = 0; i < packetCount; i++) | ||
340 | { | ||
341 | byte[] data = datas[i]; | ||
342 | SendPacketData(udpClient, data, packet.Type, category, method); | ||
343 | } | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | byte[] data = packet.ToBytes(); | ||
348 | SendPacketData(udpClient, data, packet.Type, category, method); | ||
349 | } | ||
350 | } | ||
351 | |||
352 | /// <summary> | ||
353 | /// Start the process of sending a packet to the client. | ||
354 | /// </summary> | ||
355 | /// <param name="udpClient"></param> | ||
356 | /// <param name="data"></param> | ||
357 | /// <param name="type"></param> | ||
358 | /// <param name="category"></param> | ||
359 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) | ||
360 | { | ||
361 | int dataLength = data.Length; | ||
362 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | ||
363 | bool doCopy = true; | ||
364 | |||
365 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | ||
366 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting | ||
367 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here | ||
368 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | ||
369 | int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; | ||
370 | |||
371 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); | ||
372 | |||
373 | // Zerocode if needed | ||
374 | if (doZerocode) | ||
375 | { | ||
376 | try | ||
377 | { | ||
378 | dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); | ||
379 | doCopy = false; | ||
380 | } | ||
381 | catch (IndexOutOfRangeException) | ||
382 | { | ||
383 | // The packet grew larger than the bufferSize while zerocoding. | ||
384 | // Remove the MSG_ZEROCODED flag and send the unencoded data | ||
385 | // instead | ||
386 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + | ||
387 | " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); | ||
388 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | // If the packet data wasn't already copied during zerocoding, copy it now | ||
393 | if (doCopy) | ||
394 | { | ||
395 | if (dataLength <= buffer.Data.Length) | ||
396 | { | ||
397 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | bufferSize = dataLength; | ||
402 | buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); | ||
403 | |||
404 | // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | ||
405 | // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | ||
406 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | buffer.DataLength = dataLength; | ||
411 | |||
412 | #region Queue or Send | ||
413 | |||
414 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); | ||
415 | // If we were not provided a method for handling unacked, use the UDPServer default method | ||
416 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | ||
417 | |||
418 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will | ||
419 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object | ||
420 | // packet so that it isn't sent before a queued update packet. | ||
421 | bool requestQueue = type == PacketType.KillObject; | ||
422 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) | ||
423 | SendPacketFinal(outgoingPacket); | ||
424 | |||
425 | #endregion Queue or Send | ||
426 | } | ||
427 | |||
428 | public void SendAcks(LLUDPClient udpClient) | ||
429 | { | ||
430 | uint ack; | ||
431 | |||
432 | if (udpClient.PendingAcks.Dequeue(out ack)) | ||
433 | { | ||
434 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); | ||
435 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); | ||
436 | block.ID = ack; | ||
437 | blocks.Add(block); | ||
438 | |||
439 | while (udpClient.PendingAcks.Dequeue(out ack)) | ||
440 | { | ||
441 | block = new PacketAckPacket.PacketsBlock(); | ||
442 | block.ID = ack; | ||
443 | blocks.Add(block); | ||
444 | } | ||
445 | |||
446 | PacketAckPacket packet = new PacketAckPacket(); | ||
447 | packet.Header.Reliable = false; | ||
448 | packet.Packets = blocks.ToArray(); | ||
449 | |||
450 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | public void SendPing(LLUDPClient udpClient) | ||
455 | { | ||
456 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); | ||
457 | pc.Header.Reliable = false; | ||
458 | |||
459 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; | ||
460 | // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit | ||
461 | pc.PingID.OldestUnacked = 0; | ||
462 | |||
463 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); | ||
464 | } | ||
465 | |||
466 | public void CompletePing(LLUDPClient udpClient, byte pingID) | ||
467 | { | ||
468 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); | ||
469 | completePing.PingID.PingID = pingID; | ||
470 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null); | ||
471 | } | ||
472 | |||
473 | public void HandleUnacked(LLUDPClient udpClient) | ||
474 | { | ||
475 | if (!udpClient.IsConnected) | ||
476 | return; | ||
477 | |||
478 | // Disconnect an agent if no packets are received for some time | ||
479 | //FIXME: Make 60 an .ini setting | ||
480 | if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60) | ||
481 | { | ||
482 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); | ||
483 | |||
484 | RemoveClient(udpClient); | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO | ||
489 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); | ||
490 | |||
491 | if (expiredPackets != null) | ||
492 | { | ||
493 | //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); | ||
494 | // Exponential backoff of the retransmission timeout | ||
495 | udpClient.BackoffRTO(); | ||
496 | for (int i = 0; i < expiredPackets.Count; ++i) | ||
497 | expiredPackets[i].UnackedMethod(expiredPackets[i]); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | public void ResendUnacked(OutgoingPacket outgoingPacket) | ||
502 | { | ||
503 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", | ||
504 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); | ||
505 | |||
506 | // Set the resent flag | ||
507 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); | ||
508 | outgoingPacket.Category = ThrottleOutPacketType.Resend; | ||
509 | |||
510 | // Bump up the resend count on this packet | ||
511 | Interlocked.Increment(ref outgoingPacket.ResendCount); | ||
512 | |||
513 | // Requeue or resend the packet | ||
514 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) | ||
515 | SendPacketFinal(outgoingPacket); | ||
516 | } | ||
517 | |||
518 | public void Flush(LLUDPClient udpClient) | ||
519 | { | ||
520 | // FIXME: Implement? | ||
521 | } | ||
522 | |||
523 | /// <summary> | ||
524 | /// Actually send a packet to a client. | ||
525 | /// </summary> | ||
526 | /// <param name="outgoingPacket"></param> | ||
527 | internal void SendPacketFinal(OutgoingPacket outgoingPacket) | ||
528 | { | ||
529 | UDPPacketBuffer buffer = outgoingPacket.Buffer; | ||
530 | byte flags = buffer.Data[0]; | ||
531 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; | ||
532 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; | ||
533 | bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0; | ||
534 | LLUDPClient udpClient = outgoingPacket.Client; | ||
535 | |||
536 | if (!udpClient.IsConnected) | ||
537 | return; | ||
538 | |||
539 | #region ACK Appending | ||
540 | |||
541 | int dataLength = buffer.DataLength; | ||
542 | |||
543 | // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here | ||
544 | if (!isZerocoded) | ||
545 | { | ||
546 | // Keep appending ACKs until there is no room left in the buffer or there are | ||
547 | // no more ACKs to append | ||
548 | uint ackCount = 0; | ||
549 | uint ack; | ||
550 | while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack)) | ||
551 | { | ||
552 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); | ||
553 | dataLength += 4; | ||
554 | ++ackCount; | ||
555 | } | ||
556 | |||
557 | if (ackCount > 0) | ||
558 | { | ||
559 | // Set the last byte of the packet equal to the number of appended ACKs | ||
560 | buffer.Data[dataLength++] = (byte)ackCount; | ||
561 | // Set the appended ACKs flag on this packet | ||
562 | buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | buffer.DataLength = dataLength; | ||
567 | |||
568 | #endregion ACK Appending | ||
569 | |||
570 | #region Sequence Number Assignment | ||
571 | |||
572 | if (!isResend) | ||
573 | { | ||
574 | // Not a resend, assign a new sequence number | ||
575 | uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); | ||
576 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | ||
577 | outgoingPacket.SequenceNumber = sequenceNumber; | ||
578 | |||
579 | if (isReliable) | ||
580 | { | ||
581 | // Add this packet to the list of ACK responses we are waiting on from the server | ||
582 | udpClient.NeedAcks.Add(outgoingPacket); | ||
583 | } | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | Interlocked.Increment(ref udpClient.PacketsResent); | ||
588 | } | ||
589 | |||
590 | #endregion Sequence Number Assignment | ||
591 | |||
592 | // Stats tracking | ||
593 | Interlocked.Increment(ref udpClient.PacketsSent); | ||
594 | |||
595 | // Put the UDP payload on the wire | ||
596 | AsyncBeginSend(buffer); | ||
597 | |||
598 | // Keep track of when this packet was sent out (right now) | ||
599 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | ||
600 | } | ||
601 | |||
602 | protected override void PacketReceived(UDPPacketBuffer buffer) | ||
603 | { | ||
604 | // Debugging/Profiling | ||
605 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } | ||
606 | //catch (Exception) { } | ||
607 | |||
608 | LLUDPClient udpClient = null; | ||
609 | Packet packet = null; | ||
610 | int packetEnd = buffer.DataLength - 1; | ||
611 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; | ||
612 | |||
613 | #region Decoding | ||
614 | |||
615 | try | ||
616 | { | ||
617 | packet = Packet.BuildPacket(buffer.Data, ref packetEnd, | ||
618 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | ||
619 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | ||
620 | } | ||
621 | catch (MalformedDataException) | ||
622 | { | ||
623 | } | ||
624 | |||
625 | // Fail-safe check | ||
626 | if (packet == null) | ||
627 | { | ||
628 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", | ||
629 | buffer.DataLength, buffer.RemoteEndPoint); | ||
630 | m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | ||
631 | return; | ||
632 | } | ||
633 | |||
634 | #endregion Decoding | ||
635 | |||
636 | #region Packet to Client Mapping | ||
637 | |||
638 | // UseCircuitCode handling | ||
639 | if (packet.Type == PacketType.UseCircuitCode) | ||
640 | { | ||
641 | object[] array = new object[] { buffer, packet }; | ||
642 | |||
643 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
644 | |||
645 | return; | ||
646 | } | ||
647 | |||
648 | // Determine which agent this packet came from | ||
649 | IClientAPI client; | ||
650 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | ||
651 | { | ||
652 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | ||
653 | return; | ||
654 | } | ||
655 | |||
656 | udpClient = ((LLClientView)client).UDPClient; | ||
657 | |||
658 | if (!udpClient.IsConnected) | ||
659 | return; | ||
660 | |||
661 | #endregion Packet to Client Mapping | ||
662 | |||
663 | // Stats tracking | ||
664 | Interlocked.Increment(ref udpClient.PacketsReceived); | ||
665 | |||
666 | int now = Environment.TickCount & Int32.MaxValue; | ||
667 | udpClient.TickLastPacketReceived = now; | ||
668 | |||
669 | #region ACK Receiving | ||
670 | |||
671 | // Handle appended ACKs | ||
672 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | ||
673 | { | ||
674 | for (int i = 0; i < packet.Header.AckList.Length; i++) | ||
675 | udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); | ||
676 | } | ||
677 | |||
678 | // Handle PacketAck packets | ||
679 | if (packet.Type == PacketType.PacketAck) | ||
680 | { | ||
681 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | ||
682 | |||
683 | for (int i = 0; i < ackPacket.Packets.Length; i++) | ||
684 | udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); | ||
685 | |||
686 | // We don't need to do anything else with PacketAck packets | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | #endregion ACK Receiving | ||
691 | |||
692 | #region ACK Sending | ||
693 | |||
694 | if (packet.Header.Reliable) | ||
695 | { | ||
696 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); | ||
697 | |||
698 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | ||
699 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove | ||
700 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to | ||
701 | // client.BytesSinceLastACK. Lockless thread safety | ||
702 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); | ||
703 | bytesSinceLastACK += buffer.DataLength; | ||
704 | if (bytesSinceLastACK > LLUDPServer.MTU * 2) | ||
705 | { | ||
706 | bytesSinceLastACK -= LLUDPServer.MTU * 2; | ||
707 | SendAcks(udpClient); | ||
708 | } | ||
709 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); | ||
710 | } | ||
711 | |||
712 | #endregion ACK Sending | ||
713 | |||
714 | #region Incoming Packet Accounting | ||
715 | |||
716 | // Check the archive of received reliable packet IDs to see whether we already received this packet | ||
717 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) | ||
718 | { | ||
719 | if (packet.Header.Resent) | ||
720 | m_log.DebugFormat( | ||
721 | "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}", | ||
722 | packet.Header.Sequence, packet.Type, client.Name); | ||
723 | else | ||
724 | m_log.WarnFormat( | ||
725 | "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}", | ||
726 | packet.Header.Sequence, packet.Type, client.Name); | ||
727 | |||
728 | // Avoid firing a callback twice for the same packet | ||
729 | return; | ||
730 | } | ||
731 | |||
732 | #endregion Incoming Packet Accounting | ||
733 | |||
734 | #region BinaryStats | ||
735 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | ||
736 | #endregion BinaryStats | ||
737 | |||
738 | #region Ping Check Handling | ||
739 | |||
740 | if (packet.Type == PacketType.StartPingCheck) | ||
741 | { | ||
742 | // We don't need to do anything else with ping checks | ||
743 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; | ||
744 | CompletePing(udpClient, startPing.PingID.PingID); | ||
745 | |||
746 | if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) | ||
747 | { | ||
748 | udpClient.SendPacketStats(); | ||
749 | m_elapsedMSSinceLastStatReport = Environment.TickCount; | ||
750 | } | ||
751 | return; | ||
752 | } | ||
753 | else if (packet.Type == PacketType.CompletePingCheck) | ||
754 | { | ||
755 | // We don't currently track client ping times | ||
756 | return; | ||
757 | } | ||
758 | |||
759 | #endregion Ping Check Handling | ||
760 | |||
761 | // Inbox insertion | ||
762 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); | ||
763 | } | ||
764 | |||
765 | #region BinaryStats | ||
766 | |||
767 | public class PacketLogger | ||
768 | { | ||
769 | public DateTime StartTime; | ||
770 | public string Path = null; | ||
771 | public System.IO.BinaryWriter Log = null; | ||
772 | } | ||
773 | |||
774 | public static PacketLogger PacketLog; | ||
775 | |||
776 | protected static bool m_shouldCollectStats = false; | ||
777 | // Number of seconds to log for | ||
778 | static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300); | ||
779 | static object binStatsLogLock = new object(); | ||
780 | static string binStatsDir = ""; | ||
781 | |||
782 | public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) | ||
783 | { | ||
784 | if (!m_shouldCollectStats) return; | ||
785 | |||
786 | // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size | ||
787 | |||
788 | // Put the incoming bit into the least significant bit of the flags byte | ||
789 | if (incoming) | ||
790 | flags |= 0x01; | ||
791 | else | ||
792 | flags &= 0xFE; | ||
793 | |||
794 | // Put the flags byte into the most significant bits of the type integer | ||
795 | uint type = (uint)packetType; | ||
796 | type |= (uint)flags << 24; | ||
797 | |||
798 | // m_log.Debug("1 LogPacketHeader(): Outside lock"); | ||
799 | lock (binStatsLogLock) | ||
800 | { | ||
801 | DateTime now = DateTime.Now; | ||
802 | |||
803 | // m_log.Debug("2 LogPacketHeader(): Inside lock. now is " + now.Ticks); | ||
804 | try | ||
805 | { | ||
806 | if (PacketLog == null || (now > PacketLog.StartTime + binStatsMaxFilesize)) | ||
807 | { | ||
808 | if (PacketLog != null && PacketLog.Log != null) | ||
809 | { | ||
810 | PacketLog.Log.Close(); | ||
811 | } | ||
812 | |||
813 | // First log file or time has expired, start writing to a new log file | ||
814 | PacketLog = new PacketLogger(); | ||
815 | PacketLog.StartTime = now; | ||
816 | PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() : "") | ||
817 | + String.Format("packets-{0}.log", now.ToString("yyyyMMddHHmmss")); | ||
818 | PacketLog.Log = new BinaryWriter(File.Open(PacketLog.Path, FileMode.Append, FileAccess.Write)); | ||
819 | } | ||
820 | |||
821 | // Serialize the data | ||
822 | byte[] output = new byte[18]; | ||
823 | Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8); | ||
824 | Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4); | ||
825 | Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4); | ||
826 | Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2); | ||
827 | |||
828 | // Write the serialized data to disk | ||
829 | if (PacketLog != null && PacketLog.Log != null) | ||
830 | PacketLog.Log.Write(output); | ||
831 | } | ||
832 | catch (Exception ex) | ||
833 | { | ||
834 | m_log.Error("Packet statistics gathering failed: " + ex.Message, ex); | ||
835 | if (PacketLog.Log != null) | ||
836 | { | ||
837 | PacketLog.Log.Close(); | ||
838 | } | ||
839 | PacketLog = null; | ||
840 | } | ||
841 | } | ||
842 | } | ||
843 | |||
844 | #endregion BinaryStats | ||
845 | |||
846 | private void HandleUseCircuitCode(object o) | ||
847 | { | ||
848 | // DateTime startTime = DateTime.Now; | ||
849 | object[] array = (object[])o; | ||
850 | UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; | ||
851 | UseCircuitCodePacket packet = (UseCircuitCodePacket)array[1]; | ||
852 | |||
853 | m_log.DebugFormat("[LLUDPSERVER]: Handling UseCircuitCode request from {0}", buffer.RemoteEndPoint); | ||
854 | |||
855 | IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; | ||
856 | |||
857 | // Begin the process of adding the client to the simulator | ||
858 | AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint); | ||
859 | |||
860 | // Send ack | ||
861 | SendAckImmediate(remoteEndPoint, packet.Header.Sequence); | ||
862 | |||
863 | // m_log.DebugFormat( | ||
864 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", | ||
865 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); | ||
866 | } | ||
867 | |||
868 | private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) | ||
869 | { | ||
870 | PacketAckPacket ack = new PacketAckPacket(); | ||
871 | ack.Header.Reliable = false; | ||
872 | ack.Packets = new PacketAckPacket.PacketsBlock[1]; | ||
873 | ack.Packets[0] = new PacketAckPacket.PacketsBlock(); | ||
874 | ack.Packets[0].ID = sequenceNumber; | ||
875 | |||
876 | byte[] packetData = ack.ToBytes(); | ||
877 | int length = packetData.Length; | ||
878 | |||
879 | UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length); | ||
880 | buffer.DataLength = length; | ||
881 | |||
882 | Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); | ||
883 | |||
884 | AsyncBeginSend(buffer); | ||
885 | } | ||
886 | |||
887 | private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) | ||
888 | { | ||
889 | UUID agentID = useCircuitCode.CircuitCode.ID; | ||
890 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | ||
891 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
892 | |||
893 | sessionInfo = m_circuitManager.AuthenticateSession(sessionID, agentID, circuitCode); | ||
894 | return sessionInfo.Authorised; | ||
895 | } | ||
896 | |||
897 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) | ||
898 | { | ||
899 | UUID agentID = useCircuitCode.CircuitCode.ID; | ||
900 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | ||
901 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
902 | |||
903 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) | ||
904 | { | ||
905 | AuthenticateResponse sessionInfo; | ||
906 | if (IsClientAuthorized(useCircuitCode, out sessionInfo)) | ||
907 | { | ||
908 | AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); | ||
909 | } | ||
910 | else | ||
911 | { | ||
912 | // Don't create circuits for unauthorized clients | ||
913 | m_log.WarnFormat( | ||
914 | "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", | ||
915 | useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); | ||
916 | } | ||
917 | } | ||
918 | else | ||
919 | { | ||
920 | // Slave regions don't accept new clients | ||
921 | m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet"); | ||
922 | } | ||
923 | } | ||
924 | |||
925 | protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | ||
926 | { | ||
927 | // In priciple there shouldn't be more than one thread here, ever. | ||
928 | // But in case that happens, we need to synchronize this piece of code | ||
929 | // because it's too important | ||
930 | lock (this) | ||
931 | { | ||
932 | IClientAPI existingClient; | ||
933 | |||
934 | if (!m_scene.TryGetClient(agentID, out existingClient)) | ||
935 | { | ||
936 | // Create the LLUDPClient | ||
937 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); | ||
938 | // Create the LLClientView | ||
939 | LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | ||
940 | client.OnLogout += LogoutHandler; | ||
941 | |||
942 | client.DisableFacelights = m_disableFacelights; | ||
943 | |||
944 | // Start the IClientAPI | ||
945 | client.Start(); | ||
946 | |||
947 | } | ||
948 | else | ||
949 | { | ||
950 | m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}", | ||
951 | existingClient.AgentId, remoteEndPoint, circuitCode); | ||
952 | } | ||
953 | } | ||
954 | } | ||
955 | |||
956 | private void RemoveClient(LLUDPClient udpClient) | ||
957 | { | ||
958 | // Remove this client from the scene | ||
959 | IClientAPI client; | ||
960 | if (m_scene.TryGetClient(udpClient.AgentID, out client)) | ||
961 | { | ||
962 | client.IsLoggingOut = true; | ||
963 | client.Close(false); | ||
964 | } | ||
965 | } | ||
966 | |||
967 | private void IncomingPacketHandler() | ||
968 | { | ||
969 | // Set this culture for the thread that incoming packets are received | ||
970 | // on to en-US to avoid number parsing issues | ||
971 | Culture.SetCurrentCulture(); | ||
972 | |||
973 | while (base.IsRunning) | ||
974 | { | ||
975 | m_scene.ThreadAlive(1); | ||
976 | try | ||
977 | { | ||
978 | IncomingPacket incomingPacket = null; | ||
979 | |||
980 | // HACK: This is a test to try and rate limit packet handling on Mono. | ||
981 | // If it works, a more elegant solution can be devised | ||
982 | if (Util.FireAndForgetCount() < 2) | ||
983 | { | ||
984 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | ||
985 | Thread.Sleep(30); | ||
986 | } | ||
987 | |||
988 | if (packetInbox.Dequeue(100, ref incomingPacket)) | ||
989 | ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); | ||
990 | } | ||
991 | catch (Exception ex) | ||
992 | { | ||
993 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); | ||
994 | } | ||
995 | |||
996 | Watchdog.UpdateThread(); | ||
997 | } | ||
998 | |||
999 | if (packetInbox.Count > 0) | ||
1000 | m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count + " packets"); | ||
1001 | packetInbox.Clear(); | ||
1002 | |||
1003 | Watchdog.RemoveThread(); | ||
1004 | } | ||
1005 | |||
1006 | private void OutgoingPacketHandler() | ||
1007 | { | ||
1008 | // Set this culture for the thread that outgoing packets are sent | ||
1009 | // on to en-US to avoid number parsing issues | ||
1010 | Culture.SetCurrentCulture(); | ||
1011 | |||
1012 | // Typecast the function to an Action<IClientAPI> once here to avoid allocating a new | ||
1013 | // Action generic every round | ||
1014 | Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; | ||
1015 | |||
1016 | while (base.IsRunning) | ||
1017 | { | ||
1018 | m_scene.ThreadAlive(2); | ||
1019 | try | ||
1020 | { | ||
1021 | m_packetSent = false; | ||
1022 | |||
1023 | #region Update Timers | ||
1024 | |||
1025 | m_resendUnacked = false; | ||
1026 | m_sendAcks = false; | ||
1027 | m_sendPing = false; | ||
1028 | |||
1029 | // Update elapsed time | ||
1030 | int thisTick = Environment.TickCount & Int32.MaxValue; | ||
1031 | if (m_tickLastOutgoingPacketHandler > thisTick) | ||
1032 | m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); | ||
1033 | else | ||
1034 | m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); | ||
1035 | |||
1036 | m_tickLastOutgoingPacketHandler = thisTick; | ||
1037 | |||
1038 | // Check for pending outgoing resends every 100ms | ||
1039 | if (m_elapsedMSOutgoingPacketHandler >= 100) | ||
1040 | { | ||
1041 | m_resendUnacked = true; | ||
1042 | m_elapsedMSOutgoingPacketHandler = 0; | ||
1043 | m_elapsed100MSOutgoingPacketHandler += 1; | ||
1044 | } | ||
1045 | |||
1046 | // Check for pending outgoing ACKs every 500ms | ||
1047 | if (m_elapsed100MSOutgoingPacketHandler >= 5) | ||
1048 | { | ||
1049 | m_sendAcks = true; | ||
1050 | m_elapsed100MSOutgoingPacketHandler = 0; | ||
1051 | m_elapsed500MSOutgoingPacketHandler += 1; | ||
1052 | } | ||
1053 | |||
1054 | // Send pings to clients every 5000ms | ||
1055 | if (m_elapsed500MSOutgoingPacketHandler >= 10) | ||
1056 | { | ||
1057 | m_sendPing = true; | ||
1058 | m_elapsed500MSOutgoingPacketHandler = 0; | ||
1059 | } | ||
1060 | |||
1061 | #endregion Update Timers | ||
1062 | |||
1063 | // Use this for emergency monitoring -- bug hunting | ||
1064 | //if (m_scene.EmergencyMonitoring) | ||
1065 | // clientPacketHandler = MonitoredClientOutgoingPacketHandler; | ||
1066 | //else | ||
1067 | // clientPacketHandler = ClientOutgoingPacketHandler; | ||
1068 | |||
1069 | // Handle outgoing packets, resends, acknowledgements, and pings for each | ||
1070 | // client. m_packetSent will be set to true if a packet is sent | ||
1071 | m_scene.ForEachClient(clientPacketHandler); | ||
1072 | |||
1073 | // If nothing was sent, sleep for the minimum amount of time before a | ||
1074 | // token bucket could get more tokens | ||
1075 | if (!m_packetSent) | ||
1076 | Thread.Sleep((int)TickCountResolution); | ||
1077 | |||
1078 | Watchdog.UpdateThread(); | ||
1079 | } | ||
1080 | catch (Exception ex) | ||
1081 | { | ||
1082 | m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex); | ||
1083 | } | ||
1084 | |||
1085 | } | ||
1086 | |||
1087 | Watchdog.RemoveThread(); | ||
1088 | } | ||
1089 | |||
1090 | private void ClientOutgoingPacketHandler(IClientAPI client) | ||
1091 | { | ||
1092 | try | ||
1093 | { | ||
1094 | if (client is LLClientView) | ||
1095 | { | ||
1096 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; | ||
1097 | |||
1098 | if (udpClient.IsConnected) | ||
1099 | { | ||
1100 | if (m_resendUnacked) | ||
1101 | HandleUnacked(udpClient); | ||
1102 | |||
1103 | if (m_sendAcks) | ||
1104 | SendAcks(udpClient); | ||
1105 | |||
1106 | if (m_sendPing) | ||
1107 | SendPing(udpClient); | ||
1108 | |||
1109 | // Dequeue any outgoing packets that are within the throttle limits | ||
1110 | if (udpClient.DequeueOutgoing()) | ||
1111 | m_packetSent = true; | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | catch (Exception ex) | ||
1116 | { | ||
1117 | m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + | ||
1118 | " threw an exception: " + ex.Message, ex); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | #region Emergency Monitoring | ||
1123 | // Alternative packet handler fuull of instrumentation | ||
1124 | // Handy for hunting bugs | ||
1125 | private Stopwatch watch1 = new Stopwatch(); | ||
1126 | private Stopwatch watch2 = new Stopwatch(); | ||
1127 | |||
1128 | private float avgProcessingTicks = 0; | ||
1129 | private float avgResendUnackedTicks = 0; | ||
1130 | private float avgSendAcksTicks = 0; | ||
1131 | private float avgSendPingTicks = 0; | ||
1132 | private float avgDequeueTicks = 0; | ||
1133 | private long nticks = 0; | ||
1134 | private long nticksUnack = 0; | ||
1135 | private long nticksAck = 0; | ||
1136 | private long nticksPing = 0; | ||
1137 | private int npacksSent = 0; | ||
1138 | private int npackNotSent = 0; | ||
1139 | |||
1140 | private void MonitoredClientOutgoingPacketHandler(IClientAPI client) | ||
1141 | { | ||
1142 | nticks++; | ||
1143 | watch1.Start(); | ||
1144 | try | ||
1145 | { | ||
1146 | if (client is LLClientView) | ||
1147 | { | ||
1148 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; | ||
1149 | |||
1150 | if (udpClient.IsConnected) | ||
1151 | { | ||
1152 | if (m_resendUnacked) | ||
1153 | { | ||
1154 | nticksUnack++; | ||
1155 | watch2.Start(); | ||
1156 | |||
1157 | HandleUnacked(udpClient); | ||
1158 | |||
1159 | watch2.Stop(); | ||
1160 | avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); | ||
1161 | watch2.Reset(); | ||
1162 | } | ||
1163 | |||
1164 | if (m_sendAcks) | ||
1165 | { | ||
1166 | nticksAck++; | ||
1167 | watch2.Start(); | ||
1168 | |||
1169 | SendAcks(udpClient); | ||
1170 | |||
1171 | watch2.Stop(); | ||
1172 | avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck); | ||
1173 | watch2.Reset(); | ||
1174 | } | ||
1175 | |||
1176 | if (m_sendPing) | ||
1177 | { | ||
1178 | nticksPing++; | ||
1179 | watch2.Start(); | ||
1180 | |||
1181 | SendPing(udpClient); | ||
1182 | |||
1183 | watch2.Stop(); | ||
1184 | avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing); | ||
1185 | watch2.Reset(); | ||
1186 | } | ||
1187 | |||
1188 | watch2.Start(); | ||
1189 | // Dequeue any outgoing packets that are within the throttle limits | ||
1190 | if (udpClient.DequeueOutgoing()) | ||
1191 | { | ||
1192 | m_packetSent = true; | ||
1193 | npacksSent++; | ||
1194 | } | ||
1195 | else | ||
1196 | npackNotSent++; | ||
1197 | |||
1198 | watch2.Stop(); | ||
1199 | avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks); | ||
1200 | watch2.Reset(); | ||
1201 | |||
1202 | } | ||
1203 | else | ||
1204 | m_log.WarnFormat("[LLUDPSERVER]: Client is not connected"); | ||
1205 | } | ||
1206 | } | ||
1207 | catch (Exception ex) | ||
1208 | { | ||
1209 | m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + | ||
1210 | " threw an exception: " + ex.Message, ex); | ||
1211 | } | ||
1212 | watch1.Stop(); | ||
1213 | avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks); | ||
1214 | watch1.Reset(); | ||
1215 | |||
1216 | // reuse this -- it's every ~100ms | ||
1217 | if (m_scene.EmergencyMonitoring && nticks % 100 == 0) | ||
1218 | { | ||
1219 | 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})", | ||
1220 | avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); | ||
1221 | npackNotSent = npacksSent = 0; | ||
1222 | } | ||
1223 | |||
1224 | } | ||
1225 | |||
1226 | #endregion | ||
1227 | |||
1228 | private void ProcessInPacket(object state) | ||
1229 | { | ||
1230 | IncomingPacket incomingPacket = (IncomingPacket)state; | ||
1231 | Packet packet = incomingPacket.Packet; | ||
1232 | LLUDPClient udpClient = incomingPacket.Client; | ||
1233 | IClientAPI client; | ||
1234 | |||
1235 | // Sanity check | ||
1236 | if (packet == null || udpClient == null) | ||
1237 | { | ||
1238 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", | ||
1239 | packet, udpClient); | ||
1240 | } | ||
1241 | |||
1242 | // Make sure this client is still alive | ||
1243 | if (m_scene.TryGetClient(udpClient.AgentID, out client)) | ||
1244 | { | ||
1245 | try | ||
1246 | { | ||
1247 | // Process this packet | ||
1248 | client.ProcessInPacket(packet); | ||
1249 | } | ||
1250 | catch (ThreadAbortException) | ||
1251 | { | ||
1252 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | ||
1253 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | ||
1254 | Stop(); | ||
1255 | } | ||
1256 | catch (Exception e) | ||
1257 | { | ||
1258 | // Don't let a failure in an individual client thread crash the whole sim. | ||
1259 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); | ||
1260 | m_log.Error(e.Message, e); | ||
1261 | } | ||
1262 | } | ||
1263 | else | ||
1264 | { | ||
1265 | m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | protected void LogoutHandler(IClientAPI client) | ||
1270 | { | ||
1271 | client.SendLogoutPacket(); | ||
1272 | if (client.IsActive) | ||
1273 | RemoveClient(((LLClientView)client).UDPClient); | ||
1274 | } | ||
1275 | } | ||
1276 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs new file mode 100644 index 0000000..d2779ba --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -0,0 +1,280 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006, Clutch, Inc. | ||
3 | * Original Author: Jeff Cesnik | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * - Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * | ||
9 | * - Redistributions of source code must retain the above copyright notice, this | ||
10 | * list of conditions and the following disclaimer. | ||
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 | ||
13 | * this software without specific prior written permission. | ||
14 | * | ||
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 | ||
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
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 | ||
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 | ||
25 | * POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using System.Net.Sockets; | ||
31 | using System.Threading; | ||
32 | using log4net; | ||
33 | |||
34 | namespace OpenMetaverse | ||
35 | { | ||
36 | /// <summary> | ||
37 | /// Base UDP server | ||
38 | /// </summary> | ||
39 | public abstract class OpenSimUDPBase | ||
40 | { | ||
41 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | |||
43 | /// <summary> | ||
44 | /// This method is called when an incoming packet is received | ||
45 | /// </summary> | ||
46 | /// <param name="buffer">Incoming packet buffer</param> | ||
47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); | ||
48 | |||
49 | /// <summary>UDP port to bind to in server mode</summary> | ||
50 | protected int m_udpPort; | ||
51 | |||
52 | /// <summary>Local IP address to bind to in server mode</summary> | ||
53 | protected IPAddress m_localBindAddress; | ||
54 | |||
55 | /// <summary>UDP socket, used in either client or server mode</summary> | ||
56 | private Socket m_udpSocket; | ||
57 | |||
58 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
59 | private bool m_asyncPacketHandling; | ||
60 | |||
61 | /// <summary>The all important shutdown flag</summary> | ||
62 | private volatile bool m_shutdownFlag = true; | ||
63 | |||
64 | /// <summary>Returns true if the server is currently listening, otherwise false</summary> | ||
65 | public bool IsRunning { get { return !m_shutdownFlag; } } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Default constructor | ||
69 | /// </summary> | ||
70 | /// <param name="bindAddress">Local IP address to bind the server to</param> | ||
71 | /// <param name="port">Port to listening for incoming UDP packets on</param> | ||
72 | public OpenSimUDPBase(IPAddress bindAddress, int port) | ||
73 | { | ||
74 | m_localBindAddress = bindAddress; | ||
75 | m_udpPort = port; | ||
76 | } | ||
77 | |||
78 | /// <summary> | ||
79 | /// Start the UDP server | ||
80 | /// </summary> | ||
81 | /// <param name="recvBufferSize">The size of the receive buffer for | ||
82 | /// the UDP socket. This value is passed up to the operating system | ||
83 | /// and used in the system networking stack. Use zero to leave this | ||
84 | /// value as the default</param> | ||
85 | /// <param name="asyncPacketHandling">Set this to true to start | ||
86 | /// receiving more packets while current packet handler callbacks are | ||
87 | /// still running. Setting this to false will complete each packet | ||
88 | /// callback before the next packet is processed</param> | ||
89 | /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag | ||
90 | /// on the socket to get newer versions of Windows to behave in a sane | ||
91 | /// manner (not throwing an exception when the remote side resets the | ||
92 | /// connection). This call is ignored on Mono where the flag is not | ||
93 | /// necessary</remarks> | ||
94 | public void Start(int recvBufferSize, bool asyncPacketHandling) | ||
95 | { | ||
96 | m_asyncPacketHandling = asyncPacketHandling; | ||
97 | |||
98 | if (m_shutdownFlag) | ||
99 | { | ||
100 | const int SIO_UDP_CONNRESET = -1744830452; | ||
101 | |||
102 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); | ||
103 | |||
104 | m_udpSocket = new Socket( | ||
105 | AddressFamily.InterNetwork, | ||
106 | SocketType.Dgram, | ||
107 | ProtocolType.Udp); | ||
108 | |||
109 | try | ||
110 | { | ||
111 | // This udp socket flag is not supported under mono, | ||
112 | // so we'll catch the exception and continue | ||
113 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | ||
114 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
115 | } | ||
116 | catch (SocketException) | ||
117 | { | ||
118 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | ||
119 | } | ||
120 | |||
121 | if (recvBufferSize != 0) | ||
122 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | ||
123 | |||
124 | m_udpSocket.Bind(ipep); | ||
125 | |||
126 | // we're not shutting down, we're starting up | ||
127 | m_shutdownFlag = false; | ||
128 | |||
129 | // kick off an async receive. The Start() method will return, the | ||
130 | // actual receives will occur asynchronously and will be caught in | ||
131 | // AsyncEndRecieve(). | ||
132 | AsyncBeginReceive(); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | /// <summary> | ||
137 | /// Stops the UDP server | ||
138 | /// </summary> | ||
139 | public void Stop() | ||
140 | { | ||
141 | if (!m_shutdownFlag) | ||
142 | { | ||
143 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime | ||
144 | // will deny any more reader locks, in effect blocking all other send/receive | ||
145 | // threads. Once we have the lock, we set shutdownFlag to inform the other | ||
146 | // threads that the socket is closed. | ||
147 | m_shutdownFlag = true; | ||
148 | m_udpSocket.Close(); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | private void AsyncBeginReceive() | ||
153 | { | ||
154 | // allocate a packet buffer | ||
155 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | ||
156 | UDPPacketBuffer buf = new UDPPacketBuffer(); | ||
157 | |||
158 | if (!m_shutdownFlag) | ||
159 | { | ||
160 | try | ||
161 | { | ||
162 | // kick off an async read | ||
163 | m_udpSocket.BeginReceiveFrom( | ||
164 | //wrappedBuffer.Instance.Data, | ||
165 | buf.Data, | ||
166 | 0, | ||
167 | UDPPacketBuffer.BUFFER_SIZE, | ||
168 | SocketFlags.None, | ||
169 | ref buf.RemoteEndPoint, | ||
170 | AsyncEndReceive, | ||
171 | //wrappedBuffer); | ||
172 | buf); | ||
173 | } | ||
174 | catch (SocketException e) | ||
175 | { | ||
176 | if (e.SocketErrorCode == SocketError.ConnectionReset) | ||
177 | { | ||
178 | m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); | ||
179 | bool salvaged = false; | ||
180 | while (!salvaged) | ||
181 | { | ||
182 | try | ||
183 | { | ||
184 | m_udpSocket.BeginReceiveFrom( | ||
185 | //wrappedBuffer.Instance.Data, | ||
186 | buf.Data, | ||
187 | 0, | ||
188 | UDPPacketBuffer.BUFFER_SIZE, | ||
189 | SocketFlags.None, | ||
190 | ref buf.RemoteEndPoint, | ||
191 | AsyncEndReceive, | ||
192 | //wrappedBuffer); | ||
193 | buf); | ||
194 | salvaged = true; | ||
195 | } | ||
196 | catch (SocketException) { } | ||
197 | catch (ObjectDisposedException) { return; } | ||
198 | } | ||
199 | |||
200 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); | ||
201 | } | ||
202 | } | ||
203 | catch (ObjectDisposedException) { } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | private void AsyncEndReceive(IAsyncResult iar) | ||
208 | { | ||
209 | // Asynchronous receive operations will complete here through the call | ||
210 | // to AsyncBeginReceive | ||
211 | if (!m_shutdownFlag) | ||
212 | { | ||
213 | // Asynchronous mode will start another receive before the | ||
214 | // callback for this packet is even fired. Very parallel :-) | ||
215 | if (m_asyncPacketHandling) | ||
216 | AsyncBeginReceive(); | ||
217 | |||
218 | // get the buffer that was created in AsyncBeginReceive | ||
219 | // this is the received data | ||
220 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState; | ||
221 | //UDPPacketBuffer buffer = wrappedBuffer.Instance; | ||
222 | UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
223 | |||
224 | try | ||
225 | { | ||
226 | // get the length of data actually read from the socket, store it with the | ||
227 | // buffer | ||
228 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | ||
229 | |||
230 | // call the abstract method PacketReceived(), passing the buffer that | ||
231 | // has just been filled from the socket read. | ||
232 | PacketReceived(buffer); | ||
233 | } | ||
234 | catch (SocketException) { } | ||
235 | catch (ObjectDisposedException) { } | ||
236 | finally | ||
237 | { | ||
238 | //wrappedBuffer.Dispose(); | ||
239 | |||
240 | // Synchronous mode waits until the packet callback completes | ||
241 | // before starting the receive to fetch another packet | ||
242 | if (!m_asyncPacketHandling) | ||
243 | AsyncBeginReceive(); | ||
244 | } | ||
245 | |||
246 | } | ||
247 | } | ||
248 | |||
249 | public void AsyncBeginSend(UDPPacketBuffer buf) | ||
250 | { | ||
251 | if (!m_shutdownFlag) | ||
252 | { | ||
253 | try | ||
254 | { | ||
255 | m_udpSocket.BeginSendTo( | ||
256 | buf.Data, | ||
257 | 0, | ||
258 | buf.DataLength, | ||
259 | SocketFlags.None, | ||
260 | buf.RemoteEndPoint, | ||
261 | AsyncEndSend, | ||
262 | buf); | ||
263 | } | ||
264 | catch (SocketException) { } | ||
265 | catch (ObjectDisposedException) { } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | void AsyncEndSend(IAsyncResult result) | ||
270 | { | ||
271 | try | ||
272 | { | ||
273 | // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | ||
274 | m_udpSocket.EndSendTo(result); | ||
275 | } | ||
276 | catch (SocketException) { } | ||
277 | catch (ObjectDisposedException) { } | ||
278 | } | ||
279 | } | ||
280 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs new file mode 100644 index 0000000..76c6c14 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs | |||
@@ -0,0 +1,75 @@ | |||
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 OpenSim.Framework; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
33 | { | ||
34 | |||
35 | public delegate void UnackedPacketMethod(OutgoingPacket oPacket); | ||
36 | /// <summary> | ||
37 | /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is | ||
38 | /// destined for, along with the serialized packet data, sequence number | ||
39 | /// (if this is a resend), number of times this packet has been resent, | ||
40 | /// the time of the last resend, and the throttling category for this | ||
41 | /// packet | ||
42 | /// </summary> | ||
43 | public sealed class OutgoingPacket | ||
44 | { | ||
45 | /// <summary>Client this packet is destined for</summary> | ||
46 | public LLUDPClient Client; | ||
47 | /// <summary>Packet data to send</summary> | ||
48 | public UDPPacketBuffer Buffer; | ||
49 | /// <summary>Sequence number of the wrapped packet</summary> | ||
50 | public uint SequenceNumber; | ||
51 | /// <summary>Number of times this packet has been resent</summary> | ||
52 | public int ResendCount; | ||
53 | /// <summary>Environment.TickCount when this packet was last sent over the wire</summary> | ||
54 | public int TickCount; | ||
55 | /// <summary>Category this packet belongs to</summary> | ||
56 | public ThrottleOutPacketType Category; | ||
57 | /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary> | ||
58 | public UnackedPacketMethod UnackedMethod; | ||
59 | |||
60 | /// <summary> | ||
61 | /// Default constructor | ||
62 | /// </summary> | ||
63 | /// <param name="client">Reference to the client this packet is destined for</param> | ||
64 | /// <param name="buffer">Serialized packet data. If the flags or sequence number | ||
65 | /// need to be updated, they will be injected directly into this binary buffer</param> | ||
66 | /// <param name="category">Throttling category for this packet</param> | ||
67 | public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method) | ||
68 | { | ||
69 | Client = client; | ||
70 | Buffer = buffer; | ||
71 | Category = category; | ||
72 | UnackedMethod = method; | ||
73 | } | ||
74 | } | ||
75 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs new file mode 100644 index 0000000..daab84f --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | |||
@@ -0,0 +1,299 @@ | |||
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.Net; | ||
29 | using log4net.Config; | ||
30 | using Nini.Config; | ||
31 | using NUnit.Framework; | ||
32 | using NUnit.Framework.SyntaxHelpers; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.Packets; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Tests.Common; | ||
37 | using OpenSim.Tests.Common.Mock; | ||
38 | |||
39 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// This will contain basic tests for the LindenUDP client stack | ||
43 | /// </summary> | ||
44 | [TestFixture] | ||
45 | public class BasicCircuitTests | ||
46 | { | ||
47 | [SetUp] | ||
48 | public void Init() | ||
49 | { | ||
50 | try | ||
51 | { | ||
52 | XmlConfigurator.Configure(); | ||
53 | } | ||
54 | catch | ||
55 | { | ||
56 | // I don't care, just leave log4net off | ||
57 | } | ||
58 | } | ||
59 | |||
60 | /// <summary> | ||
61 | /// Add a client for testing | ||
62 | /// </summary> | ||
63 | /// <param name="scene"></param> | ||
64 | /// <param name="testLLUDPServer"></param> | ||
65 | /// <param name="testPacketServer"></param> | ||
66 | /// <param name="acm">Agent circuit manager used in setting up the stack</param> | ||
67 | protected void SetupStack( | ||
68 | IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, | ||
69 | out AgentCircuitManager acm) | ||
70 | { | ||
71 | IConfigSource configSource = new IniConfigSource(); | ||
72 | ClientStackUserSettings userSettings = new ClientStackUserSettings(); | ||
73 | testLLUDPServer = new TestLLUDPServer(); | ||
74 | acm = new AgentCircuitManager(); | ||
75 | |||
76 | uint port = 666; | ||
77 | testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); | ||
78 | testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); | ||
79 | testLLUDPServer.LocalScene = scene; | ||
80 | } | ||
81 | |||
82 | /// <summary> | ||
83 | /// Set up a client for tests which aren't concerned with this process itself and where only one client is being | ||
84 | /// tested | ||
85 | /// </summary> | ||
86 | /// <param name="circuitCode"></param> | ||
87 | /// <param name="epSender"></param> | ||
88 | /// <param name="testLLUDPServer"></param> | ||
89 | /// <param name="acm"></param> | ||
90 | protected void AddClient( | ||
91 | uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) | ||
92 | { | ||
93 | UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
94 | UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); | ||
95 | |||
96 | AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm); | ||
97 | } | ||
98 | |||
99 | /// <summary> | ||
100 | /// Set up a client for tests which aren't concerned with this process itself | ||
101 | /// </summary> | ||
102 | /// <param name="circuitCode"></param> | ||
103 | /// <param name="epSender"></param> | ||
104 | /// <param name="agentId"></param> | ||
105 | /// <param name="sessionId"></param> | ||
106 | /// <param name="testLLUDPServer"></param> | ||
107 | /// <param name="acm"></param> | ||
108 | protected void AddClient( | ||
109 | uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId, | ||
110 | TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) | ||
111 | { | ||
112 | AgentCircuitData acd = new AgentCircuitData(); | ||
113 | acd.AgentID = agentId; | ||
114 | acd.SessionID = sessionId; | ||
115 | |||
116 | UseCircuitCodePacket uccp = new UseCircuitCodePacket(); | ||
117 | |||
118 | UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock | ||
119 | = new UseCircuitCodePacket.CircuitCodeBlock(); | ||
120 | uccpCcBlock.Code = circuitCode; | ||
121 | uccpCcBlock.ID = agentId; | ||
122 | uccpCcBlock.SessionID = sessionId; | ||
123 | uccp.CircuitCode = uccpCcBlock; | ||
124 | |||
125 | acm.AddNewCircuit(circuitCode, acd); | ||
126 | |||
127 | testLLUDPServer.LoadReceive(uccp, epSender); | ||
128 | testLLUDPServer.ReceiveData(null); | ||
129 | } | ||
130 | |||
131 | /// <summary> | ||
132 | /// Build an object name packet for test purposes | ||
133 | /// </summary> | ||
134 | /// <param name="objectLocalId"></param> | ||
135 | /// <param name="objectName"></param> | ||
136 | protected ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) | ||
137 | { | ||
138 | ObjectNamePacket onp = new ObjectNamePacket(); | ||
139 | ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); | ||
140 | odb.LocalID = objectLocalId; | ||
141 | odb.Name = Utils.StringToBytes(objectName); | ||
142 | onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; | ||
143 | onp.Header.Zerocoded = false; | ||
144 | |||
145 | return onp; | ||
146 | } | ||
147 | |||
148 | /// <summary> | ||
149 | /// Test adding a client to the stack | ||
150 | /// </summary> | ||
151 | [Test, LongRunning] | ||
152 | public void TestAddClient() | ||
153 | { | ||
154 | TestHelper.InMethod(); | ||
155 | |||
156 | uint myCircuitCode = 123456; | ||
157 | UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
158 | UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); | ||
159 | |||
160 | TestLLUDPServer testLLUDPServer; | ||
161 | TestLLPacketServer testLLPacketServer; | ||
162 | AgentCircuitManager acm; | ||
163 | SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); | ||
164 | |||
165 | AgentCircuitData acd = new AgentCircuitData(); | ||
166 | acd.AgentID = myAgentUuid; | ||
167 | acd.SessionID = mySessionUuid; | ||
168 | |||
169 | UseCircuitCodePacket uccp = new UseCircuitCodePacket(); | ||
170 | |||
171 | UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock | ||
172 | = new UseCircuitCodePacket.CircuitCodeBlock(); | ||
173 | uccpCcBlock.Code = myCircuitCode; | ||
174 | uccpCcBlock.ID = myAgentUuid; | ||
175 | uccpCcBlock.SessionID = mySessionUuid; | ||
176 | uccp.CircuitCode = uccpCcBlock; | ||
177 | |||
178 | EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); | ||
179 | |||
180 | testLLUDPServer.LoadReceive(uccp, testEp); | ||
181 | testLLUDPServer.ReceiveData(null); | ||
182 | |||
183 | // Circuit shouildn't exist since the circuit manager doesn't know about this circuit for authentication yet | ||
184 | Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); | ||
185 | |||
186 | acm.AddNewCircuit(myCircuitCode, acd); | ||
187 | |||
188 | testLLUDPServer.LoadReceive(uccp, testEp); | ||
189 | testLLUDPServer.ReceiveData(null); | ||
190 | |||
191 | // Should succeed now | ||
192 | Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); | ||
193 | Assert.IsFalse(testLLUDPServer.HasCircuit(101)); | ||
194 | } | ||
195 | |||
196 | /// <summary> | ||
197 | /// Test removing a client from the stack | ||
198 | /// </summary> | ||
199 | [Test] | ||
200 | public void TestRemoveClient() | ||
201 | { | ||
202 | TestHelper.InMethod(); | ||
203 | |||
204 | uint myCircuitCode = 123457; | ||
205 | |||
206 | TestLLUDPServer testLLUDPServer; | ||
207 | TestLLPacketServer testLLPacketServer; | ||
208 | AgentCircuitManager acm; | ||
209 | SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); | ||
210 | AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm); | ||
211 | |||
212 | testLLUDPServer.RemoveClientCircuit(myCircuitCode); | ||
213 | Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); | ||
214 | |||
215 | // Check that removing a non-existant circuit doesn't have any bad effects | ||
216 | testLLUDPServer.RemoveClientCircuit(101); | ||
217 | Assert.IsFalse(testLLUDPServer.HasCircuit(101)); | ||
218 | } | ||
219 | |||
220 | /// <summary> | ||
221 | /// Make sure that the client stack reacts okay to malformed packets | ||
222 | /// </summary> | ||
223 | [Test] | ||
224 | public void TestMalformedPacketSend() | ||
225 | { | ||
226 | TestHelper.InMethod(); | ||
227 | |||
228 | uint myCircuitCode = 123458; | ||
229 | EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001); | ||
230 | MockScene scene = new MockScene(); | ||
231 | |||
232 | TestLLUDPServer testLLUDPServer; | ||
233 | TestLLPacketServer testLLPacketServer; | ||
234 | AgentCircuitManager acm; | ||
235 | SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); | ||
236 | AddClient(myCircuitCode, testEp, testLLUDPServer, acm); | ||
237 | |||
238 | byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 }; | ||
239 | |||
240 | // Send two garbled 'packets' in succession | ||
241 | testLLUDPServer.LoadReceive(data, testEp); | ||
242 | testLLUDPServer.LoadReceive(data, testEp); | ||
243 | testLLUDPServer.ReceiveData(null); | ||
244 | |||
245 | // Check that we are still here | ||
246 | Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); | ||
247 | Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0)); | ||
248 | |||
249 | // Check that sending a valid packet to same circuit still succeeds | ||
250 | Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0)); | ||
251 | |||
252 | testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp); | ||
253 | testLLUDPServer.ReceiveData(null); | ||
254 | |||
255 | Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1)); | ||
256 | Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1)); | ||
257 | } | ||
258 | |||
259 | /// <summary> | ||
260 | /// Test that the stack continues to work even if some client has caused a | ||
261 | /// SocketException on Socket.BeginReceive() | ||
262 | /// </summary> | ||
263 | [Test] | ||
264 | public void TestExceptionOnBeginReceive() | ||
265 | { | ||
266 | TestHelper.InMethod(); | ||
267 | |||
268 | MockScene scene = new MockScene(); | ||
269 | |||
270 | uint circuitCodeA = 130000; | ||
271 | EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300); | ||
272 | UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300"); | ||
273 | UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300"); | ||
274 | |||
275 | uint circuitCodeB = 130001; | ||
276 | EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301); | ||
277 | UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301"); | ||
278 | UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301"); | ||
279 | |||
280 | TestLLUDPServer testLLUDPServer; | ||
281 | TestLLPacketServer testLLPacketServer; | ||
282 | AgentCircuitManager acm; | ||
283 | SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); | ||
284 | AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm); | ||
285 | AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm); | ||
286 | |||
287 | testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA); | ||
288 | testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB); | ||
289 | testLLUDPServer.LoadReceiveWithBeginException(epA); | ||
290 | testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB); | ||
291 | testLLUDPServer.ReceiveData(null); | ||
292 | |||
293 | Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA)); | ||
294 | |||
295 | Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3)); | ||
296 | Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3)); | ||
297 | } | ||
298 | } | ||
299 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs new file mode 100644 index 0000000..34c21aa --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs | |||
@@ -0,0 +1,72 @@ | |||
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 OpenMetaverse; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.Framework.Scenes; | ||
31 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
32 | |||
33 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Mock scene for unit tests | ||
37 | /// </summary> | ||
38 | public class MockScene : SceneBase | ||
39 | { | ||
40 | public int ObjectNameCallsReceived | ||
41 | { | ||
42 | get { return m_objectNameCallsReceived; } | ||
43 | } | ||
44 | protected int m_objectNameCallsReceived; | ||
45 | |||
46 | public MockScene() | ||
47 | { | ||
48 | m_regInfo = new RegionInfo(1000, 1000, null, null); | ||
49 | m_regStatus = RegionStatus.Up; | ||
50 | } | ||
51 | |||
52 | public override void Update() {} | ||
53 | public override void LoadWorldMap() {} | ||
54 | |||
55 | public override void AddNewClient(IClientAPI client) | ||
56 | { | ||
57 | client.OnObjectName += RecordObjectNameCall; | ||
58 | } | ||
59 | |||
60 | public override void RemoveClient(UUID agentID) {} | ||
61 | public override void CloseAllAgents(uint circuitcode) {} | ||
62 | public override void OtherRegionUp(GridRegion otherRegion) { } | ||
63 | |||
64 | /// <summary> | ||
65 | /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received | ||
66 | /// </summary> | ||
67 | protected void RecordObjectNameCall(IClientAPI remoteClient, uint localID, string message) | ||
68 | { | ||
69 | m_objectNameCallsReceived++; | ||
70 | } | ||
71 | } | ||
72 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs new file mode 100644 index 0000000..7d0757f --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs | |||
@@ -0,0 +1,106 @@ | |||
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 Nini.Config; | ||
29 | using NUnit.Framework; | ||
30 | using NUnit.Framework.SyntaxHelpers; | ||
31 | using OpenMetaverse; | ||
32 | using OpenMetaverse.Packets; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Tests.Common.Mock; | ||
35 | using OpenSim.Tests.Common; | ||
36 | |||
37 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
38 | { | ||
39 | /// <summary> | ||
40 | /// Tests for the LL packet handler | ||
41 | /// </summary> | ||
42 | [TestFixture] | ||
43 | public class PacketHandlerTests | ||
44 | { | ||
45 | [Test] | ||
46 | /// <summary> | ||
47 | /// More a placeholder, really | ||
48 | /// </summary> | ||
49 | public void InPacketTest() | ||
50 | { | ||
51 | TestHelper.InMethod(); | ||
52 | |||
53 | AgentCircuitData agent = new AgentCircuitData(); | ||
54 | agent.AgentID = UUID.Random(); | ||
55 | agent.firstname = "testfirstname"; | ||
56 | agent.lastname = "testlastname"; | ||
57 | agent.SessionID = UUID.Zero; | ||
58 | agent.SecureSessionID = UUID.Zero; | ||
59 | agent.circuitcode = 123; | ||
60 | agent.BaseFolder = UUID.Zero; | ||
61 | agent.InventoryFolder = UUID.Zero; | ||
62 | agent.startpos = Vector3.Zero; | ||
63 | agent.CapsPath = "http://wibble.com"; | ||
64 | |||
65 | TestLLUDPServer testLLUDPServer; | ||
66 | TestLLPacketServer testLLPacketServer; | ||
67 | AgentCircuitManager acm; | ||
68 | IScene scene = new MockScene(); | ||
69 | SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); | ||
70 | |||
71 | TestClient testClient = new TestClient(agent, scene); | ||
72 | |||
73 | LLPacketHandler packetHandler | ||
74 | = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings()); | ||
75 | |||
76 | packetHandler.InPacket(new AgentAnimationPacket()); | ||
77 | LLQueItem receivedPacket = packetHandler.PacketQueue.Dequeue(); | ||
78 | |||
79 | Assert.That(receivedPacket, Is.Not.Null); | ||
80 | Assert.That(receivedPacket.Incoming, Is.True); | ||
81 | Assert.That(receivedPacket.Packet, Is.TypeOf(typeof(AgentAnimationPacket))); | ||
82 | } | ||
83 | |||
84 | /// <summary> | ||
85 | /// Add a client for testing | ||
86 | /// </summary> | ||
87 | /// <param name="scene"></param> | ||
88 | /// <param name="testLLUDPServer"></param> | ||
89 | /// <param name="testPacketServer"></param> | ||
90 | /// <param name="acm">Agent circuit manager used in setting up the stack</param> | ||
91 | protected void SetupStack( | ||
92 | IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, | ||
93 | out AgentCircuitManager acm) | ||
94 | { | ||
95 | IConfigSource configSource = new IniConfigSource(); | ||
96 | ClientStackUserSettings userSettings = new ClientStackUserSettings(); | ||
97 | testLLUDPServer = new TestLLUDPServer(); | ||
98 | acm = new AgentCircuitManager(); | ||
99 | |||
100 | uint port = 666; | ||
101 | testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); | ||
102 | testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); | ||
103 | testLLUDPServer.LocalScene = scene; | ||
104 | } | ||
105 | } | ||
106 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLPacketServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLPacketServer.cs new file mode 100644 index 0000000..e995d65 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLPacketServer.cs | |||
@@ -0,0 +1,72 @@ | |||
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.Collections.Generic; | ||
29 | using OpenMetaverse.Packets; | ||
30 | |||
31 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
32 | { | ||
33 | public class TestLLPacketServer : LLPacketServer | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Record counts of packets received | ||
37 | /// </summary> | ||
38 | protected Dictionary<PacketType, int> m_packetsReceived = new Dictionary<PacketType, int>(); | ||
39 | |||
40 | public TestLLPacketServer(LLUDPServer networkHandler, ClientStackUserSettings userSettings) | ||
41 | : base(networkHandler, userSettings) | ||
42 | {} | ||
43 | |||
44 | public override void InPacket(uint circuitCode, Packet packet) | ||
45 | { | ||
46 | base.InPacket(circuitCode, packet); | ||
47 | |||
48 | if (m_packetsReceived.ContainsKey(packet.Type)) | ||
49 | m_packetsReceived[packet.Type]++; | ||
50 | else | ||
51 | m_packetsReceived[packet.Type] = 1; | ||
52 | } | ||
53 | |||
54 | public int GetTotalPacketsReceived() | ||
55 | { | ||
56 | int totalCount = 0; | ||
57 | |||
58 | foreach (int count in m_packetsReceived.Values) | ||
59 | totalCount += count; | ||
60 | |||
61 | return totalCount; | ||
62 | } | ||
63 | |||
64 | public int GetPacketsReceivedFor(PacketType packetType) | ||
65 | { | ||
66 | if (m_packetsReceived.ContainsKey(packetType)) | ||
67 | return m_packetsReceived[packetType]; | ||
68 | else | ||
69 | return 0; | ||
70 | } | ||
71 | } | ||
72 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs new file mode 100644 index 0000000..f98586d --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs | |||
@@ -0,0 +1,153 @@ | |||
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.Generic; | ||
30 | using System.Net; | ||
31 | using System.Net.Sockets; | ||
32 | using OpenMetaverse.Packets; | ||
33 | |||
34 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
35 | { | ||
36 | /// <summary> | ||
37 | /// This class enables synchronous testing of the LLUDPServer by allowing us to load our own data into the end | ||
38 | /// receive event | ||
39 | /// </summary> | ||
40 | public class TestLLUDPServer : LLUDPServer | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// The chunks of data to pass to the LLUDPServer when it calls EndReceive | ||
44 | /// </summary> | ||
45 | protected Queue<ChunkSenderTuple> m_chunksToLoad = new Queue<ChunkSenderTuple>(); | ||
46 | |||
47 | protected override void BeginReceive() | ||
48 | { | ||
49 | if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException) | ||
50 | { | ||
51 | ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); | ||
52 | reusedEpSender = tuple.Sender; | ||
53 | throw new SocketException(); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender) | ||
58 | { | ||
59 | numBytes = 0; | ||
60 | |||
61 | //m_log.Debug("Queue size " + m_chunksToLoad.Count); | ||
62 | |||
63 | if (m_chunksToLoad.Count <= 0) | ||
64 | return false; | ||
65 | |||
66 | ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); | ||
67 | RecvBuffer = tuple.Data; | ||
68 | numBytes = tuple.Data.Length; | ||
69 | epSender = tuple.Sender; | ||
70 | |||
71 | return true; | ||
72 | } | ||
73 | |||
74 | public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) | ||
75 | { | ||
76 | // Don't do anything just yet | ||
77 | } | ||
78 | |||
79 | /// <summary> | ||
80 | /// Signal that this chunk should throw an exception on Socket.BeginReceive() | ||
81 | /// </summary> | ||
82 | /// <param name="epSender"></param> | ||
83 | public void LoadReceiveWithBeginException(EndPoint epSender) | ||
84 | { | ||
85 | ChunkSenderTuple tuple = new ChunkSenderTuple(epSender); | ||
86 | tuple.BeginReceiveException = true; | ||
87 | m_chunksToLoad.Enqueue(tuple); | ||
88 | } | ||
89 | |||
90 | /// <summary> | ||
91 | /// Load some data to be received by the LLUDPServer on the next receive call | ||
92 | /// </summary> | ||
93 | /// <param name="data"></param> | ||
94 | /// <param name="epSender"></param> | ||
95 | public void LoadReceive(byte[] data, EndPoint epSender) | ||
96 | { | ||
97 | m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender)); | ||
98 | } | ||
99 | |||
100 | /// <summary> | ||
101 | /// Load a packet to be received by the LLUDPServer on the next receive call | ||
102 | /// </summary> | ||
103 | /// <param name="packet"></param> | ||
104 | public void LoadReceive(Packet packet, EndPoint epSender) | ||
105 | { | ||
106 | LoadReceive(packet.ToBytes(), epSender); | ||
107 | } | ||
108 | |||
109 | /// <summary> | ||
110 | /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send | ||
111 | /// </summary> | ||
112 | /// <param name="result"></param> | ||
113 | public void ReceiveData(IAsyncResult result) | ||
114 | { | ||
115 | while (m_chunksToLoad.Count > 0) | ||
116 | OnReceivedData(result); | ||
117 | } | ||
118 | |||
119 | /// <summary> | ||
120 | /// Has a circuit with the given code been established? | ||
121 | /// </summary> | ||
122 | /// <param name="circuitCode"></param> | ||
123 | /// <returns></returns> | ||
124 | public bool HasCircuit(uint circuitCode) | ||
125 | { | ||
126 | lock (clientCircuits_reverse) | ||
127 | { | ||
128 | return clientCircuits_reverse.ContainsKey(circuitCode); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /// <summary> | ||
134 | /// Record the data and sender tuple | ||
135 | /// </summary> | ||
136 | public class ChunkSenderTuple | ||
137 | { | ||
138 | public byte[] Data; | ||
139 | public EndPoint Sender; | ||
140 | public bool BeginReceiveException; | ||
141 | |||
142 | public ChunkSenderTuple(byte[] data, EndPoint sender) | ||
143 | { | ||
144 | Data = data; | ||
145 | Sender = sender; | ||
146 | } | ||
147 | |||
148 | public ChunkSenderTuple(EndPoint sender) | ||
149 | { | ||
150 | Sender = sender; | ||
151 | } | ||
152 | } | ||
153 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs new file mode 100644 index 0000000..c9aac0b --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs | |||
@@ -0,0 +1,111 @@ | |||
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 OpenSim.Framework; | ||
30 | using Nini.Config; | ||
31 | |||
32 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
33 | { | ||
34 | /// <summary> | ||
35 | /// Holds drip rates and maximum burst rates for throttling with hierarchical | ||
36 | /// token buckets. The maximum burst rates set here are hard limits and can | ||
37 | /// not be overridden by client requests | ||
38 | /// </summary> | ||
39 | public sealed class ThrottleRates | ||
40 | { | ||
41 | /// <summary>Drip rate for resent packets</summary> | ||
42 | public int Resend; | ||
43 | /// <summary>Drip rate for terrain packets</summary> | ||
44 | public int Land; | ||
45 | /// <summary>Drip rate for wind packets</summary> | ||
46 | public int Wind; | ||
47 | /// <summary>Drip rate for cloud packets</summary> | ||
48 | public int Cloud; | ||
49 | /// <summary>Drip rate for task packets</summary> | ||
50 | public int Task; | ||
51 | /// <summary>Drip rate for texture packets</summary> | ||
52 | public int Texture; | ||
53 | /// <summary>Drip rate for asset packets</summary> | ||
54 | public int Asset; | ||
55 | |||
56 | /// <summary>Drip rate for the parent token bucket</summary> | ||
57 | public int Total; | ||
58 | |||
59 | /// <summary>Flag used to enable adaptive throttles</summary> | ||
60 | public bool AdaptiveThrottlesEnabled; | ||
61 | |||
62 | /// <summary> | ||
63 | /// Default constructor | ||
64 | /// </summary> | ||
65 | /// <param name="config">Config source to load defaults from</param> | ||
66 | public ThrottleRates(IConfigSource config) | ||
67 | { | ||
68 | try | ||
69 | { | ||
70 | IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; | ||
71 | |||
72 | Resend = throttleConfig.GetInt("resend_default", 6625); | ||
73 | Land = throttleConfig.GetInt("land_default", 9125); | ||
74 | Wind = throttleConfig.GetInt("wind_default", 1750); | ||
75 | Cloud = throttleConfig.GetInt("cloud_default", 1750); | ||
76 | Task = throttleConfig.GetInt("task_default", 18500); | ||
77 | Texture = throttleConfig.GetInt("texture_default", 18500); | ||
78 | Asset = throttleConfig.GetInt("asset_default", 10500); | ||
79 | |||
80 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); | ||
81 | |||
82 | AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); | ||
83 | } | ||
84 | catch (Exception) { } | ||
85 | } | ||
86 | |||
87 | public int GetRate(ThrottleOutPacketType type) | ||
88 | { | ||
89 | switch (type) | ||
90 | { | ||
91 | case ThrottleOutPacketType.Resend: | ||
92 | return Resend; | ||
93 | case ThrottleOutPacketType.Land: | ||
94 | return Land; | ||
95 | case ThrottleOutPacketType.Wind: | ||
96 | return Wind; | ||
97 | case ThrottleOutPacketType.Cloud: | ||
98 | return Cloud; | ||
99 | case ThrottleOutPacketType.Task: | ||
100 | return Task; | ||
101 | case ThrottleOutPacketType.Texture: | ||
102 | return Texture; | ||
103 | case ThrottleOutPacketType.Asset: | ||
104 | return Asset; | ||
105 | case ThrottleOutPacketType.Unknown: | ||
106 | default: | ||
107 | return 0; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs new file mode 100644 index 0000000..29fd1a4 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | |||
@@ -0,0 +1,393 @@ | |||
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.Generic; | ||
31 | using System.Reflection; | ||
32 | using OpenSim.Framework; | ||
33 | |||
34 | using log4net; | ||
35 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// A hierarchical token bucket for bandwidth throttling. See | ||
40 | /// http://en.wikipedia.org/wiki/Token_bucket for more information | ||
41 | /// </summary> | ||
42 | public class TokenBucket | ||
43 | { | ||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
45 | private static Int32 m_counter = 0; | ||
46 | |||
47 | private Int32 m_identifier; | ||
48 | |||
49 | /// <summary> | ||
50 | /// Number of ticks (ms) per quantum, drip rate and max burst | ||
51 | /// are defined over this interval. | ||
52 | /// </summary> | ||
53 | protected const Int32 m_ticksPerQuantum = 1000; | ||
54 | |||
55 | /// <summary> | ||
56 | /// This is the number of quantums worth of packets that can | ||
57 | /// be accommodated during a burst | ||
58 | /// </summary> | ||
59 | protected const Double m_quantumsPerBurst = 1.5; | ||
60 | |||
61 | /// <summary> | ||
62 | /// </summary> | ||
63 | protected const Int32 m_minimumDripRate = 1400; | ||
64 | |||
65 | /// <summary>Time of the last drip, in system ticks</summary> | ||
66 | protected Int32 m_lastDrip; | ||
67 | |||
68 | /// <summary> | ||
69 | /// The number of bytes that can be sent at this moment. This is the | ||
70 | /// current number of tokens in the bucket | ||
71 | /// </summary> | ||
72 | protected Int64 m_tokenCount; | ||
73 | |||
74 | /// <summary> | ||
75 | /// Map of children buckets and their requested maximum burst rate | ||
76 | /// </summary> | ||
77 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | ||
78 | |||
79 | #region Properties | ||
80 | |||
81 | /// <summary> | ||
82 | /// The parent bucket of this bucket, or null if this bucket has no | ||
83 | /// parent. The parent bucket will limit the aggregate bandwidth of all | ||
84 | /// of its children buckets | ||
85 | /// </summary> | ||
86 | protected TokenBucket m_parent; | ||
87 | public TokenBucket Parent | ||
88 | { | ||
89 | get { return m_parent; } | ||
90 | set { m_parent = value; } | ||
91 | } | ||
92 | |||
93 | /// <summary> | ||
94 | /// Maximum burst rate in bytes per second. This is the maximum number | ||
95 | /// of tokens that can accumulate in the bucket at any one time. This | ||
96 | /// also sets the total request for leaf nodes | ||
97 | /// </summary> | ||
98 | protected Int64 m_burstRate; | ||
99 | public Int64 RequestedBurstRate | ||
100 | { | ||
101 | get { return m_burstRate; } | ||
102 | set { m_burstRate = (value < 0 ? 0 : value); } | ||
103 | } | ||
104 | |||
105 | public Int64 BurstRate | ||
106 | { | ||
107 | get { | ||
108 | double rate = RequestedBurstRate * BurstRateModifier(); | ||
109 | if (rate < m_minimumDripRate * m_quantumsPerBurst) | ||
110 | rate = m_minimumDripRate * m_quantumsPerBurst; | ||
111 | |||
112 | return (Int64) rate; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /// <summary> | ||
117 | /// The speed limit of this bucket in bytes per second. This is the | ||
118 | /// number of tokens that are added to the bucket per quantum | ||
119 | /// </summary> | ||
120 | /// <remarks>Tokens are added to the bucket any time | ||
121 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | ||
122 | /// the system tick interval (typically around 15-22ms)</remarks> | ||
123 | protected Int64 m_dripRate; | ||
124 | public virtual Int64 RequestedDripRate | ||
125 | { | ||
126 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } | ||
127 | set { | ||
128 | m_dripRate = (value < 0 ? 0 : value); | ||
129 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | ||
130 | m_totalDripRequest = m_dripRate; | ||
131 | if (m_parent != null) | ||
132 | m_parent.RegisterRequest(this,m_dripRate); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | public virtual Int64 DripRate | ||
137 | { | ||
138 | get { | ||
139 | if (m_parent == null) | ||
140 | return Math.Min(RequestedDripRate,TotalDripRequest); | ||
141 | |||
142 | double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); | ||
143 | if (rate < m_minimumDripRate) | ||
144 | rate = m_minimumDripRate; | ||
145 | |||
146 | return (Int64)rate; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /// <summary> | ||
151 | /// The current total of the requested maximum burst rates of | ||
152 | /// this bucket's children buckets. | ||
153 | /// </summary> | ||
154 | protected Int64 m_totalDripRequest; | ||
155 | public Int64 TotalDripRequest | ||
156 | { | ||
157 | get { return m_totalDripRequest; } | ||
158 | set { m_totalDripRequest = value; } | ||
159 | } | ||
160 | |||
161 | #endregion Properties | ||
162 | |||
163 | #region Constructor | ||
164 | |||
165 | /// <summary> | ||
166 | /// Default constructor | ||
167 | /// </summary> | ||
168 | /// <param name="parent">Parent bucket if this is a child bucket, or | ||
169 | /// null if this is a root bucket</param> | ||
170 | /// <param name="maxBurst">Maximum size of the bucket in bytes, or | ||
171 | /// zero if this bucket has no maximum capacity</param> | ||
172 | /// <param name="dripRate">Rate that the bucket fills, in bytes per | ||
173 | /// second. If zero, the bucket always remains full</param> | ||
174 | public TokenBucket(TokenBucket parent, Int64 dripRate) | ||
175 | { | ||
176 | m_identifier = m_counter++; | ||
177 | |||
178 | Parent = parent; | ||
179 | RequestedDripRate = dripRate; | ||
180 | // TotalDripRequest = dripRate; // this will be overwritten when a child node registers | ||
181 | // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); | ||
182 | m_lastDrip = Util.EnvironmentTickCount(); | ||
183 | } | ||
184 | |||
185 | #endregion Constructor | ||
186 | |||
187 | /// <summary> | ||
188 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning | ||
189 | /// no modification if the requested bandwidth is less than the | ||
190 | /// max burst bandwidth all the way to the root of the throttle | ||
191 | /// hierarchy. However, if any of the parents is over-booked, then | ||
192 | /// the modifier will be less than 1. | ||
193 | /// </summary> | ||
194 | protected double DripRateModifier() | ||
195 | { | ||
196 | Int64 driprate = DripRate; | ||
197 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | ||
198 | } | ||
199 | |||
200 | /// <summary> | ||
201 | /// </summary> | ||
202 | protected double BurstRateModifier() | ||
203 | { | ||
204 | // for now... burst rate is always m_quantumsPerBurst (constant) | ||
205 | // larger than drip rate so the ratio of burst requests is the | ||
206 | // same as the drip ratio | ||
207 | return DripRateModifier(); | ||
208 | } | ||
209 | |||
210 | /// <summary> | ||
211 | /// Register drip rate requested by a child of this throttle. Pass the | ||
212 | /// changes up the hierarchy. | ||
213 | /// </summary> | ||
214 | public void RegisterRequest(TokenBucket child, Int64 request) | ||
215 | { | ||
216 | lock (m_children) | ||
217 | { | ||
218 | m_children[child] = request; | ||
219 | // m_totalDripRequest = m_children.Values.Sum(); | ||
220 | |||
221 | m_totalDripRequest = 0; | ||
222 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | ||
223 | m_totalDripRequest += cref.Value; | ||
224 | } | ||
225 | |||
226 | // Pass the new values up to the parent | ||
227 | if (m_parent != null) | ||
228 | m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | ||
229 | } | ||
230 | |||
231 | /// <summary> | ||
232 | /// Remove the rate requested by a child of this throttle. Pass the | ||
233 | /// changes up the hierarchy. | ||
234 | /// </summary> | ||
235 | public void UnregisterRequest(TokenBucket child) | ||
236 | { | ||
237 | lock (m_children) | ||
238 | { | ||
239 | m_children.Remove(child); | ||
240 | // m_totalDripRequest = m_children.Values.Sum(); | ||
241 | |||
242 | m_totalDripRequest = 0; | ||
243 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | ||
244 | m_totalDripRequest += cref.Value; | ||
245 | } | ||
246 | |||
247 | |||
248 | // Pass the new values up to the parent | ||
249 | if (m_parent != null) | ||
250 | m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | ||
251 | } | ||
252 | |||
253 | /// <summary> | ||
254 | /// Remove a given number of tokens from the bucket | ||
255 | /// </summary> | ||
256 | /// <param name="amount">Number of tokens to remove from the bucket</param> | ||
257 | /// <returns>True if the requested number of tokens were removed from | ||
258 | /// the bucket, otherwise false</returns> | ||
259 | public bool RemoveTokens(Int64 amount) | ||
260 | { | ||
261 | // Deposit tokens for this interval | ||
262 | Drip(); | ||
263 | |||
264 | // If we have enough tokens then remove them and return | ||
265 | if (m_tokenCount - amount >= 0) | ||
266 | { | ||
267 | // we don't have to remove from the parent, the drip rate is already | ||
268 | // reflective of the drip rate limits in the parent | ||
269 | m_tokenCount -= amount; | ||
270 | return true; | ||
271 | } | ||
272 | |||
273 | return false; | ||
274 | } | ||
275 | |||
276 | /// <summary> | ||
277 | /// Deposit tokens into the bucket from a child bucket that did | ||
278 | /// not use all of its available tokens | ||
279 | /// </summary> | ||
280 | protected void Deposit(Int64 count) | ||
281 | { | ||
282 | m_tokenCount += count; | ||
283 | |||
284 | // Deposit the overflow in the parent bucket, this is how we share | ||
285 | // unused bandwidth | ||
286 | Int64 burstrate = BurstRate; | ||
287 | if (m_tokenCount > burstrate) | ||
288 | m_tokenCount = burstrate; | ||
289 | } | ||
290 | |||
291 | /// <summary> | ||
292 | /// Add tokens to the bucket over time. The number of tokens added each | ||
293 | /// call depends on the length of time that has passed since the last | ||
294 | /// call to Drip | ||
295 | /// </summary> | ||
296 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> | ||
297 | protected void Drip() | ||
298 | { | ||
299 | // This should never happen... means we are a leaf node and were created | ||
300 | // with no drip rate... | ||
301 | if (DripRate == 0) | ||
302 | { | ||
303 | m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | // Determine the interval over which we are adding tokens, never add | ||
308 | // more than a single quantum of tokens | ||
309 | Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); | ||
310 | m_lastDrip = Util.EnvironmentTickCount(); | ||
311 | |||
312 | // This can be 0 in the very unusual case that the timer wrapped | ||
313 | // It can be 0 if we try add tokens at a sub-tick rate | ||
314 | if (deltaMS <= 0) | ||
315 | return; | ||
316 | |||
317 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | public class AdaptiveTokenBucket : TokenBucket | ||
322 | { | ||
323 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
324 | |||
325 | /// <summary> | ||
326 | /// The minimum rate for flow control. Minimum drip rate is one | ||
327 | /// packet per second. Open the throttle to 15 packets per second | ||
328 | /// or about 160kbps. | ||
329 | /// </summary> | ||
330 | protected const Int64 m_minimumFlow = m_minimumDripRate * 15; | ||
331 | |||
332 | // <summary> | ||
333 | // The maximum rate for flow control. Drip rate can never be | ||
334 | // greater than this. | ||
335 | // </summary> | ||
336 | protected Int64 m_maxDripRate = 0; | ||
337 | protected Int64 MaxDripRate | ||
338 | { | ||
339 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | ||
340 | set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } | ||
341 | } | ||
342 | |||
343 | private bool m_enabled = false; | ||
344 | |||
345 | // <summary> | ||
346 | // | ||
347 | // </summary> | ||
348 | public virtual Int64 AdjustedDripRate | ||
349 | { | ||
350 | get { return m_dripRate; } | ||
351 | set { | ||
352 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); | ||
353 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | ||
354 | if (m_parent != null) | ||
355 | m_parent.RegisterRequest(this,m_dripRate); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | // <summary> | ||
360 | // | ||
361 | // </summary> | ||
362 | public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate) | ||
363 | { | ||
364 | m_enabled = enabled; | ||
365 | |||
366 | if (m_enabled) | ||
367 | { | ||
368 | // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled"); | ||
369 | MaxDripRate = maxDripRate; | ||
370 | AdjustedDripRate = m_minimumFlow; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | // <summary> | ||
375 | // | ||
376 | // </summary> | ||
377 | public void ExpirePackets(Int32 count) | ||
378 | { | ||
379 | // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); | ||
380 | if (m_enabled) | ||
381 | AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count)); | ||
382 | } | ||
383 | |||
384 | // <summary> | ||
385 | // | ||
386 | // </summary> | ||
387 | public void AcknowledgePackets(Int32 count) | ||
388 | { | ||
389 | if (m_enabled) | ||
390 | AdjustedDripRate = AdjustedDripRate + count; | ||
391 | } | ||
392 | } | ||
393 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs new file mode 100644 index 0000000..793aefe --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs | |||
@@ -0,0 +1,219 @@ | |||
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.Generic; | ||
30 | using System.Net; | ||
31 | using System.Threading; | ||
32 | using OpenMetaverse; | ||
33 | |||
34 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
35 | { | ||
36 | /// <summary> | ||
37 | /// Special collection that is optimized for tracking unacknowledged packets | ||
38 | /// </summary> | ||
39 | public sealed class UnackedPacketCollection | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// Holds information about a pending acknowledgement | ||
43 | /// </summary> | ||
44 | private struct PendingAck | ||
45 | { | ||
46 | /// <summary>Sequence number of the packet to remove</summary> | ||
47 | public uint SequenceNumber; | ||
48 | /// <summary>Environment.TickCount value when the remove was queued. | ||
49 | /// This is used to update round-trip times for packets</summary> | ||
50 | public int RemoveTime; | ||
51 | /// <summary>Whether or not this acknowledgement was attached to a | ||
52 | /// resent packet. If so, round-trip time will not be calculated</summary> | ||
53 | public bool FromResend; | ||
54 | |||
55 | public PendingAck(uint sequenceNumber, int currentTime, bool fromResend) | ||
56 | { | ||
57 | SequenceNumber = sequenceNumber; | ||
58 | RemoveTime = currentTime; | ||
59 | FromResend = fromResend; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary> | ||
64 | private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>(); | ||
65 | /// <summary>Holds packets that need to be added to the unacknowledged list</summary> | ||
66 | private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>(); | ||
67 | /// <summary>Holds information about pending acknowledgements</summary> | ||
68 | private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>(); | ||
69 | /// <summary>Holds information about pending removals</summary> | ||
70 | private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>(); | ||
71 | |||
72 | /// <summary> | ||
73 | /// Add an unacked packet to the collection | ||
74 | /// </summary> | ||
75 | /// <param name="packet">Packet that is awaiting acknowledgement</param> | ||
76 | /// <returns>True if the packet was successfully added, false if the | ||
77 | /// packet already existed in the collection</returns> | ||
78 | /// <remarks>This does not immediately add the ACK to the collection, | ||
79 | /// it only queues it so it can be added in a thread-safe way later</remarks> | ||
80 | public void Add(OutgoingPacket packet) | ||
81 | { | ||
82 | m_pendingAdds.Enqueue(packet); | ||
83 | Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength); | ||
84 | } | ||
85 | |||
86 | /// <summary> | ||
87 | /// Marks a packet as acknowledged | ||
88 | /// This method is used when an acknowledgement is received from the network for a previously | ||
89 | /// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT | ||
90 | /// and increase throttle to the coresponding client. | ||
91 | /// </summary> | ||
92 | /// <param name="sequenceNumber">Sequence number of the packet to | ||
93 | /// acknowledge</param> | ||
94 | /// <param name="currentTime">Current value of Environment.TickCount</param> | ||
95 | /// <remarks>This does not immediately acknowledge the packet, it only | ||
96 | /// queues the ack so it can be handled in a thread-safe way later</remarks> | ||
97 | public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend) | ||
98 | { | ||
99 | m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); | ||
100 | } | ||
101 | |||
102 | /// <summary> | ||
103 | /// Marks a packet as no longer needing acknowledgement without a received acknowledgement. | ||
104 | /// This method is called when a packet expires and we no longer need an acknowledgement. | ||
105 | /// When some reliable packet types expire, they are handled in a way other than simply | ||
106 | /// resending them. The only effect of removal this way is to update unacked byte count. | ||
107 | /// </summary> | ||
108 | /// <param name="sequenceNumber">Sequence number of the packet to | ||
109 | /// acknowledge</param> | ||
110 | /// <remarks>The does not immediately remove the packet, it only queues the removal | ||
111 | /// so it can be handled in a thread safe way later</remarks> | ||
112 | public void Remove(uint sequenceNumber) | ||
113 | { | ||
114 | m_pendingRemoves.Enqueue(sequenceNumber); | ||
115 | } | ||
116 | |||
117 | /// <summary> | ||
118 | /// Returns a list of all of the packets with a TickCount older than | ||
119 | /// the specified timeout | ||
120 | /// </summary> | ||
121 | /// <param name="timeoutMS">Number of ticks (milliseconds) before a | ||
122 | /// packet is considered expired</param> | ||
123 | /// <returns>A list of all expired packets according to the given | ||
124 | /// expiration timeout</returns> | ||
125 | /// <remarks>This function is not thread safe, and cannot be called | ||
126 | /// multiple times concurrently</remarks> | ||
127 | public List<OutgoingPacket> GetExpiredPackets(int timeoutMS) | ||
128 | { | ||
129 | ProcessQueues(); | ||
130 | |||
131 | List<OutgoingPacket> expiredPackets = null; | ||
132 | |||
133 | if (m_packets.Count > 0) | ||
134 | { | ||
135 | int now = Environment.TickCount & Int32.MaxValue; | ||
136 | |||
137 | foreach (OutgoingPacket packet in m_packets.Values) | ||
138 | { | ||
139 | // TickCount of zero means a packet is in the resend queue | ||
140 | // but hasn't actually been sent over the wire yet | ||
141 | if (packet.TickCount == 0) | ||
142 | continue; | ||
143 | |||
144 | if (now - packet.TickCount >= timeoutMS) | ||
145 | { | ||
146 | if (expiredPackets == null) | ||
147 | expiredPackets = new List<OutgoingPacket>(); | ||
148 | |||
149 | // The TickCount will be set to the current time when the packet | ||
150 | // is actually sent out again | ||
151 | packet.TickCount = 0; | ||
152 | |||
153 | // As with other network applications, assume that an expired packet is | ||
154 | // an indication of some network problem, slow transmission | ||
155 | packet.Client.FlowThrottle.ExpirePackets(1); | ||
156 | |||
157 | expiredPackets.Add(packet); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | return expiredPackets; | ||
163 | } | ||
164 | |||
165 | private void ProcessQueues() | ||
166 | { | ||
167 | // Process all the pending adds | ||
168 | OutgoingPacket pendingAdd; | ||
169 | while (m_pendingAdds.TryDequeue(out pendingAdd)) | ||
170 | if (pendingAdd != null) | ||
171 | m_packets[pendingAdd.SequenceNumber] = pendingAdd; | ||
172 | |||
173 | // Process all the pending removes, including updating statistics and round-trip times | ||
174 | PendingAck pendingAcknowledgement; | ||
175 | while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement)) | ||
176 | { | ||
177 | OutgoingPacket ackedPacket; | ||
178 | if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket)) | ||
179 | { | ||
180 | if (ackedPacket != null) | ||
181 | { | ||
182 | m_packets.Remove(pendingAcknowledgement.SequenceNumber); | ||
183 | |||
184 | // As with other network applications, assume that an acknowledged packet is an | ||
185 | // indication that the network can handle a little more load, speed up the transmission | ||
186 | ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength); | ||
187 | |||
188 | // Update stats | ||
189 | Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); | ||
190 | |||
191 | if (!pendingAcknowledgement.FromResend) | ||
192 | { | ||
193 | // Calculate the round-trip time for this packet and its ACK | ||
194 | int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount; | ||
195 | if (rtt > 0) | ||
196 | ackedPacket.Client.UpdateRoundTrip(rtt); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | uint pendingRemove; | ||
203 | while(m_pendingRemoves.TryDequeue(out pendingRemove)) | ||
204 | { | ||
205 | OutgoingPacket removedPacket; | ||
206 | if (m_packets.TryGetValue(pendingRemove, out removedPacket)) | ||
207 | { | ||
208 | if (removedPacket != null) | ||
209 | { | ||
210 | m_packets.Remove(pendingRemove); | ||
211 | |||
212 | // Update stats | ||
213 | Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | } | ||