diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 238 |
1 files changed, 156 insertions, 82 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index f81c551..d4e3717 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -43,6 +43,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
43 | 43 | ||
44 | public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone); | 44 | public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone); |
45 | 45 | ||
46 | public delegate void AttachToBackupDelegate(SceneObjectGroup sog); | ||
47 | |||
48 | public delegate void DetachFromBackupDelegate(SceneObjectGroup sog); | ||
49 | |||
50 | public delegate void ChangedBackupDelegate(SceneObjectGroup sog); | ||
51 | |||
46 | public delegate void ObjectCreateDelegate(EntityBase obj); | 52 | public delegate void ObjectCreateDelegate(EntityBase obj); |
47 | 53 | ||
48 | public delegate void ObjectDeleteDelegate(EntityBase obj); | 54 | public delegate void ObjectDeleteDelegate(EntityBase obj); |
@@ -61,6 +67,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
61 | private PhysicsCrash handlerPhysicsCrash = null; | 67 | private PhysicsCrash handlerPhysicsCrash = null; |
62 | 68 | ||
63 | public event ObjectDuplicateDelegate OnObjectDuplicate; | 69 | public event ObjectDuplicateDelegate OnObjectDuplicate; |
70 | public event AttachToBackupDelegate OnAttachToBackup; | ||
71 | public event DetachFromBackupDelegate OnDetachFromBackup; | ||
72 | public event ChangedBackupDelegate OnChangeBackup; | ||
64 | public event ObjectCreateDelegate OnObjectCreate; | 73 | public event ObjectCreateDelegate OnObjectCreate; |
65 | public event ObjectDeleteDelegate OnObjectRemove; | 74 | public event ObjectDeleteDelegate OnObjectRemove; |
66 | 75 | ||
@@ -68,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
68 | 77 | ||
69 | #region Fields | 78 | #region Fields |
70 | 79 | ||
71 | protected object m_presenceLock = new object(); | 80 | protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim(); |
72 | protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); | 81 | protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); |
73 | protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); | 82 | protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); |
74 | 83 | ||
@@ -124,13 +133,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
124 | 133 | ||
125 | protected internal void Close() | 134 | protected internal void Close() |
126 | { | 135 | { |
127 | lock (m_presenceLock) | 136 | m_scenePresencesLock.EnterWriteLock(); |
137 | try | ||
128 | { | 138 | { |
129 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); | 139 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); |
130 | List<ScenePresence> newlist = new List<ScenePresence>(); | 140 | List<ScenePresence> newlist = new List<ScenePresence>(); |
131 | m_scenePresenceMap = newmap; | 141 | m_scenePresenceMap = newmap; |
132 | m_scenePresenceArray = newlist; | 142 | m_scenePresenceArray = newlist; |
133 | } | 143 | } |
144 | finally | ||
145 | { | ||
146 | m_scenePresencesLock.ExitWriteLock(); | ||
147 | } | ||
134 | 148 | ||
135 | lock (SceneObjectGroupsByFullID) | 149 | lock (SceneObjectGroupsByFullID) |
136 | SceneObjectGroupsByFullID.Clear(); | 150 | SceneObjectGroupsByFullID.Clear(); |
@@ -209,27 +223,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
209 | if (sp.IsChildAgent) | 223 | if (sp.IsChildAgent) |
210 | return; | 224 | return; |
211 | 225 | ||
212 | if (sp.ParentID != 0) | 226 | coarseLocations.Add(sp.AbsolutePosition); |
213 | { | 227 | avatarUUIDs.Add(sp.UUID); |
214 | // sitting avatar | ||
215 | SceneObjectPart sop = m_parentScene.GetSceneObjectPart(sp.ParentID); | ||
216 | if (sop != null) | ||
217 | { | ||
218 | coarseLocations.Add(sop.AbsolutePosition + sp.AbsolutePosition); | ||
219 | avatarUUIDs.Add(sp.UUID); | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | // we can't find the parent.. ! arg! | ||
224 | coarseLocations.Add(sp.AbsolutePosition); | ||
225 | avatarUUIDs.Add(sp.UUID); | ||
226 | } | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | coarseLocations.Add(sp.AbsolutePosition); | ||
231 | avatarUUIDs.Add(sp.UUID); | ||
232 | } | ||
233 | } | 228 | } |
234 | } | 229 | } |
235 | 230 | ||
@@ -259,6 +254,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
259 | protected internal bool AddRestoredSceneObject( | 254 | protected internal bool AddRestoredSceneObject( |
260 | SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) | 255 | SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) |
261 | { | 256 | { |
257 | if (!m_parentScene.CombineRegions) | ||
258 | { | ||
259 | // KF: Check for out-of-region, move inside and make static. | ||
260 | Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X, | ||
261 | sceneObject.RootPart.GroupPosition.Y, | ||
262 | sceneObject.RootPart.GroupPosition.Z); | ||
263 | if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || npos.Z < 0.0 || | ||
264 | npos.X > Constants.RegionSize || | ||
265 | npos.Y > Constants.RegionSize)) | ||
266 | { | ||
267 | if (npos.X < 0.0) npos.X = 1.0f; | ||
268 | if (npos.Y < 0.0) npos.Y = 1.0f; | ||
269 | if (npos.Z < 0.0) npos.Z = 0.0f; | ||
270 | if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f; | ||
271 | if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f; | ||
272 | |||
273 | foreach (SceneObjectPart part in sceneObject.Parts) | ||
274 | { | ||
275 | part.GroupPosition = npos; | ||
276 | } | ||
277 | sceneObject.RootPart.Velocity = Vector3.Zero; | ||
278 | sceneObject.RootPart.AngularVelocity = Vector3.Zero; | ||
279 | sceneObject.RootPart.Acceleration = Vector3.Zero; | ||
280 | sceneObject.RootPart.Velocity = Vector3.Zero; | ||
281 | } | ||
282 | } | ||
283 | |||
262 | if (!alreadyPersisted) | 284 | if (!alreadyPersisted) |
263 | { | 285 | { |
264 | sceneObject.ForceInventoryPersistence(); | 286 | sceneObject.ForceInventoryPersistence(); |
@@ -453,6 +475,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
453 | m_updateList[obj.UUID] = obj; | 475 | m_updateList[obj.UUID] = obj; |
454 | } | 476 | } |
455 | 477 | ||
478 | public void FireAttachToBackup(SceneObjectGroup obj) | ||
479 | { | ||
480 | if (OnAttachToBackup != null) | ||
481 | { | ||
482 | OnAttachToBackup(obj); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | public void FireDetachFromBackup(SceneObjectGroup obj) | ||
487 | { | ||
488 | if (OnDetachFromBackup != null) | ||
489 | { | ||
490 | OnDetachFromBackup(obj); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | public void FireChangeBackup(SceneObjectGroup obj) | ||
495 | { | ||
496 | if (OnChangeBackup != null) | ||
497 | { | ||
498 | OnChangeBackup(obj); | ||
499 | } | ||
500 | } | ||
501 | |||
456 | /// <summary> | 502 | /// <summary> |
457 | /// Process all pending updates | 503 | /// Process all pending updates |
458 | /// </summary> | 504 | /// </summary> |
@@ -587,7 +633,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
587 | 633 | ||
588 | Entities[presence.UUID] = presence; | 634 | Entities[presence.UUID] = presence; |
589 | 635 | ||
590 | lock (m_presenceLock) | 636 | m_scenePresencesLock.EnterWriteLock(); |
637 | try | ||
591 | { | 638 | { |
592 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); | 639 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); |
593 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); | 640 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); |
@@ -611,6 +658,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
611 | m_scenePresenceMap = newmap; | 658 | m_scenePresenceMap = newmap; |
612 | m_scenePresenceArray = newlist; | 659 | m_scenePresenceArray = newlist; |
613 | } | 660 | } |
661 | finally | ||
662 | { | ||
663 | m_scenePresencesLock.ExitWriteLock(); | ||
664 | } | ||
614 | } | 665 | } |
615 | 666 | ||
616 | /// <summary> | 667 | /// <summary> |
@@ -625,7 +676,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
625 | agentID); | 676 | agentID); |
626 | } | 677 | } |
627 | 678 | ||
628 | lock (m_presenceLock) | 679 | m_scenePresencesLock.EnterWriteLock(); |
680 | try | ||
629 | { | 681 | { |
630 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); | 682 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); |
631 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); | 683 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); |
@@ -647,6 +699,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
647 | m_log.WarnFormat("[SCENE]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); | 699 | m_log.WarnFormat("[SCENE]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); |
648 | } | 700 | } |
649 | } | 701 | } |
702 | finally | ||
703 | { | ||
704 | m_scenePresencesLock.ExitWriteLock(); | ||
705 | } | ||
650 | } | 706 | } |
651 | 707 | ||
652 | protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) | 708 | protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) |
@@ -770,6 +826,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
770 | return m_scenePresenceArray; | 826 | return m_scenePresenceArray; |
771 | } | 827 | } |
772 | 828 | ||
829 | public int GetNumberOfScenePresences() | ||
830 | { | ||
831 | return m_scenePresenceArray.Count; | ||
832 | } | ||
833 | |||
773 | /// <summary> | 834 | /// <summary> |
774 | /// Request a scene presence by UUID. Fast, indexed lookup. | 835 | /// Request a scene presence by UUID. Fast, indexed lookup. |
775 | /// </summary> | 836 | /// </summary> |
@@ -1063,9 +1124,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1063 | /// <param name="action"></param> | 1124 | /// <param name="action"></param> |
1064 | protected internal void ForEachSOG(Action<SceneObjectGroup> action) | 1125 | protected internal void ForEachSOG(Action<SceneObjectGroup> action) |
1065 | { | 1126 | { |
1066 | List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); | 1127 | EntityBase[] objlist = Entities.GetAllByType<SceneObjectGroup>(); |
1067 | foreach (SceneObjectGroup obj in objlist) | 1128 | foreach (EntityBase ent in objlist) |
1068 | { | 1129 | { |
1130 | SceneObjectGroup obj = (SceneObjectGroup)ent; | ||
1131 | |||
1069 | try | 1132 | try |
1070 | { | 1133 | { |
1071 | action(obj); | 1134 | action(obj); |
@@ -1521,10 +1584,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1521 | /// <param name="childPrims"></param> | 1584 | /// <param name="childPrims"></param> |
1522 | protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) | 1585 | protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) |
1523 | { | 1586 | { |
1587 | SceneObjectGroup parentGroup = root.ParentGroup; | ||
1588 | if (parentGroup == null) return; | ||
1524 | Monitor.Enter(m_updateLock); | 1589 | Monitor.Enter(m_updateLock); |
1590 | |||
1525 | try | 1591 | try |
1526 | { | 1592 | { |
1527 | SceneObjectGroup parentGroup = root.ParentGroup; | 1593 | parentGroup.areUpdatesSuspended = true; |
1528 | 1594 | ||
1529 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); | 1595 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); |
1530 | if (parentGroup != null) | 1596 | if (parentGroup != null) |
@@ -1536,11 +1602,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1536 | 1602 | ||
1537 | if (child != null) | 1603 | if (child != null) |
1538 | { | 1604 | { |
1539 | // Make sure no child prim is set for sale | ||
1540 | // So that, on delink, no prims are unwittingly | ||
1541 | // left for sale and sold off | ||
1542 | child.RootPart.ObjectSaleType = 0; | ||
1543 | child.RootPart.SalePrice = 10; | ||
1544 | childGroups.Add(child); | 1605 | childGroups.Add(child); |
1545 | } | 1606 | } |
1546 | } | 1607 | } |
@@ -1563,12 +1624,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1563 | // occur on link to invoke this elsewhere (such as object selection) | 1624 | // occur on link to invoke this elsewhere (such as object selection) |
1564 | parentGroup.RootPart.CreateSelected = true; | 1625 | parentGroup.RootPart.CreateSelected = true; |
1565 | parentGroup.TriggerScriptChangedEvent(Changed.LINK); | 1626 | parentGroup.TriggerScriptChangedEvent(Changed.LINK); |
1566 | parentGroup.HasGroupChanged = true; | ||
1567 | parentGroup.ScheduleGroupForFullUpdate(); | ||
1568 | |||
1569 | } | 1627 | } |
1570 | finally | 1628 | finally |
1571 | { | 1629 | { |
1630 | parentGroup.areUpdatesSuspended = false; | ||
1631 | parentGroup.HasGroupChanged = true; | ||
1632 | parentGroup.ScheduleGroupForFullUpdate(); | ||
1572 | Monitor.Exit(m_updateLock); | 1633 | Monitor.Exit(m_updateLock); |
1573 | } | 1634 | } |
1574 | } | 1635 | } |
@@ -1600,21 +1661,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
1600 | 1661 | ||
1601 | SceneObjectGroup group = part.ParentGroup; | 1662 | SceneObjectGroup group = part.ParentGroup; |
1602 | if (!affectedGroups.Contains(group)) | 1663 | if (!affectedGroups.Contains(group)) |
1664 | { | ||
1665 | group.areUpdatesSuspended = true; | ||
1603 | affectedGroups.Add(group); | 1666 | affectedGroups.Add(group); |
1667 | } | ||
1604 | } | 1668 | } |
1605 | } | 1669 | } |
1606 | } | 1670 | } |
1607 | 1671 | ||
1608 | foreach (SceneObjectPart child in childParts) | 1672 | if (childParts.Count > 0) |
1609 | { | 1673 | { |
1610 | // Unlink all child parts from their groups | 1674 | foreach (SceneObjectPart child in childParts) |
1611 | // | 1675 | { |
1612 | child.ParentGroup.DelinkFromGroup(child, true); | 1676 | // Unlink all child parts from their groups |
1613 | 1677 | // | |
1614 | // These are not in affected groups and will not be | 1678 | child.ParentGroup.DelinkFromGroup(child, true); |
1615 | // handled further. Do the honors here. | 1679 | child.ParentGroup.HasGroupChanged = true; |
1616 | child.ParentGroup.HasGroupChanged = true; | 1680 | child.ParentGroup.ScheduleGroupForFullUpdate(); |
1617 | child.ParentGroup.ScheduleGroupForFullUpdate(); | 1681 | } |
1618 | } | 1682 | } |
1619 | 1683 | ||
1620 | foreach (SceneObjectPart root in rootParts) | 1684 | foreach (SceneObjectPart root in rootParts) |
@@ -1624,56 +1688,68 @@ namespace OpenSim.Region.Framework.Scenes | |||
1624 | // However, editing linked parts and unlinking may be different | 1688 | // However, editing linked parts and unlinking may be different |
1625 | // | 1689 | // |
1626 | SceneObjectGroup group = root.ParentGroup; | 1690 | SceneObjectGroup group = root.ParentGroup; |
1691 | group.areUpdatesSuspended = true; | ||
1627 | 1692 | ||
1628 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); | 1693 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); |
1629 | int numChildren = newSet.Count; | 1694 | int numChildren = newSet.Count; |
1630 | 1695 | ||
1696 | if (numChildren == 1) | ||
1697 | break; | ||
1698 | |||
1631 | // If there are prims left in a link set, but the root is | 1699 | // If there are prims left in a link set, but the root is |
1632 | // slated for unlink, we need to do this | 1700 | // slated for unlink, we need to do this |
1701 | // Unlink the remaining set | ||
1633 | // | 1702 | // |
1634 | if (numChildren != 1) | 1703 | bool sendEventsToRemainder = true; |
1635 | { | 1704 | if (numChildren > 1) |
1636 | // Unlink the remaining set | 1705 | sendEventsToRemainder = false; |
1637 | // | ||
1638 | bool sendEventsToRemainder = true; | ||
1639 | if (numChildren > 1) | ||
1640 | sendEventsToRemainder = false; | ||
1641 | 1706 | ||
1642 | foreach (SceneObjectPart p in newSet) | 1707 | foreach (SceneObjectPart p in newSet) |
1708 | { | ||
1709 | if (p != group.RootPart) | ||
1643 | { | 1710 | { |
1644 | if (p != group.RootPart) | 1711 | group.DelinkFromGroup(p, sendEventsToRemainder); |
1645 | group.DelinkFromGroup(p, sendEventsToRemainder); | 1712 | if (numChildren > 2) |
1713 | { | ||
1714 | p.ParentGroup.areUpdatesSuspended = true; | ||
1715 | } | ||
1716 | else | ||
1717 | { | ||
1718 | p.ParentGroup.HasGroupChanged = true; | ||
1719 | p.ParentGroup.ScheduleGroupForFullUpdate(); | ||
1720 | } | ||
1646 | } | 1721 | } |
1722 | } | ||
1723 | |||
1724 | // If there is more than one prim remaining, we | ||
1725 | // need to re-link | ||
1726 | // | ||
1727 | if (numChildren > 2) | ||
1728 | { | ||
1729 | // Remove old root | ||
1730 | // | ||
1731 | if (newSet.Contains(root)) | ||
1732 | newSet.Remove(root); | ||
1647 | 1733 | ||
1648 | // If there is more than one prim remaining, we | 1734 | // Preserve link ordering |
1649 | // need to re-link | ||
1650 | // | 1735 | // |
1651 | if (numChildren > 2) | 1736 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) |
1652 | { | 1737 | { |
1653 | // Remove old root | 1738 | return a.LinkNum.CompareTo(b.LinkNum); |
1654 | // | 1739 | }); |
1655 | if (newSet.Contains(root)) | ||
1656 | newSet.Remove(root); | ||
1657 | |||
1658 | // Preserve link ordering | ||
1659 | // | ||
1660 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) | ||
1661 | { | ||
1662 | return a.LinkNum.CompareTo(b.LinkNum); | ||
1663 | }); | ||
1664 | 1740 | ||
1665 | // Determine new root | 1741 | // Determine new root |
1666 | // | 1742 | // |
1667 | SceneObjectPart newRoot = newSet[0]; | 1743 | SceneObjectPart newRoot = newSet[0]; |
1668 | newSet.RemoveAt(0); | 1744 | newSet.RemoveAt(0); |
1669 | 1745 | ||
1670 | foreach (SceneObjectPart newChild in newSet) | 1746 | foreach (SceneObjectPart newChild in newSet) |
1671 | newChild.UpdateFlag = 0; | 1747 | newChild.UpdateFlag = 0; |
1672 | 1748 | ||
1673 | LinkObjects(newRoot, newSet); | 1749 | newRoot.ParentGroup.areUpdatesSuspended = true; |
1674 | if (!affectedGroups.Contains(newRoot.ParentGroup)) | 1750 | LinkObjects(newRoot, newSet); |
1675 | affectedGroups.Add(newRoot.ParentGroup); | 1751 | if (!affectedGroups.Contains(newRoot.ParentGroup)) |
1676 | } | 1752 | affectedGroups.Add(newRoot.ParentGroup); |
1677 | } | 1753 | } |
1678 | } | 1754 | } |
1679 | 1755 | ||
@@ -1683,6 +1759,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1683 | { | 1759 | { |
1684 | g.TriggerScriptChangedEvent(Changed.LINK); | 1760 | g.TriggerScriptChangedEvent(Changed.LINK); |
1685 | g.HasGroupChanged = true; // Persist | 1761 | g.HasGroupChanged = true; // Persist |
1762 | g.areUpdatesSuspended = false; | ||
1686 | g.ScheduleGroupForFullUpdate(); | 1763 | g.ScheduleGroupForFullUpdate(); |
1687 | } | 1764 | } |
1688 | } | 1765 | } |
@@ -1797,9 +1874,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1797 | child.ApplyNextOwnerPermissions(); | 1874 | child.ApplyNextOwnerPermissions(); |
1798 | } | 1875 | } |
1799 | } | 1876 | } |
1800 | |||
1801 | copy.RootPart.ObjectSaleType = 0; | ||
1802 | copy.RootPart.SalePrice = 10; | ||
1803 | } | 1877 | } |
1804 | 1878 | ||
1805 | Entities.Add(copy); | 1879 | Entities.Add(copy); |