ParcelManager.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. /*
  2. * Copyright (c) Contributors, http://www.openmetaverse.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 OpenSim 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 libsecondlife;
  31. using libsecondlife.Packets;
  32. using OpenSim.Framework.Interfaces;
  33. using OpenSim.Framework.Types;
  34. using OpenSim.Region.Environment.Scenes;
  35. using Avatar = OpenSim.Region.Environment.Scenes.ScenePresence;
  36. using System.IO;
  37. namespace OpenSim.Region.Environment
  38. {
  39. #region ParcelManager Class
  40. /// <summary>
  41. /// Handles Parcel objects and operations requiring information from other Parcel objects (divide, join, etc)
  42. /// </summary>
  43. public class ParcelManager : ILocalStorageParcelReceiver
  44. {
  45. #region Constants
  46. //Parcel types set with flags in ParcelOverlay.
  47. //Only one of these can be used.
  48. public const byte PARCEL_TYPE_PUBLIC = (byte)0; //Equals 00000000
  49. public const byte PARCEL_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
  50. public const byte PARCEL_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
  51. public const byte PARCEL_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
  52. public const byte PARCEL_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
  53. public const byte PARCEL_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
  54. //Flags that when set, a border on the given side will be placed
  55. //NOTE: North and East is assumable by the west and south sides (if parcel to east has a west border, then I have an east border; etc)
  56. //This took forever to figure out -- jeesh. /blame LL for even having to send these
  57. public const byte PARCEL_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
  58. public const byte PARCEL_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
  59. //RequestResults (I think these are right, they seem to work):
  60. public const int PARCEL_RESULT_ONE_PARCEL = 0; // The request they made contained only one parcel
  61. public const int PARCEL_RESULT_MULTIPLE_PARCELS = 1; // The request they made contained more than one parcel
  62. //ParcelSelectObjects
  63. public const int PARCEL_SELECT_OBJECTS_OWNER = 2;
  64. public const int PARCEL_SELECT_OBJECTS_GROUP = 4;
  65. public const int PARCEL_SELECT_OBJECTS_OTHER = 8;
  66. //These are other constants. Yay!
  67. public const int START_PARCEL_LOCAL_ID = 1;
  68. #endregion
  69. #region Member Variables
  70. public Dictionary<int, Parcel> parcelList = new Dictionary<int, Parcel>();
  71. private int lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
  72. private int[,] parcelIDList = new int[64, 64];
  73. /// <summary>
  74. /// Set to true when a prim is moved, created, added. Performs a prim count update
  75. /// </summary>
  76. public bool parcelPrimCountTainted = false;
  77. private Scene m_world;
  78. private RegionInfo m_regInfo;
  79. #endregion
  80. #region Constructors
  81. public ParcelManager(Scene world, RegionInfo reginfo)
  82. {
  83. m_world = world;
  84. m_regInfo = reginfo;
  85. parcelIDList.Initialize();
  86. }
  87. #endregion
  88. #region Member Functions
  89. #region Parcel From Storage Functions
  90. public void ParcelFromStorage(ParcelData data)
  91. {
  92. Parcel new_parcel = new Parcel(data.ownerID, data.isGroupOwned, m_world);
  93. new_parcel.parcelData = data.Copy();
  94. new_parcel.setParcelBitmapFromByteArray();
  95. addParcel(new_parcel);
  96. }
  97. public void NoParcelDataFromStorage()
  98. {
  99. resetSimParcels();
  100. }
  101. #endregion
  102. #region Parcel Add/Remove/Get/Create
  103. /// <summary>
  104. /// Creates a basic Parcel object without an owner (a zeroed key)
  105. /// </summary>
  106. /// <returns></returns>
  107. public Parcel createBaseParcel()
  108. {
  109. return new Parcel(new LLUUID(), false, m_world);
  110. }
  111. /// <summary>
  112. /// Adds a parcel to the stored list and adds them to the parcelIDList to what they own
  113. /// </summary>
  114. /// <param name="new_parcel">The parcel being added</param>
  115. public Parcel addParcel(Parcel new_parcel)
  116. {
  117. lastParcelLocalID++;
  118. new_parcel.parcelData.localID = lastParcelLocalID;
  119. parcelList.Add(lastParcelLocalID, new_parcel.Copy());
  120. bool[,] parcelBitmap = new_parcel.getParcelBitmap();
  121. int x, y;
  122. for (x = 0; x < 64; x++)
  123. {
  124. for (y = 0; y < 64; y++)
  125. {
  126. if (parcelBitmap[x, y])
  127. {
  128. parcelIDList[x, y] = lastParcelLocalID;
  129. }
  130. }
  131. }
  132. parcelList[lastParcelLocalID].forceUpdateParcelInfo();
  133. return new_parcel;
  134. }
  135. /// <summary>
  136. /// Removes a parcel from the list. Will not remove if local_id is still owning an area in parcelIDList
  137. /// </summary>
  138. /// <param name="local_id">Parcel.localID of the parcel to remove.</param>
  139. public void removeParcel(int local_id)
  140. {
  141. int x, y;
  142. for (x = 0; x < 64; x++)
  143. {
  144. for (y = 0; y < 64; y++)
  145. {
  146. if (parcelIDList[x, y] == local_id)
  147. {
  148. throw new Exception("Could not remove parcel. Still being used at " + x + ", " + y);
  149. }
  150. }
  151. }
  152. m_world.localStorage.RemoveParcel(parcelList[local_id].parcelData);
  153. parcelList.Remove(local_id);
  154. }
  155. private void performFinalParcelJoin(Parcel master, Parcel slave)
  156. {
  157. int x, y;
  158. bool[,] parcelBitmapSlave = slave.getParcelBitmap();
  159. for (x = 0; x < 64; x++)
  160. {
  161. for (y = 0; y < 64; y++)
  162. {
  163. if (parcelBitmapSlave[x, y])
  164. {
  165. parcelIDList[x, y] = master.parcelData.localID;
  166. }
  167. }
  168. }
  169. removeParcel(slave.parcelData.localID);
  170. }
  171. /// <summary>
  172. /// Get the parcel at the specified point
  173. /// </summary>
  174. /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
  175. /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
  176. /// <returns>Parcel at the point supplied</returns>
  177. public Parcel getParcel(float x_float, float y_float)
  178. {
  179. int x = Convert.ToInt32(Math.Floor(Convert.ToDecimal(x_float) / Convert.ToDecimal(4.0)));
  180. int y = Convert.ToInt32(Math.Floor(Convert.ToDecimal(y_float) / Convert.ToDecimal(4.0)));
  181. if (x > 63 || y > 63 || x < 0 || y < 0)
  182. {
  183. throw new Exception("Error: Parcel not found at point " + x + ", " + y);
  184. }
  185. else
  186. {
  187. // Console.WriteLine("Point (" + x + ", " + y + ") determined from point (" + x_float + ", " + y_float + ")");
  188. return parcelList[parcelIDList[x, y]];
  189. }
  190. }
  191. public Parcel getParcel(int x, int y)
  192. {
  193. if (x > 256 || y > 256 || x < 0 || y < 0)
  194. {
  195. throw new Exception("Error: Parcel not found at point " + x + ", " + y);
  196. }
  197. else
  198. {
  199. return parcelList[parcelIDList[x / 4, y / 4]];
  200. }
  201. }
  202. #endregion
  203. #region Parcel Modification
  204. /// <summary>
  205. /// Subdivides a parcel
  206. /// </summary>
  207. /// <param name="start_x">West Point</param>
  208. /// <param name="start_y">South Point</param>
  209. /// <param name="end_x">East Point</param>
  210. /// <param name="end_y">North Point</param>
  211. /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
  212. /// <returns>Returns true if successful</returns>
  213. private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
  214. {
  215. //First, lets loop through the points and make sure they are all in the same parcel
  216. //Get the parcel at start
  217. Parcel startParcel = getParcel(start_x, start_y);
  218. if (startParcel == null) return false; //No such parcel at the beginning
  219. //Loop through the points
  220. try
  221. {
  222. int totalX = end_x - start_x;
  223. int totalY = end_y - start_y;
  224. int x, y;
  225. for (y = 0; y < totalY; y++)
  226. {
  227. for (x = 0; x < totalX; x++)
  228. {
  229. Parcel tempParcel = getParcel(start_x + x, start_y + y);
  230. if (tempParcel == null) return false; //No such parcel at that point
  231. if (tempParcel != startParcel) return false; //Subdividing over 2 parcels; no-no
  232. }
  233. }
  234. }
  235. catch (Exception)
  236. {
  237. return false; //Exception. For now, lets skip subdivision
  238. }
  239. //If we are still here, then they are subdividing within one parcel
  240. //Check owner
  241. if (startParcel.parcelData.ownerID != attempting_user_id)
  242. {
  243. return false; //They cant do this!
  244. }
  245. //Lets create a new parcel with bitmap activated at that point (keeping the old parcels info)
  246. Parcel newParcel = startParcel.Copy();
  247. newParcel.parcelData.parcelName = "Subdivision of " + newParcel.parcelData.parcelName;
  248. newParcel.parcelData.globalID = LLUUID.Random();
  249. newParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(start_x, start_y, end_x, end_y));
  250. //Now, lets set the subdivision area of the original to false
  251. int startParcelIndex = startParcel.parcelData.localID;
  252. parcelList[startParcelIndex].setParcelBitmap(Parcel.modifyParcelBitmapSquare(startParcel.getParcelBitmap(), start_x, start_y, end_x, end_y, false));
  253. parcelList[startParcelIndex].forceUpdateParcelInfo();
  254. this.setPrimsTainted();
  255. //Now add the new parcel
  256. Parcel result = addParcel(newParcel);
  257. result.sendParcelUpdateToAvatarsOverMe();
  258. return true;
  259. }
  260. /// <summary>
  261. /// Join 2 parcels together
  262. /// </summary>
  263. /// <param name="start_x">x value in first parcel</param>
  264. /// <param name="start_y">y value in first parcel</param>
  265. /// <param name="end_x">x value in second parcel</param>
  266. /// <param name="end_y">y value in second parcel</param>
  267. /// <param name="attempting_user_id">LLUUID of the avatar trying to join the parcels</param>
  268. /// <returns>Returns true if successful</returns>
  269. private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
  270. {
  271. end_x -= 4;
  272. end_y -= 4;
  273. List<Parcel> selectedParcels = new List<Parcel>();
  274. int stepXSelected = 0;
  275. int stepYSelected = 0;
  276. for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
  277. {
  278. for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
  279. {
  280. Parcel p = getParcel(stepXSelected,stepYSelected);
  281. if (!selectedParcels.Contains(p))
  282. {
  283. selectedParcels.Add(p);
  284. }
  285. }
  286. }
  287. Parcel masterParcel = selectedParcels[0];
  288. selectedParcels.RemoveAt(0);
  289. if (selectedParcels.Count < 1)
  290. {
  291. return false; //Only one parcel selected
  292. }
  293. if (masterParcel.parcelData.ownerID != attempting_user_id)
  294. {
  295. return false; //Not the same owner
  296. }
  297. foreach (Parcel p in selectedParcels)
  298. {
  299. if (p.parcelData.ownerID != masterParcel.parcelData.ownerID)
  300. {
  301. return false; //Over multiple users. TODO: make this just ignore this parcel?
  302. }
  303. }
  304. foreach (Parcel slaveParcel in selectedParcels)
  305. {
  306. parcelList[masterParcel.parcelData.localID].setParcelBitmap(Parcel.mergeParcelBitmaps(masterParcel.getParcelBitmap(), slaveParcel.getParcelBitmap()));
  307. performFinalParcelJoin(masterParcel, slaveParcel);
  308. }
  309. this.setPrimsTainted();
  310. masterParcel.sendParcelUpdateToAvatarsOverMe();
  311. return true;
  312. }
  313. #endregion
  314. #region Parcel Updating
  315. /// <summary>
  316. /// Where we send the ParcelOverlay packet to the client
  317. /// </summary>
  318. /// <param name="remote_client">The object representing the client</param>
  319. public void sendParcelOverlay(IClientAPI remote_client)
  320. {
  321. const int PARCEL_BLOCKS_PER_PACKET = 1024;
  322. int x, y = 0;
  323. byte[] byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
  324. int byteArrayCount = 0;
  325. int sequenceID = 0;
  326. ParcelOverlayPacket packet;
  327. for (y = 0; y < 64; y++)
  328. {
  329. for (x = 0; x < 64; x++)
  330. {
  331. byte tempByte = (byte)0; //This represents the byte for the current 4x4
  332. Parcel currentParcelBlock = getParcel(x * 4, y * 4);
  333. if (currentParcelBlock.parcelData.ownerID == remote_client.AgentId)
  334. {
  335. //Owner Flag
  336. tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_REQUESTER);
  337. }
  338. else if (currentParcelBlock.parcelData.salePrice > 0 && (currentParcelBlock.parcelData.authBuyerID == LLUUID.Zero || currentParcelBlock.parcelData.authBuyerID == remote_client.AgentId))
  339. {
  340. //Sale Flag
  341. tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_IS_FOR_SALE);
  342. }
  343. else if (currentParcelBlock.parcelData.ownerID == LLUUID.Zero)
  344. {
  345. //Public Flag
  346. tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_PUBLIC);
  347. }
  348. else
  349. {
  350. //Other Flag
  351. tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_OTHER);
  352. }
  353. //Now for border control
  354. if (x == 0)
  355. {
  356. tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
  357. }
  358. else if (getParcel((x - 1) * 4, y * 4) != currentParcelBlock)
  359. {
  360. tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
  361. }
  362. if (y == 0)
  363. {
  364. tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
  365. }
  366. else if (getParcel(x * 4, (y - 1) * 4) != currentParcelBlock)
  367. {
  368. tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
  369. }
  370. byteArray[byteArrayCount] = tempByte;
  371. byteArrayCount++;
  372. if (byteArrayCount >= PARCEL_BLOCKS_PER_PACKET)
  373. {
  374. byteArrayCount = 0;
  375. packet = new ParcelOverlayPacket();
  376. packet.ParcelData.Data = byteArray;
  377. packet.ParcelData.SequenceID = sequenceID;
  378. remote_client.OutPacket((Packet)packet);
  379. sequenceID++;
  380. byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
  381. }
  382. }
  383. }
  384. }
  385. public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, bool snap_selection, IClientAPI remote_client)
  386. {
  387. //Get the parcels within the bounds
  388. List<Parcel> temp = new List<Parcel>();
  389. int x, y, i;
  390. int inc_x = end_x - start_x;
  391. int inc_y = end_y - start_y;
  392. for (x = 0; x < inc_x; x++)
  393. {
  394. for (y = 0; y < inc_y; y++)
  395. {
  396. Parcel currentParcel = getParcel(start_x + x, start_y + y);
  397. if (!temp.Contains(currentParcel))
  398. {
  399. currentParcel.forceUpdateParcelInfo();
  400. temp.Add(currentParcel);
  401. }
  402. }
  403. }
  404. int requestResult = PARCEL_RESULT_ONE_PARCEL;
  405. if (temp.Count > 1)
  406. {
  407. requestResult = PARCEL_RESULT_MULTIPLE_PARCELS;
  408. }
  409. for (i = 0; i < temp.Count; i++)
  410. {
  411. temp[i].sendParcelProperties(sequence_id, snap_selection, requestResult, remote_client);
  412. }
  413. sendParcelOverlay(remote_client);
  414. }
  415. public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
  416. {
  417. if (parcelList.ContainsKey(packet.ParcelData.LocalID))
  418. {
  419. parcelList[packet.ParcelData.LocalID].updateParcelProperties(packet, remote_client);
  420. }
  421. }
  422. public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
  423. {
  424. subdivide(west, south, east, north, remote_client.AgentId);
  425. }
  426. public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
  427. {
  428. join(west, south, east, north, remote_client.AgentId);
  429. }
  430. public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client)
  431. {
  432. parcelList[local_id].sendForceObjectSelect(local_id, request_type, remote_client);
  433. }
  434. public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
  435. {
  436. parcelList[local_id].sendParcelObjectOwners(remote_client);
  437. }
  438. #endregion
  439. /// <summary>
  440. /// Resets the sim to the default parcel (full sim parcel owned by the default user)
  441. /// </summary>
  442. public void resetSimParcels()
  443. {
  444. //Remove all the parcels in the sim and add a blank, full sim parcel set to public
  445. parcelList.Clear();
  446. lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
  447. parcelIDList.Initialize();
  448. Parcel fullSimParcel = new Parcel(LLUUID.Zero, false, m_world);
  449. fullSimParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(0, 0, 256, 256));
  450. fullSimParcel.parcelData.ownerID = m_regInfo.MasterAvatarAssignedUUID;
  451. addParcel(fullSimParcel);
  452. }
  453. public void handleSignificantClientMovement(IClientAPI remote_client)
  454. {
  455. Avatar clientAvatar = m_world.RequestAvatar(remote_client.AgentId);
  456. if (clientAvatar != null)
  457. {
  458. Parcel over = getParcel(clientAvatar.Pos.X,clientAvatar.Pos.Y);
  459. if (over != null)
  460. {
  461. over.sendParcelProperties(0, false, 0, remote_client);
  462. }
  463. }
  464. }
  465. public void resetAllParcelPrimCounts()
  466. {
  467. foreach (Parcel p in parcelList.Values)
  468. {
  469. p.resetParcelPrimCounts();
  470. }
  471. }
  472. public void setPrimsTainted()
  473. {
  474. this.parcelPrimCountTainted = true;
  475. }
  476. public void addPrimToParcelCounts(SceneObject obj)
  477. {
  478. LLVector3 position = obj.Pos;
  479. Parcel parcelUnderPrim = getParcel(position.X, position.Y);
  480. if (parcelUnderPrim != null)
  481. {
  482. parcelUnderPrim.addPrimToCount(obj);
  483. }
  484. }
  485. public void removePrimFromParcelCounts(SceneObject obj)
  486. {
  487. foreach (Parcel p in parcelList.Values)
  488. {
  489. p.removePrimFromCount(obj);
  490. }
  491. }
  492. public void finalizeParcelPrimCountUpdate()
  493. {
  494. //Get Simwide prim count for owner
  495. Dictionary<LLUUID, List<Parcel>> parcelOwnersAndParcels = new Dictionary<LLUUID,List<Parcel>>();
  496. foreach (Parcel p in parcelList.Values)
  497. {
  498. if(!parcelOwnersAndParcels.ContainsKey(p.parcelData.ownerID))
  499. {
  500. List<Parcel> tempList = new List<Parcel>();
  501. tempList.Add(p);
  502. parcelOwnersAndParcels.Add(p.parcelData.ownerID,tempList);
  503. }
  504. else
  505. {
  506. parcelOwnersAndParcels[p.parcelData.ownerID].Add(p);
  507. }
  508. }
  509. foreach (LLUUID owner in parcelOwnersAndParcels.Keys)
  510. {
  511. int simArea = 0;
  512. int simPrims = 0;
  513. foreach (Parcel p in parcelOwnersAndParcels[owner])
  514. {
  515. simArea += p.parcelData.area;
  516. simPrims += p.parcelData.ownerPrims + p.parcelData.otherPrims + p.parcelData.groupPrims + p.parcelData.selectedPrims;
  517. }
  518. foreach (Parcel p in parcelOwnersAndParcels[owner])
  519. {
  520. p.parcelData.simwideArea = simArea;
  521. p.parcelData.simwidePrims = simPrims;
  522. }
  523. }
  524. }
  525. #endregion
  526. }
  527. #endregion
  528. #region Parcel Class
  529. /// <summary>
  530. /// Keeps track of a specific parcel's information
  531. /// </summary>
  532. public class Parcel
  533. {
  534. #region Member Variables
  535. public ParcelData parcelData = new ParcelData();
  536. public List<SceneObject> primsOverMe = new List<SceneObject>();
  537. public Scene m_world;
  538. private bool[,] parcelBitmap = new bool[64, 64];
  539. #endregion
  540. #region Constructors
  541. public Parcel(LLUUID owner_id, bool is_group_owned, Scene world)
  542. {
  543. m_world = world;
  544. parcelData.ownerID = owner_id;
  545. parcelData.isGroupOwned = is_group_owned;
  546. }
  547. #endregion
  548. #region Member Functions
  549. #region General Functions
  550. /// <summary>
  551. /// Checks to see if this parcel contains a point
  552. /// </summary>
  553. /// <param name="x"></param>
  554. /// <param name="y"></param>
  555. /// <returns>Returns true if the parcel contains the specified point</returns>
  556. public bool containsPoint(int x, int y)
  557. {
  558. if (x >= 0 && y >= 0 && x <= 256 && x <= 256)
  559. {
  560. return (parcelBitmap[x / 4, y / 4] == true);
  561. }
  562. else
  563. {
  564. return false;
  565. }
  566. }
  567. public Parcel Copy()
  568. {
  569. Parcel newParcel = new Parcel(this.parcelData.ownerID, this.parcelData.isGroupOwned, m_world);
  570. //Place all new variables here!
  571. newParcel.parcelBitmap = (bool[,])(this.parcelBitmap.Clone());
  572. newParcel.parcelData = parcelData.Copy();
  573. return newParcel;
  574. }
  575. #endregion
  576. #region Packet Request Handling
  577. /// <summary>
  578. /// Sends parcel properties as requested
  579. /// </summary>
  580. /// <param name="sequence_id">ID sent by client for them to keep track of</param>
  581. /// <param name="snap_selection">Bool sent by client for them to use</param>
  582. /// <param name="remote_client">Object representing the client</param>
  583. public void sendParcelProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
  584. {
  585. ParcelPropertiesPacket updatePacket = new ParcelPropertiesPacket();
  586. updatePacket.ParcelData.AABBMax = parcelData.AABBMax;
  587. updatePacket.ParcelData.AABBMin = parcelData.AABBMin;
  588. updatePacket.ParcelData.Area = parcelData.area;
  589. updatePacket.ParcelData.AuctionID = parcelData.auctionID;
  590. updatePacket.ParcelData.AuthBuyerID = parcelData.authBuyerID; //unemplemented
  591. updatePacket.ParcelData.Bitmap = parcelData.parcelBitmapByteArray;
  592. updatePacket.ParcelData.Desc = Helpers.StringToField(parcelData.parcelDesc);
  593. updatePacket.ParcelData.Category = (byte)parcelData.category;
  594. updatePacket.ParcelData.ClaimDate = parcelData.claimDate;
  595. updatePacket.ParcelData.ClaimPrice = parcelData.claimPrice;
  596. updatePacket.ParcelData.GroupID = parcelData.groupID;
  597. updatePacket.ParcelData.GroupPrims = parcelData.groupPrims;
  598. updatePacket.ParcelData.IsGroupOwned = parcelData.isGroupOwned;
  599. updatePacket.ParcelData.LandingType = (byte)parcelData.landingType;
  600. updatePacket.ParcelData.LocalID = parcelData.localID;
  601. if (parcelData.area > 0)
  602. {
  603. updatePacket.ParcelData.MaxPrims = Convert.ToInt32(Math.Round((Convert.ToDecimal(parcelData.area) / Convert.ToDecimal(65536)) * 15000 * Convert.ToDecimal(m_world.RegionInfo.estateSettings.objectBonusFactor)));
  604. }
  605. else
  606. {
  607. updatePacket.ParcelData.MaxPrims = 0;
  608. }
  609. updatePacket.ParcelData.MediaAutoScale = parcelData.mediaAutoScale;
  610. updatePacket.ParcelData.MediaID = parcelData.mediaID;
  611. updatePacket.ParcelData.MediaURL = Helpers.StringToField(parcelData.mediaURL);
  612. updatePacket.ParcelData.MusicURL = Helpers.StringToField(parcelData.musicURL);
  613. updatePacket.ParcelData.Name = Helpers.StringToField(parcelData.parcelName);
  614. updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
  615. updatePacket.ParcelData.OtherCount = 0; //unemplemented
  616. updatePacket.ParcelData.OtherPrims = parcelData.otherPrims;
  617. updatePacket.ParcelData.OwnerID = parcelData.ownerID;
  618. updatePacket.ParcelData.OwnerPrims = parcelData.ownerPrims;
  619. updatePacket.ParcelData.ParcelFlags = parcelData.parcelFlags;
  620. updatePacket.ParcelData.ParcelPrimBonus = m_world.RegionInfo.estateSettings.objectBonusFactor;
  621. updatePacket.ParcelData.PassHours = parcelData.passHours;
  622. updatePacket.ParcelData.PassPrice = parcelData.passPrice;
  623. updatePacket.ParcelData.PublicCount = 0; //unemplemented
  624. updatePacket.ParcelData.RegionDenyAnonymous = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.DenyAnonymous) > 0);
  625. updatePacket.ParcelData.RegionDenyIdentified = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.DenyIdentified) > 0);
  626. updatePacket.ParcelData.RegionDenyTransacted = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.DenyTransacted) > 0);
  627. updatePacket.ParcelData.RegionPushOverride = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.RestrictPushObject) > 0);
  628. updatePacket.ParcelData.RentPrice = 0;
  629. updatePacket.ParcelData.RequestResult = request_result;
  630. updatePacket.ParcelData.SalePrice = parcelData.salePrice;
  631. updatePacket.ParcelData.SelectedPrims = parcelData.selectedPrims;
  632. updatePacket.ParcelData.SelfCount = 0;//unemplemented
  633. updatePacket.ParcelData.SequenceID = sequence_id;
  634. if (parcelData.simwideArea > 0)
  635. {
  636. updatePacket.ParcelData.SimWideMaxPrims = Convert.ToInt32(Math.Round((Convert.ToDecimal(parcelData.simwideArea) / Convert.ToDecimal(65536)) * 15000 * Convert.ToDecimal(m_world.RegionInfo.estateSettings.objectBonusFactor)));
  637. }
  638. else
  639. {
  640. updatePacket.ParcelData.SimWideMaxPrims = 0;
  641. }
  642. updatePacket.ParcelData.SimWideTotalPrims = parcelData.simwidePrims;
  643. updatePacket.ParcelData.SnapSelection = snap_selection;
  644. updatePacket.ParcelData.SnapshotID = parcelData.snapshotID;
  645. updatePacket.ParcelData.Status = (byte)parcelData.parcelStatus;
  646. updatePacket.ParcelData.TotalPrims = parcelData.ownerPrims + parcelData.groupPrims + parcelData.otherPrims + parcelData.selectedPrims;
  647. updatePacket.ParcelData.UserLocation = parcelData.userLocation;
  648. updatePacket.ParcelData.UserLookAt = parcelData.userLookAt;
  649. remote_client.OutPacket((Packet)updatePacket);
  650. }
  651. public void updateParcelProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
  652. {
  653. if (remote_client.AgentId == parcelData.ownerID)
  654. {
  655. //Needs later group support
  656. parcelData.authBuyerID = packet.ParcelData.AuthBuyerID;
  657. parcelData.category = (libsecondlife.Parcel.ParcelCategory)packet.ParcelData.Category;
  658. parcelData.parcelDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
  659. parcelData.groupID = packet.ParcelData.GroupID;
  660. parcelData.landingType = packet.ParcelData.LandingType;
  661. parcelData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
  662. parcelData.mediaID = packet.ParcelData.MediaID;
  663. parcelData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
  664. parcelData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
  665. parcelData.parcelName = Helpers.FieldToUTF8String(packet.ParcelData.Name);
  666. parcelData.parcelFlags = packet.ParcelData.ParcelFlags;
  667. parcelData.passHours = packet.ParcelData.PassHours;
  668. parcelData.passPrice = packet.ParcelData.PassPrice;
  669. parcelData.salePrice = packet.ParcelData.SalePrice;
  670. parcelData.snapshotID = packet.ParcelData.SnapshotID;
  671. parcelData.userLocation = packet.ParcelData.UserLocation;
  672. parcelData.userLookAt = packet.ParcelData.UserLookAt;
  673. sendParcelUpdateToAvatarsOverMe();
  674. }
  675. }
  676. public void sendParcelUpdateToAvatarsOverMe()
  677. {
  678. List<Avatar> avatars = m_world.RequestAvatarList();
  679. for (int i = 0; i < avatars.Count; i++)
  680. {
  681. Parcel over = m_world.ParcelManager.getParcel((int)Math.Round(avatars[i].Pos.X), (int)Math.Round(avatars[i].Pos.Y));
  682. if (over.parcelData.localID == this.parcelData.localID)
  683. {
  684. sendParcelProperties(0, false, 0, avatars[i].ControllingClient);
  685. }
  686. }
  687. }
  688. #endregion
  689. #region Update Functions
  690. /// <summary>
  691. /// Updates the AABBMin and AABBMax values after area/shape modification of parcel
  692. /// </summary>
  693. private void updateAABBAndAreaValues()
  694. {
  695. int min_x = 64;
  696. int min_y = 64;
  697. int max_x = 0;
  698. int max_y = 0;
  699. int tempArea = 0;
  700. int x, y;
  701. for (x = 0; x < 64; x++)
  702. {
  703. for (y = 0; y < 64; y++)
  704. {
  705. if (parcelBitmap[x, y] == true)
  706. {
  707. if (min_x > x) min_x = x;
  708. if (min_y > y) min_y = y;
  709. if (max_x < x) max_x = x;
  710. if (max_y < y) max_y = y;
  711. tempArea += 16; //16sqm parcel
  712. }
  713. }
  714. }
  715. parcelData.AABBMin = new LLVector3((float)(min_x * 4), (float)(min_y * 4), (float)m_world.Terrain.get((min_x * 4), (min_y * 4)));
  716. parcelData.AABBMax = new LLVector3((float)(max_x * 4), (float)(max_y * 4), (float)m_world.Terrain.get((max_x * 4), (max_y * 4)));
  717. parcelData.area = tempArea;
  718. }
  719. public void updateParcelBitmapByteArray()
  720. {
  721. parcelData.parcelBitmapByteArray = convertParcelBitmapToBytes();
  722. }
  723. /// <summary>
  724. /// Update all settings in parcel such as area, bitmap byte array, etc
  725. /// </summary>
  726. public void forceUpdateParcelInfo()
  727. {
  728. this.updateAABBAndAreaValues();
  729. this.updateParcelBitmapByteArray();
  730. }
  731. public void setParcelBitmapFromByteArray()
  732. {
  733. parcelBitmap = convertBytesToParcelBitmap();
  734. }
  735. #endregion
  736. #region Parcel Bitmap Functions
  737. /// <summary>
  738. /// Sets the parcel's bitmap manually
  739. /// </summary>
  740. /// <param name="bitmap">64x64 block representing where this parcel is on a map</param>
  741. public void setParcelBitmap(bool[,] bitmap)
  742. {
  743. if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
  744. {
  745. //Throw an exception - The bitmap is not 64x64
  746. throw new Exception("Error: Invalid Parcel Bitmap");
  747. }
  748. else
  749. {
  750. //Valid: Lets set it
  751. parcelBitmap = bitmap;
  752. forceUpdateParcelInfo();
  753. }
  754. }
  755. /// <summary>
  756. /// Gets the parcels bitmap manually
  757. /// </summary>
  758. /// <returns></returns>
  759. public bool[,] getParcelBitmap()
  760. {
  761. return parcelBitmap;
  762. }
  763. /// <summary>
  764. /// Converts the parcel bitmap to a packet friendly byte array
  765. /// </summary>
  766. /// <returns></returns>
  767. private byte[] convertParcelBitmapToBytes()
  768. {
  769. byte[] tempConvertArr = new byte[512];
  770. byte tempByte = 0;
  771. int x, y, i, byteNum = 0;
  772. i = 0;
  773. for (y = 0; y < 64; y++)
  774. {
  775. for (x = 0; x < 64; x++)
  776. {
  777. tempByte = Convert.ToByte(tempByte | Convert.ToByte(parcelBitmap[x, y]) << (i++ % 8));
  778. if (i % 8 == 0)
  779. {
  780. tempConvertArr[byteNum] = tempByte;
  781. tempByte = (byte)0;
  782. i = 0;
  783. byteNum++;
  784. }
  785. }
  786. }
  787. return tempConvertArr;
  788. }
  789. private bool[,] convertBytesToParcelBitmap()
  790. {
  791. bool[,] tempConvertMap = new bool[64, 64];
  792. tempConvertMap.Initialize();
  793. byte tempByte = 0;
  794. int x = 0, y = 0, i = 0, bitNum = 0;
  795. for (i = 0; i < 512; i++)
  796. {
  797. tempByte = parcelData.parcelBitmapByteArray[i];
  798. for (bitNum = 0; bitNum < 8; bitNum++)
  799. {
  800. bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte)1);
  801. tempConvertMap[x, y] = bit;
  802. x++;
  803. if (x > 63)
  804. {
  805. x = 0;
  806. y++;
  807. }
  808. }
  809. }
  810. return tempConvertMap;
  811. }
  812. /// <summary>
  813. /// Full sim parcel creation
  814. /// </summary>
  815. /// <returns></returns>
  816. public static bool[,] basicFullRegionParcelBitmap()
  817. {
  818. return getSquareParcelBitmap(0, 0, 256, 256);
  819. }
  820. /// <summary>
  821. /// Used to modify the bitmap between the x and y points. Points use 64 scale
  822. /// </summary>
  823. /// <param name="start_x"></param>
  824. /// <param name="start_y"></param>
  825. /// <param name="end_x"></param>
  826. /// <param name="end_y"></param>
  827. /// <returns></returns>
  828. public static bool[,] getSquareParcelBitmap(int start_x, int start_y, int end_x, int end_y)
  829. {
  830. bool[,] tempBitmap = new bool[64, 64];
  831. tempBitmap.Initialize();
  832. tempBitmap = modifyParcelBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
  833. return tempBitmap;
  834. }
  835. /// <summary>
  836. /// Change a parcel's bitmap at within a square and set those points to a specific value
  837. /// </summary>
  838. /// <param name="parcel_bitmap"></param>
  839. /// <param name="start_x"></param>
  840. /// <param name="start_y"></param>
  841. /// <param name="end_x"></param>
  842. /// <param name="end_y"></param>
  843. /// <param name="set_value"></param>
  844. /// <returns></returns>
  845. public static bool[,] modifyParcelBitmapSquare(bool[,] parcel_bitmap, int start_x, int start_y, int end_x, int end_y, bool set_value)
  846. {
  847. if (parcel_bitmap.GetLength(0) != 64 || parcel_bitmap.GetLength(1) != 64 || parcel_bitmap.Rank != 2)
  848. {
  849. //Throw an exception - The bitmap is not 64x64
  850. throw new Exception("Error: Invalid Parcel Bitmap in modifyParcelBitmapSquare()");
  851. }
  852. int x, y;
  853. for (y = 0; y < 64; y++)
  854. {
  855. for (x = 0; x < 64; x++)
  856. {
  857. if (x >= start_x / 4 && x < end_x / 4
  858. && y >= start_y / 4 && y < end_y / 4)
  859. {
  860. parcel_bitmap[x, y] = set_value;
  861. }
  862. }
  863. }
  864. return parcel_bitmap;
  865. }
  866. /// <summary>
  867. /// Join the true values of 2 bitmaps together
  868. /// </summary>
  869. /// <param name="bitmap_base"></param>
  870. /// <param name="bitmap_add"></param>
  871. /// <returns></returns>
  872. public static bool[,] mergeParcelBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
  873. {
  874. if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
  875. {
  876. //Throw an exception - The bitmap is not 64x64
  877. throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeParcelBitmaps");
  878. }
  879. if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
  880. {
  881. //Throw an exception - The bitmap is not 64x64
  882. throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeParcelBitmaps");
  883. }
  884. int x, y;
  885. for (y = 0; y < 64; y++)
  886. {
  887. for (x = 0; x < 64; x++)
  888. {
  889. if (bitmap_add[x, y])
  890. {
  891. bitmap_base[x, y] = true;
  892. }
  893. }
  894. }
  895. return bitmap_base;
  896. }
  897. #endregion
  898. #region Object Select and Object Owner Listing
  899. public void sendForceObjectSelect(int local_id, int request_type, IClientAPI remote_client)
  900. {
  901. List<uint> resultLocalIDs = new List<uint>();
  902. foreach (SceneObject obj in primsOverMe)
  903. {
  904. if (obj.rootLocalID > 0)
  905. {
  906. if (request_type == ParcelManager.PARCEL_SELECT_OBJECTS_OWNER && obj.rootPrimitive.OwnerID == this.parcelData.ownerID)
  907. {
  908. resultLocalIDs.Add(obj.rootLocalID);
  909. }
  910. else if (request_type == ParcelManager.PARCEL_SELECT_OBJECTS_GROUP && false) //TODO: change false to group support!
  911. {
  912. }
  913. else if (request_type == ParcelManager.PARCEL_SELECT_OBJECTS_OTHER && obj.rootPrimitive.OwnerID != remote_client.AgentId)
  914. {
  915. resultLocalIDs.Add(obj.rootLocalID);
  916. }
  917. }
  918. }
  919. bool firstCall = true;
  920. int MAX_OBJECTS_PER_PACKET = 251;
  921. ForceObjectSelectPacket pack = new ForceObjectSelectPacket();
  922. ForceObjectSelectPacket.DataBlock[] data;
  923. while (resultLocalIDs.Count > 0)
  924. {
  925. if (firstCall)
  926. {
  927. pack._Header.ResetList = true;
  928. firstCall = false;
  929. }
  930. else
  931. {
  932. pack._Header.ResetList = false;
  933. }
  934. if (resultLocalIDs.Count > MAX_OBJECTS_PER_PACKET)
  935. {
  936. data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
  937. }
  938. else
  939. {
  940. data = new ForceObjectSelectPacket.DataBlock[resultLocalIDs.Count];
  941. }
  942. int i;
  943. for (i = 0; i < MAX_OBJECTS_PER_PACKET && resultLocalIDs.Count > 0; i++)
  944. {
  945. data[i] = new ForceObjectSelectPacket.DataBlock();
  946. data[i].LocalID = Convert.ToUInt32(resultLocalIDs[0]);
  947. resultLocalIDs.RemoveAt(0);
  948. }
  949. pack.Data = data;
  950. remote_client.OutPacket((Packet)pack);
  951. }
  952. }
  953. public void sendParcelObjectOwners(IClientAPI remote_client)
  954. {
  955. Dictionary<LLUUID, int> ownersAndCount = new Dictionary<LLUUID,int>();
  956. foreach(SceneObject obj in primsOverMe)
  957. {
  958. if(!ownersAndCount.ContainsKey(obj.rootPrimitive.OwnerID))
  959. {
  960. ownersAndCount.Add(obj.rootPrimitive.OwnerID,0);
  961. }
  962. ownersAndCount[obj.rootPrimitive.OwnerID] += obj.primCount;
  963. }
  964. if (ownersAndCount.Count > 0)
  965. {
  966. ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[32];
  967. if(ownersAndCount.Count < 32)
  968. {
  969. dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[ownersAndCount.Count];
  970. }
  971. int num = 0;
  972. foreach (LLUUID owner in ownersAndCount.Keys)
  973. {
  974. dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
  975. dataBlock[num].Count = ownersAndCount[owner];
  976. dataBlock[num].IsGroupOwned = false; //TODO: fix me when group support is added
  977. dataBlock[num].OnlineStatus = true; //TODO: fix me later
  978. dataBlock[num].OwnerID = owner;
  979. num++;
  980. }
  981. ParcelObjectOwnersReplyPacket pack = new ParcelObjectOwnersReplyPacket();
  982. pack.Data = dataBlock;
  983. remote_client.OutPacket(pack);
  984. }
  985. }
  986. #endregion
  987. #region Object Returning
  988. public void returnObject(SceneObject obj)
  989. {
  990. }
  991. public void returnParcelObjects(int type, LLUUID owner)
  992. {
  993. }
  994. #endregion
  995. #region Object Adding/Removing from Parcel
  996. public void resetParcelPrimCounts()
  997. {
  998. parcelData.groupPrims = 0;
  999. parcelData.ownerPrims = 0;
  1000. parcelData.otherPrims = 0;
  1001. parcelData.selectedPrims = 0;
  1002. primsOverMe.Clear();
  1003. }
  1004. public void addPrimToCount(SceneObject obj)
  1005. {
  1006. LLUUID prim_owner = obj.rootPrimitive.OwnerID;
  1007. int prim_count = obj.primCount;
  1008. if (obj.isSelected)
  1009. {
  1010. parcelData.selectedPrims += prim_count;
  1011. }
  1012. else
  1013. {
  1014. if (prim_owner == parcelData.ownerID)
  1015. {
  1016. parcelData.ownerPrims += prim_count;
  1017. }
  1018. else
  1019. {
  1020. parcelData.otherPrims += prim_count;
  1021. }
  1022. }
  1023. primsOverMe.Add(obj);
  1024. }
  1025. public void removePrimFromCount(SceneObject obj)
  1026. {
  1027. if (primsOverMe.Contains(obj))
  1028. {
  1029. LLUUID prim_owner = obj.rootPrimitive.OwnerID;
  1030. int prim_count = obj.primCount;
  1031. if (prim_owner == parcelData.ownerID)
  1032. {
  1033. parcelData.ownerPrims -= prim_count;
  1034. }
  1035. else if (prim_owner == parcelData.groupID)
  1036. {
  1037. parcelData.groupPrims -= prim_count;
  1038. }
  1039. else
  1040. {
  1041. parcelData.otherPrims -= prim_count;
  1042. }
  1043. primsOverMe.Remove(obj);
  1044. }
  1045. }
  1046. #endregion
  1047. #endregion
  1048. }
  1049. #endregion
  1050. }