* Added basic 3-5 level undo on prim position/rotation/scale.
* In the future this should be a config option... and, hopefully this tides the builders over for a little while.0.6.0-stable
parent
7693a7dac9
commit
1fb54b074c
|
@ -570,6 +570,8 @@ namespace OpenSim.Framework
|
|||
event UUIDNameRequest OnTeleportHomeRequest;
|
||||
|
||||
event ScriptAnswer OnScriptAnswer;
|
||||
|
||||
event AgentSit OnUndo;
|
||||
|
||||
LLVector3 StartPos { get; set; }
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Undo stack. Deletes entries beyond a certain capacity
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[Serializable]
|
||||
public class UndoStack<T>
|
||||
{
|
||||
|
||||
private int m_new = 1;
|
||||
private int m_old = 0;
|
||||
private T[] m_Undos;
|
||||
|
||||
public bool IsFull
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_new == m_old;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int Capacity
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Undos.Length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public UndoStack(int capacity)
|
||||
{
|
||||
m_Undos = new T[capacity + 1];
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
if (IsFull)
|
||||
{
|
||||
m_old++;
|
||||
if (m_old >= m_Undos.Length)
|
||||
m_old -= m_Undos.Length;
|
||||
}
|
||||
if (++m_new >= m_Undos.Length)
|
||||
m_new -= m_Undos.Length;
|
||||
m_Undos[m_new] = item;
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
T deleted = m_Undos[m_new];
|
||||
m_Undos[m_new--] = default(T);
|
||||
if (m_new < 0)
|
||||
m_new += m_Undos.Length;
|
||||
return deleted;
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException("Cannot pop from emtpy stack");
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = m_new - m_old - 1;
|
||||
if (count < 0)
|
||||
count += m_Undos.Length;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
return m_Undos[m_new];
|
||||
}
|
||||
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
for (int i = 0; i < m_Undos.Length; i++)
|
||||
{
|
||||
m_Undos[i] = default(T);
|
||||
}
|
||||
m_new = 1;
|
||||
m_old = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -238,6 +238,7 @@ namespace OpenSim.Region.ClientStack
|
|||
private ScriptAnswer handlerScriptAnswer = null;
|
||||
private RequestPayPrice handlerRequestPayPrice = null;
|
||||
private ObjectDeselect handlerObjectDetach = null;
|
||||
private AgentSit handlerOnUndo = null;
|
||||
|
||||
/* Properties */
|
||||
|
||||
|
@ -799,6 +800,7 @@ namespace OpenSim.Region.ClientStack
|
|||
|
||||
public event ScriptAnswer OnScriptAnswer;
|
||||
public event RequestPayPrice OnRequestPayPrice;
|
||||
public event AgentSit OnUndo;
|
||||
|
||||
#region Scene/Avatar to Client
|
||||
|
||||
|
@ -3884,6 +3886,23 @@ namespace OpenSim.Region.ClientStack
|
|||
// That means multiple object perms may be updated in a single packet.
|
||||
|
||||
break;
|
||||
|
||||
case PacketType.Undo:
|
||||
UndoPacket undoitem = (UndoPacket)Pack;
|
||||
if (undoitem.ObjectData.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < undoitem.ObjectData.Length; i++)
|
||||
{
|
||||
LLUUID objiD = undoitem.ObjectData[i].ObjectID;
|
||||
handlerOnUndo = OnUndo;
|
||||
if (handlerOnUndo != null)
|
||||
{
|
||||
handlerOnUndo(this, objiD);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PacketType.ObjectDuplicateOnRay:
|
||||
ObjectDuplicateOnRayPacket dupeOnRay = (ObjectDuplicateOnRayPacket)Pack;
|
||||
|
||||
|
|
|
@ -312,6 +312,20 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public void HandleUndo(IClientAPI remoteClient, LLUUID primId)
|
||||
{
|
||||
if (primId != LLUUID.Zero)
|
||||
{
|
||||
SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
|
||||
if (part != null)
|
||||
part.Undo();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event Handling routine for Attach Object
|
||||
/// </summary>
|
||||
|
|
|
@ -78,6 +78,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
private readonly Mutex updateLock;
|
||||
public bool m_physicalPrim;
|
||||
public bool m_seeIntoRegionFromNeighbor;
|
||||
public int MaxUndoCount = 5;
|
||||
private int m_RestartTimerCounter;
|
||||
private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
|
||||
private int m_incrementsof15seconds = 0;
|
||||
|
@ -1628,6 +1629,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
client.OnTeleportHomeRequest += TeleportClientHome;
|
||||
|
||||
client.OnSetStartLocationRequest += SetHomeRezPoint;
|
||||
client.OnUndo += m_innerScene.HandleUndo;
|
||||
|
||||
EventManager.TriggerOnNewClient(client);
|
||||
}
|
||||
|
|
|
@ -378,6 +378,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
part.RegionHandle = m_regionHandle;
|
||||
|
||||
part.TrimPermissions();
|
||||
part.StoreUndoState();
|
||||
}
|
||||
break;
|
||||
case XmlNodeType.EndElement:
|
||||
|
@ -436,6 +437,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
SceneObjectPart Part = SceneObjectPart.FromXml(reader);
|
||||
AddPart(Part);
|
||||
Part.StoreUndoState();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -703,6 +705,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
m_rootPart.ApplyPhysics(m_rootPart.ObjectFlags, m_scene.m_physicalPrim);
|
||||
AttachToBackup();
|
||||
m_rootPart.ScheduleFullUpdate();
|
||||
m_rootPart.ClearUndoState();
|
||||
|
||||
}
|
||||
public void DetachToInventoryPrep()
|
||||
{
|
||||
|
@ -731,6 +735,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
private void SetPartAsNonRoot(SceneObjectPart part)
|
||||
{
|
||||
part.ParentID = m_rootPart.LocalId;
|
||||
part.ClearUndoState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -783,6 +788,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
try
|
||||
{
|
||||
m_parts.Add(part.UUID, part);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -803,6 +809,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
if (part.UUID != m_rootPart.UUID)
|
||||
{
|
||||
part.ParentID = m_rootPart.LocalId;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -815,10 +822,17 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
foreach (SceneObjectPart part in m_parts.Values)
|
||||
{
|
||||
part.UUID = LLUUID.Random();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper provided for parts.
|
||||
public int GetSceneMaxUndo()
|
||||
{
|
||||
if (m_scene != null)
|
||||
return m_scene.MaxUndoCount;
|
||||
return 5;
|
||||
}
|
||||
public void ResetChildPrimPhysicsPositions()
|
||||
{
|
||||
AbsolutePosition = AbsolutePosition;
|
||||
|
@ -845,12 +859,15 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
SceneObjectPart part = GetChildPart(localId);
|
||||
OnGrabPart(part, offsetPos, remoteClient);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnGrabPart(SceneObjectPart part, LLVector3 offsetPos, IClientAPI remoteClient)
|
||||
{
|
||||
part.StoreUndoState();
|
||||
part.OnGrab(offsetPos, remoteClient);
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnGrabGroup(LLVector3 offsetPos, IClientAPI remoteClient)
|
||||
|
@ -1382,8 +1399,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
m_parts.Add(newPart.UUID, newPart);
|
||||
}
|
||||
|
||||
|
||||
SetPartAsNonRoot(newPart);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1758,6 +1776,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
LinkNonRootPart(part, oldGroupPosition, oldRootRotation);
|
||||
}
|
||||
part.ClearUndoState();
|
||||
}
|
||||
|
||||
DetachFromBackup(objectGroup);
|
||||
|
@ -1781,7 +1800,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public void DelinkFromGroup(uint partID)
|
||||
{
|
||||
SceneObjectPart linkPart = GetChildPart(partID);
|
||||
|
||||
linkPart.ClearUndoState();
|
||||
if (null != linkPart)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Runtime.Serialization;
|
||||
|
@ -106,6 +107,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
[XmlIgnore] public LLVector3 m_attachedPos = LLVector3.Zero;
|
||||
[XmlIgnore] public LLUUID fromAssetID = LLUUID.Zero;
|
||||
|
||||
[XmlIgnore] public bool m_undoing = false;
|
||||
|
||||
public Int32 CreationDate;
|
||||
public uint ParentID = 0;
|
||||
|
||||
|
@ -123,6 +126,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public uint EveryoneMask = (uint)PermissionMask.None;
|
||||
public uint NextOwnerMask = (uint)PermissionMask.All;
|
||||
|
||||
private UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5);
|
||||
|
||||
public LLObject.ObjectFlags Flags = LLObject.ObjectFlags.None;
|
||||
|
||||
public uint ObjectFlags
|
||||
|
@ -266,6 +271,40 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
//return new LLQuaternion(axiomPartRotation.x, axiomPartRotation.y, axiomPartRotation.z, axiomPartRotation.w);
|
||||
|
||||
}
|
||||
|
||||
public void StoreUndoState()
|
||||
{
|
||||
if (!m_undoing)
|
||||
{
|
||||
if (m_parentGroup != null)
|
||||
{
|
||||
if (m_undo.Count > 0)
|
||||
{
|
||||
UndoState last = m_undo.Peek();
|
||||
if (last != null)
|
||||
{
|
||||
if (last.Compare(this))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_parentGroup.GetSceneMaxUndo() > 0)
|
||||
{
|
||||
UndoState nUndo = new UndoState(this);
|
||||
|
||||
m_undo.Push(nUndo);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearUndoState()
|
||||
{
|
||||
m_undo.Clear();
|
||||
StoreUndoState();
|
||||
}
|
||||
|
||||
public LLVector3 GroupPosition
|
||||
{
|
||||
|
@ -290,7 +329,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
return m_groupPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
{
|
||||
StoreUndoState();
|
||||
|
||||
m_groupPosition = value;
|
||||
|
||||
if (PhysActor != null)
|
||||
|
@ -334,7 +375,10 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public LLVector3 OffsetPosition
|
||||
{
|
||||
get { return m_offsetPosition; }
|
||||
set { m_offsetPosition = value;
|
||||
set
|
||||
{
|
||||
StoreUndoState();
|
||||
m_offsetPosition = value;
|
||||
try
|
||||
{
|
||||
// Hack to get the child prim to update world positions in the physics engine
|
||||
|
@ -380,6 +424,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
set
|
||||
{
|
||||
StoreUndoState();
|
||||
m_rotationOffset = value;
|
||||
|
||||
if (PhysActor != null)
|
||||
|
@ -650,7 +695,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
get { return m_shape.Scale; }
|
||||
set
|
||||
{
|
||||
{
|
||||
StoreUndoState();
|
||||
m_shape.Scale = value;
|
||||
TriggerScriptChangedEvent(Changed.SCALE);
|
||||
}
|
||||
|
@ -759,7 +805,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
LLObject.ObjectFlags.CreateSelected;
|
||||
|
||||
TrimPermissions();
|
||||
|
||||
//m_undo = new UndoStack<UndoState>(ParentGroup.GetSceneMaxUndo());
|
||||
|
||||
ScheduleFullUpdate();
|
||||
}
|
||||
|
||||
|
@ -802,7 +849,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
TrimPermissions();
|
||||
// ApplyPhysics();
|
||||
|
||||
|
||||
ScheduleFullUpdate();
|
||||
}
|
||||
|
||||
|
@ -1982,6 +2029,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
public void UpdateRotation(LLQuaternion rot)
|
||||
{
|
||||
//StoreUndoState();
|
||||
RotationOffset = new LLQuaternion(rot.X, rot.Y, rot.Z, rot.W);
|
||||
ScheduleTerseUpdate();
|
||||
}
|
||||
|
@ -2097,6 +2145,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// <param name="scale"></param>
|
||||
public void Resize(LLVector3 scale)
|
||||
{
|
||||
StoreUndoState();
|
||||
m_shape.Scale = scale;
|
||||
|
||||
ScheduleFullUpdate();
|
||||
|
@ -2522,5 +2571,15 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
info.AddValue("PayPrice", PayPrice);
|
||||
}
|
||||
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (m_undo.Count > 0)
|
||||
{
|
||||
UndoState goback = m_undo.Pop();
|
||||
if (goback != null)
|
||||
goback.PlaybackState(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using libsecondlife;
|
||||
|
||||
namespace OpenSim.Region.Environment.Scenes
|
||||
{
|
||||
public class UndoState
|
||||
{
|
||||
public LLVector3 Position = LLVector3.Zero;
|
||||
public LLVector3 Scale = LLVector3.Zero;
|
||||
public LLQuaternion Rotation = LLQuaternion.Identity;
|
||||
|
||||
public UndoState(LLVector3 pos, LLQuaternion rot, LLVector3 scale)
|
||||
{
|
||||
Position = pos;
|
||||
Rotation = rot;
|
||||
Scale = scale;
|
||||
}
|
||||
|
||||
public UndoState(SceneObjectPart part)
|
||||
{
|
||||
if (part != null)
|
||||
{
|
||||
if (part.ParentID == 0)
|
||||
{
|
||||
Position = part.AbsolutePosition;
|
||||
Rotation = part.RotationOffset;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Position = part.GroupPosition;
|
||||
Rotation = part.RotationOffset;
|
||||
Scale = part.Shape.Scale;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Compare(SceneObjectPart part)
|
||||
{
|
||||
if (part != null)
|
||||
{
|
||||
if (part.ParentID == 0)
|
||||
{
|
||||
if (Position == part.AbsolutePosition && Rotation == part.RotationOffset)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Position == part.GroupPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void PlaybackState(SceneObjectPart part)
|
||||
{
|
||||
if (part != null)
|
||||
{
|
||||
part.m_undoing = true;
|
||||
|
||||
if (part.ParentID == 0)
|
||||
{
|
||||
part.ParentGroup.AbsolutePosition = Position;
|
||||
part.UpdateRotation(Rotation);
|
||||
part.ParentGroup.ScheduleGroupForTerseUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
part.OffsetPosition = Position;
|
||||
part.UpdateRotation(Rotation);
|
||||
part.Resize(Scale);
|
||||
part.ScheduleTerseUpdate();
|
||||
}
|
||||
part.m_undoing = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public UndoState()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -171,6 +171,7 @@ namespace OpenSim.Region.Examples.SimpleModule
|
|||
|
||||
public event ScriptAnswer OnScriptAnswer;
|
||||
public event RequestPayPrice OnRequestPayPrice;
|
||||
public event AgentSit OnUndo;
|
||||
|
||||
|
||||
#pragma warning restore 67
|
||||
|
|
Loading…
Reference in New Issue