aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs9
-rwxr-xr-xOpenSim/Region/Framework/Scenes/Scene.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs122
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs2
5 files changed, 71 insertions, 93 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index f2df364..339fc15 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -2454,6 +2454,7 @@ namespace OpenSim.Region.Framework.Scenes
2454 /// </summary> 2454 /// </summary>
2455 /// <param name="remoteClient"></param> 2455 /// <param name="remoteClient"></param>
2456 /// <param name="itemID"></param> 2456 /// <param name="itemID"></param>
2457 /// <param name="rezGroupID"></param>
2457 /// <param name="RayEnd"></param> 2458 /// <param name="RayEnd"></param>
2458 /// <param name="RayStart"></param> 2459 /// <param name="RayStart"></param>
2459 /// <param name="RayTargetID"></param> 2460 /// <param name="RayTargetID"></param>
@@ -2464,7 +2465,8 @@ namespace OpenSim.Region.Framework.Scenes
2464 /// <param name="RezSelected"></param> 2465 /// <param name="RezSelected"></param>
2465 /// <param name="RemoveItem"></param> 2466 /// <param name="RemoveItem"></param>
2466 /// <param name="fromTaskID"></param> 2467 /// <param name="fromTaskID"></param>
2467 public virtual void RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, 2468 public virtual void RezObject(IClientAPI remoteClient, UUID itemID, UUID rezGroupID,
2469 Vector3 RayEnd, Vector3 RayStart,
2468 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, 2470 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
2469 bool RezSelected, bool RemoveItem, UUID fromTaskID) 2471 bool RezSelected, bool RemoveItem, UUID fromTaskID)
2470 { 2472 {
@@ -2477,7 +2479,7 @@ namespace OpenSim.Region.Framework.Scenes
2477 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); 2479 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
2478 if (invAccess != null) 2480 if (invAccess != null)
2479 invAccess.RezObject( 2481 invAccess.RezObject(
2480 remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, 2482 remoteClient, itemID, rezGroupID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
2481 RezSelected, RemoveItem, fromTaskID, false); 2483 RezSelected, RemoveItem, fromTaskID, false);
2482 } 2484 }
2483 else 2485 else
@@ -2504,8 +2506,7 @@ namespace OpenSim.Region.Framework.Scenes
2504 2506
2505 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); 2507 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
2506 Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); 2508 Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f);
2507 Vector3 pos 2509 Vector3 pos = GetNewRezLocation(
2508 = GetNewRezLocation(
2509 RayStart, RayEnd, RayTargetID, Quaternion.Identity, 2510 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
2510 BypassRayCast, bRayEndIsIntersection, true, scale, false); 2511 BypassRayCast, bRayEndIsIntersection, true, scale, false);
2511 2512
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 00e699e..33418e6 100755
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3115,14 +3115,9 @@ namespace OpenSim.Region.Framework.Scenes
3115 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 3115 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
3116 3116
3117 CheckHeartbeat(); 3117 CheckHeartbeat();
3118
3119 3118
3120 sp = GetScenePresence(client.AgentId); 3119 sp = GetScenePresence(client.AgentId);
3121 3120
3122 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
3123 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
3124 // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already
3125 // connected.
3126 if (sp == null) 3121 if (sp == null)
3127 { 3122 {
3128 m_log.DebugFormat( 3123 m_log.DebugFormat(
@@ -3137,15 +3132,6 @@ namespace OpenSim.Region.Framework.Scenes
3137 3132
3138 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; 3133 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
3139 3134
3140/* done in completMovement
3141 InventoryFolderBase cof = InventoryService.GetFolderForType(client.AgentId, (AssetType)46);
3142 if (cof == null)
3143 sp.COF = UUID.Zero;
3144 else
3145 sp.COF = cof.ID;
3146
3147 m_log.DebugFormat("[SCENE]: COF for {0} is {1}", client.AgentId, sp.COF);
3148 */
3149 m_eventManager.TriggerOnNewPresence(sp); 3135 m_eventManager.TriggerOnNewPresence(sp);
3150 } 3136 }
3151 else 3137 else
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 0b8076a..0847b0b 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -2712,8 +2712,7 @@ namespace OpenSim.Region.Framework.Scenes
2712 detobj.velVector = obj.Velocity; 2712 detobj.velVector = obj.Velocity;
2713 detobj.colliderType = 0; 2713 detobj.colliderType = 0;
2714 detobj.groupUUID = obj.GroupID; 2714 detobj.groupUUID = obj.GroupID;
2715 detobj.linkNumber = LinkNum; // pass my link number 2715 detobj.linkNumber = LinkNum;
2716
2717 return detobj; 2716 return detobj;
2718 } 2717 }
2719 2718
@@ -2726,9 +2725,13 @@ namespace OpenSim.Region.Framework.Scenes
2726 detobj.posVector = av.AbsolutePosition; 2725 detobj.posVector = av.AbsolutePosition;
2727 detobj.rotQuat = av.Rotation; 2726 detobj.rotQuat = av.Rotation;
2728 detobj.velVector = av.Velocity; 2727 detobj.velVector = av.Velocity;
2729 detobj.colliderType = 0; 2728 detobj.colliderType = av.isNPC ? 0x20 : 0x1; // OpenSim\Region\ScriptEngine\Shared\Helpers.cs
2729 if(av.IsSatOnObject)
2730 detobj.colliderType |= 0x4; //passive
2731 else if(detobj.velVector != Vector3.Zero)
2732 detobj.colliderType |= 0x2; //active
2730 detobj.groupUUID = av.ControllingClient.ActiveGroupId; 2733 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
2731 detobj.linkNumber = LinkNum; // pass my link number 2734 detobj.linkNumber = LinkNum;
2732 2735
2733 return detobj; 2736 return detobj;
2734 } 2737 }
@@ -2842,7 +2845,8 @@ namespace OpenSim.Region.Framework.Scenes
2842 if (ParentGroup.Scene == null || ParentGroup.IsDeleted) 2845 if (ParentGroup.Scene == null || ParentGroup.IsDeleted)
2843 return; 2846 return;
2844 2847
2845 // single threaded here 2848 // this a thread from physics ( heartbeat )
2849
2846 CollisionEventUpdate a = (CollisionEventUpdate)e; 2850 CollisionEventUpdate a = (CollisionEventUpdate)e;
2847 Dictionary<uint, ContactPoint> collissionswith = a.m_objCollisionList; 2851 Dictionary<uint, ContactPoint> collissionswith = a.m_objCollisionList;
2848 List<uint> thisHitColliders = new List<uint>(); 2852 List<uint> thisHitColliders = new List<uint>();
@@ -2860,7 +2864,6 @@ namespace OpenSim.Region.Framework.Scenes
2860 } 2864 }
2861 m_lastColliders.Clear(); 2865 m_lastColliders.Clear();
2862 } 2866 }
2863
2864 else 2867 else
2865 { 2868 {
2866 List<CollisionForSoundInfo> soundinfolist = new List<CollisionForSoundInfo>(); 2869 List<CollisionForSoundInfo> soundinfolist = new List<CollisionForSoundInfo>();
@@ -5256,7 +5259,7 @@ SendFullUpdateToClient(remoteClient, Position) ignores position parameter
5256 { 5259 {
5257 // subscribe to physics updates. 5260 // subscribe to physics updates.
5258 pa.OnCollisionUpdate += PhysicsCollision; 5261 pa.OnCollisionUpdate += PhysicsCollision;
5259 pa.SubscribeEvents(50); // 20 reports per second 5262 pa.SubscribeEvents(100); // 10 reports per second
5260 } 5263 }
5261 else 5264 else
5262 { 5265 {
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index e985903..732d5ef 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -224,7 +224,7 @@ namespace OpenSim.Region.Framework.Scenes
224 return true; 224 return true;
225 if (!land.LandData.GroupAVSounds) 225 if (!land.LandData.GroupAVSounds)
226 return false; 226 return false;
227 return land.LandData.GroupID == ControllingClient.ActiveGroupId; 227 return ControllingClient.IsGroupMember(land.LandData.GroupID);
228 } 228 }
229 } 229 }
230 catch 230 catch
@@ -1094,6 +1094,8 @@ namespace OpenSim.Region.Framework.Scenes
1094 m_LandingPointBehavior = LandingPointBehavior.SL; 1094 m_LandingPointBehavior = LandingPointBehavior.SL;
1095 } 1095 }
1096 1096
1097 ControllingClient.RefreshGroupMembership();
1098
1097 } 1099 }
1098 1100
1099 private float lastHealthSent = 0; 1101 private float lastHealthSent = 0;
@@ -1978,7 +1980,6 @@ namespace OpenSim.Region.Framework.Scenes
1978 1980
1979 if(!haveGroupInformation && !IsChildAgent && !isNPC) 1981 if(!haveGroupInformation && !IsChildAgent && !isNPC)
1980 { 1982 {
1981 // oh crap.. lets retry it directly
1982 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 1983 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
1983 if (gm != null) 1984 if (gm != null)
1984 Grouptitle = gm.GetGroupTitle(m_uuid); 1985 Grouptitle = gm.GetGroupTitle(m_uuid);
@@ -2195,13 +2196,14 @@ namespace OpenSim.Region.Framework.Scenes
2195 if (friendsModule != null) 2196 if (friendsModule != null)
2196 { 2197 {
2197 if(gotCrossUpdate) 2198 if(gotCrossUpdate)
2198 friendsModule.IsNpwRoot(this); 2199 friendsModule.IsNowRoot(this);
2199 else 2200 else
2200 friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); 2201 friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
2201 } 2202 }
2202 m_log.DebugFormat("[CompleteMovement] friendsModule: {0}ms", Util.EnvironmentTickCountSubtract(ts)); 2203 m_log.DebugFormat("[CompleteMovement] friendsModule: {0}ms", Util.EnvironmentTickCountSubtract(ts));
2203 2204
2204 } 2205 }
2206
2205 } 2207 }
2206 finally 2208 finally
2207 { 2209 {
@@ -2214,7 +2216,7 @@ namespace OpenSim.Region.Framework.Scenes
2214 // m_currentParcelHide = newhide; 2216 // m_currentParcelHide = newhide;
2215 // } 2217 // }
2216 2218
2217 haveGroupInformation = true; 2219 haveGroupInformation = false;
2218 gotCrossUpdate = false; 2220 gotCrossUpdate = false;
2219 crossingFlags = 0; 2221 crossingFlags = 0;
2220 2222
@@ -4547,24 +4549,12 @@ namespace OpenSim.Region.Framework.Scenes
4547 else 4549 else
4548 cAgent.CrossingFlags = 0; 4550 cAgent.CrossingFlags = 0;
4549 4551
4550 if(isCrossUpdate && haveGroupInformation) 4552 if(isCrossUpdate)
4551 { 4553 {
4552 cAgent.agentCOF = COF; 4554 cAgent.agentCOF = COF;
4553 cAgent.ActiveGroupID = ControllingClient.ActiveGroupId; 4555 cAgent.ActiveGroupID = ControllingClient.ActiveGroupId;
4554 cAgent.ActiveGroupName = ControllingClient.ActiveGroupName; 4556 cAgent.ActiveGroupName = ControllingClient.ActiveGroupName;
4555 cAgent.ActiveGroupTitle = Grouptitle; 4557 cAgent.ActiveGroupTitle = Grouptitle;
4556 Dictionary<UUID, ulong> gpowers = ControllingClient.GetGroupPowers();
4557 if(gpowers.Count >0)
4558 {
4559 cAgent.Groups = new AgentGroupData[gpowers.Count];
4560 int i = 0;
4561 foreach (UUID gid in gpowers.Keys)
4562 {
4563 // WARNING we dont' have AcceptNotices in cache.. sending as true mb no one notices ;)
4564 AgentGroupData agd = new AgentGroupData(gid,gpowers[gid],true);
4565 cAgent.Groups[i++] = agd;
4566 }
4567 }
4568 } 4558 }
4569 } 4559 }
4570 4560
@@ -4661,46 +4651,32 @@ namespace OpenSim.Region.Framework.Scenes
4661 if (Scene.AttachmentsModule != null) 4651 if (Scene.AttachmentsModule != null)
4662 Scene.AttachmentsModule.CopyAttachments(cAgent, this); 4652 Scene.AttachmentsModule.CopyAttachments(cAgent, this);
4663 4653
4664 haveGroupInformation = false; 4654 crossingFlags = cAgent.CrossingFlags;
4655 gotCrossUpdate = (crossingFlags != 0);
4665 4656
4657 haveGroupInformation = false;
4666 // using this as protocol detection don't want to mess with the numbers for now 4658 // using this as protocol detection don't want to mess with the numbers for now
4667 if(cAgent.ActiveGroupTitle != null) 4659 if(cAgent.ActiveGroupTitle != null)
4668 { 4660 {
4661 haveGroupInformation = true;
4669 COF = cAgent.agentCOF; 4662 COF = cAgent.agentCOF;
4670 ControllingClient.ActiveGroupId = cAgent.ActiveGroupID; 4663 if(ControllingClient.IsGroupMember(cAgent.ActiveGroupID))
4671 ControllingClient.ActiveGroupName = cAgent.ActiveGroupName;
4672 ControllingClient.ActiveGroupPowers = 0;
4673 Grouptitle = cAgent.ActiveGroupTitle;
4674
4675 if(cAgent.Groups != null && cAgent.Groups.Length > 0)
4676 { 4664 {
4677 int ngroups = cAgent.Groups.Length; 4665 ControllingClient.ActiveGroupId = cAgent.ActiveGroupID;
4678 Dictionary<UUID, ulong> gpowers = new Dictionary<UUID, ulong>(ngroups); 4666 ControllingClient.ActiveGroupName = cAgent.ActiveGroupName;
4679 for(int i = 0 ; i < ngroups; i++) 4667 Grouptitle = cAgent.ActiveGroupTitle;
4680 { 4668 ControllingClient.ActiveGroupPowers =
4681 AgentGroupData agd = cAgent.Groups[i]; 4669 ControllingClient.GetGroupPowers(cAgent.ActiveGroupID);
4682 gpowers[agd.GroupID] = agd.GroupPowers;
4683 }
4684
4685 ControllingClient.SetGroupPowers(gpowers);
4686
4687 if(cAgent.ActiveGroupID == UUID.Zero)
4688 haveGroupInformation = true;
4689 else if(gpowers.ContainsKey(cAgent.ActiveGroupID))
4690 {
4691 ControllingClient.ActiveGroupPowers = gpowers[cAgent.ActiveGroupID];
4692 haveGroupInformation = true;
4693 }
4694 } 4670 }
4695 else if(cAgent.ActiveGroupID == UUID.Zero) 4671 else
4696 { 4672 {
4697 haveGroupInformation = true; 4673 // we got a unknown active group so get what groups thinks about us
4674 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
4675 if (gm != null)
4676 gm.SendAgentGroupDataUpdate(ControllingClient);
4698 } 4677 }
4699 } 4678 }
4700 4679
4701 crossingFlags = cAgent.CrossingFlags;
4702 gotCrossUpdate = (crossingFlags != 0);
4703
4704 lock (m_originRegionIDAccessLock) 4680 lock (m_originRegionIDAccessLock)
4705 m_originRegionID = cAgent.RegionID; 4681 m_originRegionID = cAgent.RegionID;
4706 } 4682 }
@@ -6061,7 +6037,11 @@ namespace OpenSim.Region.Framework.Scenes
6061 detobj.posVector = av.AbsolutePosition; 6037 detobj.posVector = av.AbsolutePosition;
6062 detobj.rotQuat = av.Rotation; 6038 detobj.rotQuat = av.Rotation;
6063 detobj.velVector = av.Velocity; 6039 detobj.velVector = av.Velocity;
6064 detobj.colliderType = 0; 6040 detobj.colliderType = av.isNPC ? 0x20 : 0x1; // OpenSim\Region\ScriptEngine\Shared\Helpers.cs
6041 if(av.IsSatOnObject)
6042 detobj.colliderType |= 0x4; //passive
6043 else if(detobj.velVector != Vector3.Zero)
6044 detobj.colliderType |= 0x2; //active
6065 detobj.groupUUID = av.ControllingClient.ActiveGroupId; 6045 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
6066 detobj.linkNumber = 0; 6046 detobj.linkNumber = 0;
6067 6047
@@ -6153,9 +6133,6 @@ namespace OpenSim.Region.Framework.Scenes
6153 List<uint> thisHitColliders = new List<uint>(); 6133 List<uint> thisHitColliders = new List<uint>();
6154 List<uint> endedColliders = new List<uint>(); 6134 List<uint> endedColliders = new List<uint>();
6155 List<uint> startedColliders = new List<uint>(); 6135 List<uint> startedColliders = new List<uint>();
6156 List<CollisionForSoundInfo> soundinfolist = new List<CollisionForSoundInfo>();
6157 CollisionForSoundInfo soundinfo;
6158 ContactPoint curcontact;
6159 6136
6160 if (coldata.Count == 0) 6137 if (coldata.Count == 0)
6161 { 6138 {
@@ -6168,30 +6145,41 @@ namespace OpenSim.Region.Framework.Scenes
6168 } 6145 }
6169 m_lastColliders.Clear(); 6146 m_lastColliders.Clear();
6170 } 6147 }
6171
6172 else 6148 else
6173 { 6149 {
6174 bool candoparcelSound = ParcelAllowThisAvatarSounds; 6150 List<CollisionForSoundInfo> soundinfolist = new List<CollisionForSoundInfo>();
6175 6151 if(ParcelAllowThisAvatarSounds)
6176 foreach (uint id in coldata.Keys)
6177 { 6152 {
6178 thisHitColliders.Add(id); 6153 CollisionForSoundInfo soundinfo;
6179 if (!m_lastColliders.Contains(id)) 6154 ContactPoint curcontact;
6155
6156 foreach (uint id in coldata.Keys)
6180 { 6157 {
6181 startedColliders.Add(id); 6158 thisHitColliders.Add(id);
6182 curcontact = coldata[id]; 6159 if (!m_lastColliders.Contains(id))
6183 if (candoparcelSound && Math.Abs(curcontact.RelativeSpeed) > 0.2)
6184 { 6160 {
6185 soundinfo = new CollisionForSoundInfo(); 6161 startedColliders.Add(id);
6186 soundinfo.colliderID = id; 6162 curcontact = coldata[id];
6187 soundinfo.position = curcontact.Position; 6163 if (Math.Abs(curcontact.RelativeSpeed) > 0.2)
6188 soundinfo.relativeVel = curcontact.RelativeSpeed; 6164 {
6189 soundinfolist.Add(soundinfo); 6165 soundinfo = new CollisionForSoundInfo();
6166 soundinfo.colliderID = id;
6167 soundinfo.position = curcontact.Position;
6168 soundinfo.relativeVel = curcontact.RelativeSpeed;
6169 soundinfolist.Add(soundinfo);
6170 }
6190 } 6171 }
6191 } 6172 }
6192 //m_log.Debug("[SCENE PRESENCE]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
6193 } 6173 }
6194 6174 else
6175 {
6176 foreach (uint id in coldata.Keys)
6177 {
6178 thisHitColliders.Add(id);
6179 if (!m_lastColliders.Contains(id))
6180 startedColliders.Add(id);
6181 }
6182 }
6195 // calculate things that ended colliding 6183 // calculate things that ended colliding
6196 foreach (uint localID in m_lastColliders) 6184 foreach (uint localID in m_lastColliders)
6197 { 6185 {
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
index 75b073d..142ad84 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
@@ -171,7 +171,7 @@ namespace OpenSim.Region.Framework.Tests
171 //Assert.That((retrievedItem1.CurrentPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); 171 //Assert.That((retrievedItem1.CurrentPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All);
172 172
173 // Rez the object 173 // Rez the object
174 scene.RezObject(sp2.ControllingClient, retrievedItem1.ID, Vector3.Zero, Vector3.Zero, UUID.Zero, 0, false, false, false, UUID.Zero); 174 scene.RezObject(sp2.ControllingClient, retrievedItem1.ID, UUID.Zero, Vector3.Zero, Vector3.Zero, UUID.Zero, 0, false, false, false, UUID.Zero);
175 SceneObjectGroup sog = scene.GetSceneObjectGroup("SomeObject"); 175 SceneObjectGroup sog = scene.GetSceneObjectGroup("SomeObject");
176 Assert.That(sog, Is.Not.Null); 176 Assert.That(sog, Is.Not.Null);
177 177