From e83a2181d06717afe3e5a02d8c918effbe80f226 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 9 Mar 2012 17:19:10 +0000 Subject: [PATCH 1/4] on linking update linked parts physical flags acording to new parent ones ( untested ) --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 2d71372011..58187983d2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2499,6 +2499,11 @@ namespace OpenSim.Region.Framework.Scenes if (linkPart.PhysActor != null) linkPart.PhysActor.Building = true; + // physics flags from group to be applied to linked parts + bool grpusephys = UsesPhysics; + bool grptemporary = IsTemporary; + bool gprphantom = IsPhantom; + Vector3 oldGroupPosition = linkPart.GroupPosition; Quaternion oldRootRotation = linkPart.RotationOffset; @@ -2542,7 +2547,8 @@ namespace OpenSim.Region.Framework.Scenes linkPart.SetParent(this); linkPart.CreateSelected = true; - // let physics know + // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now + linkPart.UpdatePrimFlags(grpusephys, grptemporary, gprphantom, linkPart.VolumeDetectActive, true); if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) { linkPart.PhysActor.link(m_rootPart.PhysActor); @@ -2564,6 +2570,7 @@ namespace OpenSim.Region.Framework.Scenes { LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); // let physics know + part.UpdatePrimFlags(grpusephys, grptemporary, gprphantom, part.VolumeDetectActive, true); if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) { part.PhysActor.link(m_rootPart.PhysActor); From 0e5e324a2c0969936946f0432c6783b19fc5e111 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 9 Mar 2012 17:20:49 +0000 Subject: [PATCH 2/4] ubitOde bug --- OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs index b105f77da7..563d527dcd 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs @@ -1524,17 +1524,19 @@ namespace OpenSim.Region.Physics.OdePlugin { prm.m_collisionCategories |= CollisionCategories.Body; prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + d.GeomEnable(prm.prim_geom); } if (prm.m_NoColide) { d.GeomSetCategoryBits(prm.prim_geom, 0); d.GeomSetCollideBits(prm.prim_geom, (int)CollisionCategories.Land); + d.GeomEnable(prm.prim_geom); } else { - d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags); + d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); + d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); } prm.m_collisionscore = 0; From 908abb1c3dded307e769abac71f660b835875975 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 10 Mar 2012 20:32:19 +0000 Subject: [PATCH 3/4] BIG MESS. changed Iclient interface so only one event is used to inform scene about position scale or rotation change by client (others can be added). Its served at SceneGraph that does permition checks, undostore and sends down to SOG. changed values are stored in a class (ObjectChangeData) and what is changed as a enum (ObjectChangeWhat) with bit fields and 'macros' of this for better readability (at top of scenegraph.cs lasy to find better place for now) this can be extended for other things clients changes and need undo/redo. SOG process acording to what is changed. Changed UNDO/redo to use this also (warning is only storing what is changed, previus stored all, this must be checked for side efects. to save all PRS change commented line in scenegraph). Still have excessive calls to ScheduleGroupForTerseUpdate. **** UNTESTED **** --- OpenSim/Framework/IClientAPI.cs | 3 + .../ClientStack/Linden/UDP/LLClientView.cs | 156 ++++++++++++-- OpenSim/Region/Framework/Scenes/Scene.cs | 4 + OpenSim/Region/Framework/Scenes/SceneGraph.cs | 152 +++++++++++++ .../Framework/Scenes/SceneObjectGroup.cs | 204 +++++++----------- .../Framework/Scenes/SceneObjectPart.cs | 47 +++- OpenSim/Region/Framework/Scenes/UndoState.cs | 113 +++++++++- .../Server/IRCClientView.cs | 1 + .../OptionalModules/World/NPC/NPCAvatar.cs | 1 + OpenSim/Tests/Common/Mock/TestClient.cs | 1 + 10 files changed, 543 insertions(+), 139 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 5e156f1772..1bd4749713 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -130,6 +130,8 @@ namespace OpenSim.Framework public delegate void UpdateVector(uint localID, Vector3 pos, IClientAPI remoteClient); + public delegate void ClientChangeObject(uint localID, object data ,IClientAPI remoteClient); + public delegate void UpdatePrimRotation(uint localID, Quaternion rot, IClientAPI remoteClient); public delegate void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient); @@ -838,6 +840,7 @@ namespace OpenSim.Framework event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; event UpdatePrimFlags OnUpdatePrimFlags; event UpdatePrimTexture OnUpdatePrimTexture; + event ClientChangeObject onClientChangeObject; event UpdateVector OnUpdatePrimGroupPosition; event UpdateVector OnUpdatePrimSinglePosition; event UpdatePrimRotation OnUpdatePrimGroupRotation; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 051c4fa8e3..7d51323456 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -125,6 +125,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; public event UpdatePrimFlags OnUpdatePrimFlags; public event UpdatePrimTexture OnUpdatePrimTexture; + public event ClientChangeObject onClientChangeObject; public event UpdateVector OnUpdatePrimGroupPosition; public event UpdateVector OnUpdatePrimSinglePosition; public event UpdatePrimRotation OnUpdatePrimGroupRotation; @@ -11517,22 +11518,151 @@ namespace OpenSim.Region.ClientStack.LindenUDP // parts[j].IgnoreUndoUpdate = true; // } - UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; - UpdateVector handlerUpdatePrimGroupScale; +// UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; +// UpdateVector handlerUpdatePrimGroupScale; - Quaternion arot; - Vector3 ascale; - Vector3 apos; -/*ubit from ll JIRA: - * 0x01 position - * 0x02 rotation - * 0x04 scale + ClientChangeObject updatehandler = onClientChangeObject; + + if (updatehandler != null) + { + ObjectChangeData udata = new ObjectChangeData(); + + /*ubit from ll JIRA: + * 0x01 position + * 0x02 rotation + * 0x04 scale - * 0x08 LINK_SET - * 0x10 UNIFORM for scale - */ + * 0x08 LINK_SET + * 0x10 UNIFORM for scale + */ + // translate to internal changes + // not all cases .. just the ones older code did + switch (block.Type) + { + case 1: //change position sp + udata.position = new Vector3(block.Data, 0); + + udata.what = ObjectChangeWhat.primP; + updatehandler(localId, udata, this); + break; + + case 2: // rotation sp + udata.rotation = new Quaternion(block.Data, 0, true); + + udata.what = ObjectChangeWhat.primR; + updatehandler(localId, udata, this); + break; + + case 3: // position plus rotation + udata.position = new Vector3(block.Data, 0); + udata.rotation = new Quaternion(block.Data, 12, true); + + udata.what = ObjectChangeWhat.primPR; + updatehandler(localId, udata, this); + + break; + + case 4: // scale sp + udata.scale = new Vector3(block.Data, 0); + udata.what = ObjectChangeWhat.primS; + + updatehandler(localId, udata, this); + break; + + case 0x14: // uniform scale sp + udata.scale = new Vector3(block.Data, 0); + + udata.what = ObjectChangeWhat.primUS; + updatehandler(localId, udata, this); + break; + + case 5: // scale and position sp + udata.position = new Vector3(block.Data, 0); + udata.scale = new Vector3(block.Data, 12); + + udata.what = ObjectChangeWhat.primPS; + updatehandler(localId, udata, this); + break; + + case 0x15: //uniform scale and position + udata.position = new Vector3(block.Data, 0); + udata.scale = new Vector3(block.Data, 12); + + udata.what = ObjectChangeWhat.primPUS; + updatehandler(localId, udata, this); + break; + + // now group related (bit 4) + case 9: //( 8 + 1 )group position + udata.position = new Vector3(block.Data, 0); + + udata.what = ObjectChangeWhat.groupP; + updatehandler(localId, udata, this); + break; + + case 0x0A: // (8 + 2) group rotation + udata.rotation = new Quaternion(block.Data, 0, true); + + udata.what = ObjectChangeWhat.groupR; + updatehandler(localId, udata, this); + break; + + case 0x0B: //( 8 + 2 + 1) group rotation and position + udata.position = new Vector3(block.Data, 0); + udata.rotation = new Quaternion(block.Data, 12, true); + + udata.what = ObjectChangeWhat.groupPR; + updatehandler(localId, udata, this); + break; + + case 0x0C: // (8 + 4) group scale + // only afects root prim and only sent by viewer editor object tab scaling + // mouse edition only allows uniform scaling + // SL MAY CHANGE THIS in viewers + + udata.scale = new Vector3(block.Data, 0); + + // udata.what = ObjectChangeWhat.groupS; + udata.what = ObjectChangeWhat.primS; // to conform to current SL + updatehandler(localId, udata, this); + + break; + + case 0x0D: //(8 + 4 + 1) group scale and position + // exception as above + + udata.position = new Vector3(block.Data, 0); + udata.scale = new Vector3(block.Data, 12); + + // udata.what = ObjectChangeWhat.groupPS; + udata.what = ObjectChangeWhat.primPS; // to conform to current SL + updatehandler(localId, udata, this); + break; + + case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM + udata.scale = new Vector3(block.Data, 0); + + udata.what = ObjectChangeWhat.groupUS; + updatehandler(localId, udata, this); + break; + + case 0x1D: // (UNIFORM + GROUP + SCALE + POS) + udata.position = new Vector3(block.Data, 0); + udata.scale = new Vector3(block.Data, 12); + + udata.what = ObjectChangeWhat.groupPUS; + updatehandler(localId, udata, this); + break; + + default: + m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); + break; + } + } + +/* switch (block.Type) { case 1: //change position sp @@ -11788,7 +11918,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); break; } - +*/ // for (int j = 0; j < parts.Length; j++) // parts[j].IgnoreUndoUpdate = false; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 68c05f85d6..a3358a597d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2811,6 +2811,8 @@ namespace OpenSim.Region.Framework.Scenes client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition; client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition; + client.onClientChangeObject += m_sceneGraph.ClientChangeObject; + client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; @@ -2940,6 +2942,8 @@ namespace OpenSim.Region.Framework.Scenes client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition; client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition; + client.onClientChangeObject -= m_sceneGraph.ClientChangeObject; + client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation; diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 3cd4a10e6c..5e770ba1fd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -47,6 +47,57 @@ namespace OpenSim.Region.Framework.Scenes public delegate void ChangedBackupDelegate(SceneObjectGroup sog); + + public enum ObjectChangeWhat : uint + { + // bits definitions + Position = 0x01, + Rotation = 0x02, + Scale = 0x04, + Group = 0x08, + UniformScale = 0x10, + + // macros from above + // single prim + primP = 0x01, + primR = 0x02, + primPR = 0x03, + primS = 0x04, + primPS = 0x05, + primRS = 0x06, + primPSR = 0x07, + + primUS = 0x14, + primPUS = 0x15, + primRUS = 0x16, + primPUSR = 0x17, + + // group + groupP = 0x09, + groupR = 0x0A, + groupPR = 0x0B, + groupS = 0x0C, + groupPS = 0x0D, + groupRS = 0x0E, + groupPSR = 0x0F, + + groupUS = 0x1C, + groupPUS = 0x1D, + groupRUS = 0x1E, + groupPUSR = 0x1F, + + PRSmask = 0x07 + } + + public struct ObjectChangeData + { + public Quaternion rotation; + public Vector3 position; + public Vector3 scale; + public ObjectChangeWhat what; + } + + /// /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components /// should be migrated out over time. @@ -1289,6 +1340,87 @@ namespace OpenSim.Region.Framework.Scenes #region Client Event handlers + protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient) + { + SceneObjectPart part = GetSceneObjectPart(localID); + ObjectChangeData data = (ObjectChangeData)odata; + + if (part != null) + { + SceneObjectGroup grp = part.ParentGroup; + if (grp != null) + { + if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId)) + { +// part.StoreUndoState(data.what | ObjectChangeWhat.PRSmask); // for now save all to keep previus behavour ??? + part.StoreUndoState(data.what); // lets test only saving what we changed + grp.doChangeObject(part, (ObjectChangeData)data); + } + } + } + } + +/* moved to SOG + protected internal void doChangeObject(SceneObjectPart part, ObjectChangeData data) + { + if (part != null && part.ParentGroup != null) + { + ObjectChangeWhat what = data.what; + bool togroup = ((what & ObjectChangeWhat.Group) != 0); +// bool uniform = ((what & ObjectChangeWhat.UniformScale) != 0); not in use + + SceneObjectGroup group = part.ParentGroup; + PhysicsActor pha = group.RootPart.PhysActor; + + if (togroup) + { + // related to group + if ((what & ObjectChangeWhat.Position) != 0) + group.AbsolutePosition = data.position; + if ((what & ObjectChangeWhat.Rotation) != 0) + group.RootPart.UpdateRotation(data.rotation); + if ((what & ObjectChangeWhat.Scale) != 0) + { + if (pha != null) + pha.Building = true; + group.GroupResize(data.scale); + if (pha != null) + pha.Building = false; + } + } + else + { + // related to single prim in a link-set ( ie group) + if (pha != null) + pha.Building = true; + + // must deal with root part specially for position and rotation + // so parts offset positions or rotations are fixed + + if (part == group.RootPart) + { + if ((what & ObjectChangeWhat.Position) != 0) + group.UpdateRootPosition(data.position); + if ((what & ObjectChangeWhat.Rotation) != 0) + group.UpdateRootRotation(data.rotation); + } + else + { + if ((what & ObjectChangeWhat.Position) != 0) + part.OffsetPosition = data.position; + if ((what & ObjectChangeWhat.Rotation) != 0) + part.UpdateRotation(data.rotation); + } + + if ((what & ObjectChangeWhat.Scale) != 0) + part.Resize(data.scale); + + if (pha != null) + pha.Building = false; + } + } + } +*/ /// /// Update the scale of an individual prim. /// @@ -1303,7 +1435,17 @@ namespace OpenSim.Region.Framework.Scenes { if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) { + bool physbuild = false; + if (part.ParentGroup.RootPart.PhysActor != null) + { + part.ParentGroup.RootPart.PhysActor.Building = true; + physbuild = true; + } + part.Resize(scale); + + if (physbuild) + part.ParentGroup.RootPart.PhysActor.Building = false; } } } @@ -1315,7 +1457,17 @@ namespace OpenSim.Region.Framework.Scenes { if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) { + bool physbuild = false; + if (group.RootPart.PhysActor != null) + { + group.RootPart.PhysActor.Building = true; + physbuild = true; + } + group.GroupResize(scale); + + if (physbuild) + group.RootPart.PhysActor.Building = false; } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 58187983d2..92f2d54f52 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -3124,10 +3124,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void GroupResize(Vector3 scale) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); -// RootPart.StoreUndoState(true); - scale.X = Math.Min(scale.X, Scene.m_maxNonphys); scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); @@ -3152,7 +3148,6 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart obPart = parts[i]; if (obPart.UUID != m_rootPart.UUID) { -// obPart.IgnoreUndoUpdate = true; Vector3 oldSize = new Vector3(obPart.Scale); float f = 1.0f; @@ -3216,8 +3211,6 @@ namespace OpenSim.Region.Framework.Scenes z *= a; } } - -// obPart.IgnoreUndoUpdate = false; } } } @@ -3226,9 +3219,8 @@ namespace OpenSim.Region.Framework.Scenes prevScale.X *= x; prevScale.Y *= y; prevScale.Z *= z; -// RootPart.IgnoreUndoUpdate = true; + RootPart.Resize(prevScale); -// RootPart.IgnoreUndoUpdate = false; parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) @@ -3237,8 +3229,6 @@ namespace OpenSim.Region.Framework.Scenes if (obPart.UUID != m_rootPart.UUID) { -// obPart.IgnoreUndoUpdate = true; - Vector3 currentpos = new Vector3(obPart.OffsetPosition); currentpos.X *= x; currentpos.Y *= y; @@ -3251,18 +3241,12 @@ namespace OpenSim.Region.Framework.Scenes obPart.Resize(newSize); obPart.UpdateOffSet(currentpos); - -// obPart.IgnoreUndoUpdate = false; } -// obPart.IgnoreUndoUpdate = false; HasGroupChanged = true; m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); ScheduleGroupForTerseUpdate(); } - -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale); } #endregion @@ -3275,14 +3259,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateGroupPosition(Vector3 pos) { -// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos); - -// RootPart.StoreUndoState(true); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) { if (IsAttachment) @@ -3314,22 +3290,14 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// + /// + public void UpdateSinglePosition(Vector3 pos, uint localID) { SceneObjectPart part = GetChildPart(localID); -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - if (part != null) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); - -// part.StoreUndoState(false); -// part.IgnoreUndoUpdate = true; - // unlock parts position change if (m_rootPart.PhysActor != null) m_rootPart.PhysActor.Building = true; @@ -3347,7 +3315,6 @@ namespace OpenSim.Region.Framework.Scenes m_rootPart.PhysActor.Building = false; HasGroupChanged = true; -// part.IgnoreUndoUpdate = false; } } @@ -3357,13 +3324,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateRootPosition(Vector3 pos) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - + // needs to be called with phys building true Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); Vector3 oldPos = new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, @@ -3383,17 +3344,7 @@ namespace OpenSim.Region.Framework.Scenes obPart.OffsetPosition = obPart.OffsetPosition + diff; } - //We have to set undoing here because otherwise an undo state will be saved -// if (!m_rootPart.Undoing) -// { -// m_rootPart.Undoing = true; - AbsolutePosition = newPos; -// m_rootPart.Undoing = false; -// } -// else -// { -// AbsolutePosition = newPos; -// } + AbsolutePosition = newPos; HasGroupChanged = true; if (m_rootPart.Undoing) @@ -3416,17 +3367,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateGroupRotationR(Quaternion rot) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - -// m_rootPart.StoreUndoState(true); - -// m_rootPart.UpdateRotation(rot); - PhysicsActor actor = m_rootPart.PhysActor; if (actor != null) { @@ -3445,16 +3385,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - -// RootPart.StoreUndoState(true); -// RootPart.IgnoreUndoUpdate = true; - m_rootPart.UpdateRotation(rot); PhysicsActor actor = m_rootPart.PhysActor; @@ -3468,8 +3398,6 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; ScheduleGroupForTerseUpdate(); - -// RootPart.IgnoreUndoUpdate = false; } /// @@ -3484,9 +3412,6 @@ namespace OpenSim.Region.Framework.Scenes if (part != null) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); - if (m_rootPart.PhysActor != null) m_rootPart.PhysActor.Building = true; @@ -3514,30 +3439,13 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = GetChildPart(localID); if (part != null) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", -// part.Name, part.LocalId, rot); - -// part.StoreUndoState(); -// part.IgnoreUndoUpdate = true; - if (m_rootPart.PhysActor != null) m_rootPart.PhysActor.Building = true; if (part.UUID == m_rootPart.UUID) { UpdateRootRotation(rot); -/* if (!m_rootPart.Undoing) - { - m_rootPart.Undoing = true; - AbsolutePosition = pos; - m_rootPart.Undoing = false; - } - else - { - */ - AbsolutePosition = pos; -// } + AbsolutePosition = pos; } else { @@ -3547,8 +3455,6 @@ namespace OpenSim.Region.Framework.Scenes if (m_rootPart.PhysActor != null) m_rootPart.PhysActor.Building = false; - -// part.IgnoreUndoUpdate = false; } } @@ -3558,13 +3464,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateRootRotation(Quaternion rot) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}", -// Name, LocalId, rot); - + // needs to be called with phys building true Quaternion axRot = rot; Quaternion oldParentRot = m_rootPart.RotationOffset; -// m_rootPart.StoreUndoState(); //Don't use UpdateRotation because it schedules an update prematurely m_rootPart.RotationOffset = rot; @@ -3580,8 +3482,6 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart prim = parts[i]; if (prim.UUID != m_rootPart.UUID) { -// prim.IgnoreUndoUpdate = true; - Quaternion NewRot = oldParentRot * prim.RotationOffset; NewRot = Quaternion.Inverse(axRot) * NewRot; prim.RotationOffset = NewRot; @@ -3591,26 +3491,88 @@ namespace OpenSim.Region.Framework.Scenes axPos *= oldParentRot; axPos *= Quaternion.Inverse(axRot); prim.OffsetPosition = axPos; - -// prim.IgnoreUndoUpdate = false; } } -// for (int i = 0; i < parts.Length; i++) -// { -// SceneObjectPart childpart = parts[i]; -// if (childpart != m_rootPart) -// { -//// childpart.IgnoreUndoUpdate = false; -//// childpart.StoreUndoState(); -// } -// } HasGroupChanged = true; ScheduleGroupForFullUpdate(); + } -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", -// Name, LocalId, rot); + public void doChangeObject(SceneObjectPart part, ObjectChangeData data) + { + // TODO this still as excessive ScheduleGroupForTerseUpdate()s + + if (part != null && part.ParentGroup != null) + { + ObjectChangeWhat what = data.what; + bool togroup = ((what & ObjectChangeWhat.Group) != 0); + // bool uniform = ((what & ObjectChangeWhat.UniformScale) != 0); not in use + + SceneObjectGroup group = part.ParentGroup; + PhysicsActor pha = group.RootPart.PhysActor; + + bool needgrpUpdate = false; + + if (togroup) + { + // related to group + if ((what & ObjectChangeWhat.Position) != 0) + { + group.AbsolutePosition = data.position; + needgrpUpdate = true; + } + if ((what & ObjectChangeWhat.Rotation) != 0) + group.RootPart.UpdateRotation(data.rotation); + if ((what & ObjectChangeWhat.Scale) != 0) + { + if (pha != null) + pha.Building = true; + group.GroupResize(data.scale); + if (pha != null) + pha.Building = false; + } + } + else + { + // related to single prim in a link-set ( ie group) + if (pha != null) + pha.Building = true; + + // must deal with root part specially for position and rotation + // so parts offset positions or rotations are fixed + + if (part == group.RootPart) + { + if ((what & ObjectChangeWhat.Position) != 0) + group.UpdateRootPosition(data.position); + if ((what & ObjectChangeWhat.Rotation) != 0) + group.UpdateRootRotation(data.rotation); + } + else + { + + if ((what & ObjectChangeWhat.Position) != 0) + { + part.OffsetPosition = data.position; + needgrpUpdate = true; + } + if ((what & ObjectChangeWhat.Rotation) != 0) + part.UpdateRotation(data.rotation); + } + + if ((what & ObjectChangeWhat.Scale) != 0) + part.Resize(data.scale); + + if (pha != null) + pha.Building = false; + } + + if (needgrpUpdate) + { + HasGroupChanged = true; + ScheduleGroupForTerseUpdate(); + } + } } #endregion diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 662249597a..c806fda5cc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1944,6 +1944,7 @@ namespace OpenSim.Region.Framework.Scenes PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; PhysActor.OnOutOfBounds += PhysicsOutOfBounds; + if (ParentID != 0 && ParentID != LocalId) { if (ParentGroup.RootPart.PhysActor != null) @@ -3656,7 +3657,7 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.ScheduleGroupForTerseUpdate(); //ParentGroup.ScheduleGroupForFullUpdate(); } - +/* public void StoreUndoState() { StoreUndoState(false); @@ -3697,6 +3698,44 @@ namespace OpenSim.Region.Framework.Scenes } } } +*/ + + + public void StoreUndoState(ObjectChangeWhat what) + { + if (!Undoing && !IgnoreUndoUpdate) // just to read better - undo is in progress, or suspended + { + if (ParentGroup != null) + { + lock (m_undo) + { + if (m_undo.Count > 0) + { + // see if we had a change + + UndoState last = m_undo.Peek(); + if (last != null) + { + if (last.Compare(this, what)) + { + return; + } + } + } + + if (ParentGroup.GetSceneMaxUndo() > 0) + { + UndoState nUndo = new UndoState(this, what); + + m_undo.Push(nUndo); + + if (m_redo.Count > 0) + m_redo.Clear(); + } + } + } + } + } /// /// Return number of undos on the stack. Here temporarily pending a refactor. @@ -3725,10 +3764,10 @@ namespace OpenSim.Region.Framework.Scenes if (goback != null) { UndoState nUndo = null; - + if (ParentGroup.GetSceneMaxUndo() > 0) { - nUndo = new UndoState(this, goback.ForGroup); + nUndo = new UndoState(this, goback.data.what); } goback.PlayState(this); @@ -3760,7 +3799,7 @@ namespace OpenSim.Region.Framework.Scenes { if (ParentGroup.GetSceneMaxUndo() > 0) { - UndoState nUndo = new UndoState(this, gofwd.ForGroup); + UndoState nUndo = new UndoState(this, gofwd.data.what); m_undo.Push(nUndo); } diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index 38474def84..eb76ca5bba 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs @@ -48,6 +48,7 @@ namespace OpenSim.Region.Framework.Scenes STATE_ALL = 63 } +/* public class UndoState { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -121,9 +122,16 @@ namespace OpenSim.Region.Framework.Scenes public void PlayState(SceneObjectPart part) { part.Undoing = true; - + bool physbuilding = false; + if (part.ParentID == 0) { + if (!ForGroup && part.PhysActor != null) + { + part.PhysActor.Building = true; + physbuilding = true; + } + if (Position != Vector3.Zero) { if (ForGroup) @@ -139,17 +147,34 @@ namespace OpenSim.Region.Framework.Scenes if (Scale != Vector3.Zero) { + if (!physbuilding && part.PhysActor != null) + { + part.PhysActor.Building = true; + physbuilding = true; + } + if (ForGroup) part.ParentGroup.GroupResize(Scale); else part.Resize(Scale); } + + if (physbuilding) + part.PhysActor.Building = false; + part.ParentGroup.ScheduleGroupForTerseUpdate(); } else { if (ForGroup) // trap for group since seems parts can't do it return; + + // changing a part invalidates entire object physical rep + if (part.ParentGroup != null && part.ParentGroup.RootPart != null && part.ParentGroup.RootPart.PhysActor != null) + { + part.ParentGroup.RootPart.PhysActor.Building = true; + physbuilding = true; + } // Note: Updating these properties on sop automatically schedules an update if needed part.OffsetPosition = Position; @@ -158,11 +183,97 @@ namespace OpenSim.Region.Framework.Scenes { part.Resize(Scale); } + + if (physbuilding) + part.ParentGroup.RootPart.PhysActor.Building = false; } part.Undoing = false; } } +*/ + public class UndoState + { + public ObjectChangeData data; + /// + /// Constructor. + /// + /// + /// True if the undo is for an entire group + /// only for root parts ???? + public UndoState(SceneObjectPart part, ObjectChangeWhat what) + { + data = new ObjectChangeData(); + + data.what = what; + + if (part.ParentGroup.RootPart == part) + { + if ((what & ObjectChangeWhat.Position) != 0) + data.position = part.ParentGroup.AbsolutePosition; + if ((what & ObjectChangeWhat.Rotation) != 0) + data.rotation = part.RotationOffset; + if ((what & ObjectChangeWhat.Scale) != 0) + data.scale = part.Shape.Scale; + } + else + { + if ((what & ObjectChangeWhat.Position) != 0) + data.position = part.OffsetPosition; + if ((what & ObjectChangeWhat.Rotation) != 0) + data.rotation = part.RotationOffset; + if ((what & ObjectChangeWhat.Scale) != 0) + data.scale = part.Shape.Scale; + } + } + + /// + /// Compare the relevant state in the given part to this state. + /// + /// + /// true if both the part's position, rotation and scale match those in this undo state. False otherwise. + public bool Compare(SceneObjectPart part, ObjectChangeWhat what) + { + if (data.what != what) // if diferent targets, then they are diferent + return false; + + if (part != null) + { + if (part.ParentID == 0) + { + if ((what & ObjectChangeWhat.Position) != 0 && data.position != part.ParentGroup.AbsolutePosition) + return false; + } + else + { + if ((what & ObjectChangeWhat.Position) != 0 && data.position != part.OffsetPosition) + return false; + } + + if ((what & ObjectChangeWhat.Rotation) != 0 && data.rotation != part.RotationOffset) + return false; + if ((what & ObjectChangeWhat.Rotation) != 0 && data.scale == part.Shape.Scale) + return false; + return true; + + } + return false; + } + + public void PlayState(SceneObjectPart part) + { + part.Undoing = true; + + SceneObjectGroup grp = part.ParentGroup; + + if (grp != null) + { + grp.doChangeObject(part, data); + } + part.Undoing = false; + } + } + public class LandUndoState { diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 0f62b2a1a7..18f8f34002 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -714,6 +714,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; public event UpdatePrimFlags OnUpdatePrimFlags; public event UpdatePrimTexture OnUpdatePrimTexture; + public event ClientChangeObject onClientChangeObject; public event UpdateVector OnUpdatePrimGroupPosition; public event UpdateVector OnUpdatePrimSinglePosition; public event UpdatePrimRotation OnUpdatePrimGroupRotation; diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index d0b822c64b..96f33a5a91 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -240,6 +240,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event UpdatePrimTexture OnUpdatePrimTexture; public event UpdateVector OnUpdatePrimGroupPosition; public event UpdateVector OnUpdatePrimSinglePosition; + public event ClientChangeObject onClientChangeObject; public event UpdatePrimRotation OnUpdatePrimGroupRotation; public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index fa750aba1b..be6b81b5ac 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -135,6 +135,7 @@ namespace OpenSim.Tests.Common.Mock public event GenericCall7 OnObjectMaterial; public event UpdatePrimFlags OnUpdatePrimFlags; public event UpdatePrimTexture OnUpdatePrimTexture; + public event ClientChangeObject onClientChangeObject; public event UpdateVector OnUpdatePrimGroupPosition; public event UpdateVector OnUpdatePrimSinglePosition; public event UpdatePrimRotation OnUpdatePrimGroupRotation; From ab235abc46e3d902a7aaf61e589b81f826a2d7a5 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 11 Mar 2012 00:36:34 +0000 Subject: [PATCH 4/4] Changed undo redo internals. moved exec code to UndoState.cs from sop that now only sees a unified UndoRedoStore class, added size limit on buffers so only last 5 undo/redo are kept. (5 is hardcode like it was ) ***UNTESTED*** --- .../Framework/Scenes/SceneObjectPart.cs | 155 +++------------ OpenSim/Region/Framework/Scenes/UndoState.cs | 176 +++++++++++++++++- 2 files changed, 195 insertions(+), 136 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index c806fda5cc..f70b2597c6 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -263,8 +263,7 @@ namespace OpenSim.Region.Framework.Scenes private bool m_occupied; // KF if any av is sitting on this prim private string m_text = String.Empty; private string m_touchName = String.Empty; - private Stack m_undo = new Stack(5); - private Stack m_redo = new Stack(5); + private UndoRedoState m_UndoRedo = new UndoRedoState(5); private bool m_passTouches; @@ -1709,8 +1708,8 @@ namespace OpenSim.Region.Framework.Scenes dupe.Category = Category; dupe.m_rezzed = m_rezzed; - dupe.m_undo = new Stack(5); - dupe.m_redo = new Stack(5); + dupe.m_UndoRedo = new UndoRedoState(5); + dupe.IgnoreUndoUpdate = false; dupe.Undoing = false; @@ -3657,82 +3656,14 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.ScheduleGroupForTerseUpdate(); //ParentGroup.ScheduleGroupForFullUpdate(); } -/* - public void StoreUndoState() - { - StoreUndoState(false); - } - - public void StoreUndoState(bool forGroup) - { - if (!Undoing && !IgnoreUndoUpdate) // just to read better - undo is in progress, or suspended - { - if (ParentGroup != null) - { - lock (m_undo) - { - if (m_undo.Count > 0) - { - // see if we had a change - - UndoState last = m_undo.Peek(); - if (last != null) - { - if (last.Compare(this, forGroup)) - { - return; - } - } - } - - if (ParentGroup.GetSceneMaxUndo() > 0) - { - UndoState nUndo = new UndoState(this, forGroup); - - m_undo.Push(nUndo); - - if (m_redo.Count > 0) - m_redo.Clear(); - } - } - } - } - } -*/ - public void StoreUndoState(ObjectChangeWhat what) { - if (!Undoing && !IgnoreUndoUpdate) // just to read better - undo is in progress, or suspended + lock (m_UndoRedo) { - if (ParentGroup != null) + if (!Undoing && !IgnoreUndoUpdate && ParentGroup != null) // just to read better - undo is in progress, or suspended { - lock (m_undo) - { - if (m_undo.Count > 0) - { - // see if we had a change - - UndoState last = m_undo.Peek(); - if (last != null) - { - if (last.Compare(this, what)) - { - return; - } - } - } - - if (ParentGroup.GetSceneMaxUndo() > 0) - { - UndoState nUndo = new UndoState(this, what); - - m_undo.Push(nUndo); - - if (m_redo.Count > 0) - m_redo.Clear(); - } - } + m_UndoRedo.StoreUndo(this, what); } } } @@ -3744,84 +3675,42 @@ namespace OpenSim.Region.Framework.Scenes { get { - lock (m_undo) - return m_undo.Count; + lock (m_UndoRedo) + return m_UndoRedo.Count; } } public void Undo() { - lock (m_undo) + lock (m_UndoRedo) { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handling undo request for {0} {1}, stack size {2}", -// Name, LocalId, m_undo.Count); + if (Undoing || ParentGroup == null) + return; - if (m_undo.Count > 0) - { - UndoState goback = m_undo.Pop(); - - if (goback != null) - { - UndoState nUndo = null; - - if (ParentGroup.GetSceneMaxUndo() > 0) - { - nUndo = new UndoState(this, goback.data.what); - } - - goback.PlayState(this); - - if (nUndo != null) - m_redo.Push(nUndo); - } - } - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handled undo request for {0} {1}, stack size now {2}", -// Name, LocalId, m_undo.Count); + Undoing = true; + m_UndoRedo.Undo(this); + Undoing = false; } } public void Redo() { - lock (m_undo) + lock (m_UndoRedo) { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handling redo request for {0} {1}, stack size {2}", -// Name, LocalId, m_redo.Count); + if (Undoing || ParentGroup == null) + return; - if (m_redo.Count > 0) - { - UndoState gofwd = m_redo.Pop(); - - if (gofwd != null) - { - if (ParentGroup.GetSceneMaxUndo() > 0) - { - UndoState nUndo = new UndoState(this, gofwd.data.what); - - m_undo.Push(nUndo); - } - - gofwd.PlayState(this); - } - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}", -// Name, LocalId, m_redo.Count); - } + Undoing = true; + m_UndoRedo.Redo(this); + Undoing = false; } } public void ClearUndoState() { -// m_log.DebugFormat("[SCENE OBJECT PART]: Clearing undo and redo stacks in {0} {1}", Name, LocalId); - - lock (m_undo) + lock (m_UndoRedo) { - m_undo.Clear(); - m_redo.Clear(); + m_UndoRedo.Clear(); } } diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index eb76ca5bba..668b53b5bb 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs @@ -27,6 +27,7 @@ using System; using System.Reflection; +using System.Collections.Generic; using log4net; using OpenMetaverse; using OpenSim.Region.Framework.Interfaces; @@ -34,6 +35,8 @@ using System; namespace OpenSim.Region.Framework.Scenes { + +/* [Flags] public enum UndoType { @@ -48,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes STATE_ALL = 63 } -/* + public class UndoState { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -194,7 +197,10 @@ namespace OpenSim.Region.Framework.Scenes */ public class UndoState { + const int UNDOEXPIRESECONDS = 300; // undo expire time (nice to have it came from a ini later) + public ObjectChangeData data; + public DateTime creationtime; /// /// Constructor. /// @@ -204,8 +210,8 @@ namespace OpenSim.Region.Framework.Scenes public UndoState(SceneObjectPart part, ObjectChangeWhat what) { data = new ObjectChangeData(); - data.what = what; + creationtime = DateTime.UtcNow; if (part.ParentGroup.RootPart == part) { @@ -227,12 +233,25 @@ namespace OpenSim.Region.Framework.Scenes } } + public bool checkExpire() + { + TimeSpan t = DateTime.UtcNow - creationtime; + if (t.Seconds > UNDOEXPIRESECONDS) + return true; + return false; + } + + public void updateExpire() + { + creationtime = DateTime.UtcNow; + } + /// /// Compare the relevant state in the given part to this state. /// /// /// true if both the part's position, rotation and scale match those in this undo state. False otherwise. - public bool Compare(SceneObjectPart part, ObjectChangeWhat what) + public bool Compare(SceneObjectPart part, ObjectChangeWhat what) { if (data.what != what) // if diferent targets, then they are diferent return false; @@ -274,6 +293,157 @@ namespace OpenSim.Region.Framework.Scenes } } + public class UndoRedoState + { + int size; + public LinkedList m_redo = new LinkedList(); + public LinkedList m_undo = new LinkedList(); + + public UndoRedoState() + { + size = 5; + } + + public UndoRedoState(int _size) + { + if (_size < 3) + size = 3; + else + size = _size; + } + + public int Count + { + get { return m_undo.Count; } + } + + public void Clear() + { + m_undo.Clear(); + m_redo.Clear(); + } + + public void StoreUndo(SceneObjectPart part, ObjectChangeWhat what) + { + lock (m_undo) + { + UndoState last; + + if (m_redo.Count > 0) // last code seems to clear redo on every new undo + { + m_redo.Clear(); + } + + if (m_undo.Count > 0) + { + // check expired entry + last = m_undo.First.Value; + if (last != null && last.checkExpire()) + m_undo.Clear(); + else + { + // see if we actually have a change + if (last != null) + { + if (last.Compare(part, what)) + return; + } + } + } + + // limite size + while (m_undo.Count >= size) + m_undo.RemoveLast(); + + UndoState nUndo = new UndoState(part, what); + m_undo.AddFirst(nUndo); + } + } + + public void Undo(SceneObjectPart part) + { + lock (m_undo) + { + UndoState nUndo; + + // expire redo + if (m_redo.Count > 0) + { + nUndo = m_redo.First.Value; + if (nUndo != null && nUndo.checkExpire()) + m_redo.Clear(); + } + + if (m_undo.Count > 0) + { + UndoState goback = m_undo.First.Value; + // check expired + if (goback != null && goback.checkExpire()) + { + m_undo.Clear(); + return; + } + + if (goback != null) + { + m_undo.RemoveFirst(); + + // redo limite size + while (m_redo.Count >= size) + m_redo.RemoveLast(); + + nUndo = new UndoState(part, goback.data.what); // new value in part should it be full goback copy? + m_redo.AddFirst(nUndo); + + goback.PlayState(part); + } + } + } + } + + public void Redo(SceneObjectPart part) + { + lock (m_undo) + { + UndoState nUndo; + + // expire undo + if (m_undo.Count > 0) + { + nUndo = m_undo.First.Value; + if (nUndo != null && nUndo.checkExpire()) + m_undo.Clear(); + } + + if (m_redo.Count > 0) + { + UndoState gofwd = m_redo.First.Value; + // check expired + if (gofwd != null && gofwd.checkExpire()) + { + m_redo.Clear(); + return; + } + + if (gofwd != null) + { + m_redo.RemoveFirst(); + + // limite undo size + while (m_undo.Count >= size) + m_undo.RemoveLast(); + + nUndo = new UndoState(part, gofwd.data.what); // new value in part should it be full gofwd copy? + m_undo.AddFirst(nUndo); + + gofwd.PlayState(part); + } + } + } + } + + + } public class LandUndoState {