mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-26 22:01:45 +00:00
even better copy/pasting
This commit is contained in:
parent
5a47093999
commit
8d3d00372b
8 changed files with 250 additions and 88 deletions
|
@ -83,7 +83,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// This occurs when the user presses Copy. All selected geometry must be marked for copying!
|
||||
public override bool OnCopyBegin()
|
||||
{
|
||||
General.Map.Map.MarkAllSelectedGeometry(true);
|
||||
General.Map.Map.MarkAllSelectedGeometry(true, false);
|
||||
|
||||
// Return true when anything is selected so that the copy continues
|
||||
// We only have to check vertices for the geometry, because without selected
|
||||
|
|
|
@ -685,6 +685,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
// Update
|
||||
UpdateRectangleComponents();
|
||||
Update();
|
||||
|
||||
// When pasting and mouse is in screen, drag selection immediately
|
||||
if(pasting && mouseinside) OnSelect();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -736,11 +740,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
// Make undo
|
||||
General.Map.UndoRedo.CreateUndo("Edit selection", UndoGroup.None, 0);
|
||||
|
||||
// Mark the selected geometry
|
||||
|
||||
// Mark selected geometry
|
||||
General.Map.Map.ClearAllMarks(false);
|
||||
General.Map.Map.MarkAllSelectedGeometry(true);
|
||||
|
||||
General.Map.Map.MarkAllSelectedGeometry(true, false);
|
||||
|
||||
// Move geometry to new position
|
||||
UpdateGeometry();
|
||||
General.Map.Map.Update(true, true);
|
||||
|
@ -752,21 +756,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.Map.SnapAllToAccuracy();
|
||||
|
||||
// When pasting, we want to join with the parent sector
|
||||
// where the sidedefs are referencing a virtual sector
|
||||
if(pasting)
|
||||
{
|
||||
General.Settings.FindDefaultDrawSettings();
|
||||
|
||||
// Go for all linedefs in the new geometry
|
||||
ICollection<Linedef> newlines = General.Map.Map.GetMarkedLinedefs(true);
|
||||
foreach(Linedef l in newlines)
|
||||
List<Sidedef> newsides = General.Map.Map.GetMarkedSidedefs(true);
|
||||
for(int i = 0; i < newsides.Count; i++)
|
||||
{
|
||||
// Missing sector on the front?
|
||||
if((l.Front == null) && l.Marked)
|
||||
Sidedef s = newsides[i];
|
||||
|
||||
// Connected to a virtual sector?
|
||||
if(s.Marked && s.Sector.Fields.ContainsKey(MapSet.VirtualSectorField))
|
||||
{
|
||||
bool joined = false;
|
||||
|
||||
// Find a way to join a sector here
|
||||
List<LinedefSide> sectorlines = SectorTools.FindPotentialSectorAt(l, true);
|
||||
List<LinedefSide> sectorlines = SectorTools.FindPotentialSectorAt(s.Line, s.IsFront);
|
||||
if(sectorlines != null)
|
||||
{
|
||||
// We don't always want to join a sector
|
||||
|
@ -774,12 +781,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
Sidedef joinsidedef = null;
|
||||
foreach(LinedefSide ls in sectorlines)
|
||||
{
|
||||
if(ls.Front && (ls.Line.Front != null))
|
||||
if(ls.Front && (ls.Line.Front != null) && !ls.Line.Front.Marked)
|
||||
{
|
||||
joinsidedef = ls.Line.Front;
|
||||
break;
|
||||
}
|
||||
else if(!ls.Front && (ls.Line.Back != null))
|
||||
else if(!ls.Front && (ls.Line.Back != null) && !ls.Line.Back.Marked)
|
||||
{
|
||||
joinsidedef = ls.Line.Back;
|
||||
break;
|
||||
|
@ -793,63 +800,34 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
Sector newsector = SectorTools.JoinSector(sectorlines, joinsidedef);
|
||||
joined = true;
|
||||
|
||||
// Remove mark from linedefs so that it is not used to join a sector again
|
||||
foreach(Sidedef sd in newsector.Sidedefs) sd.Line.Marked = false;
|
||||
// Remove mark from sidedefs so that it is not used to join a sector again
|
||||
foreach(Sidedef sd in newsector.Sidedefs) sd.Marked = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Not joined any sector?
|
||||
if(!joined)
|
||||
{
|
||||
// Flip the linedef and correct the sided flags
|
||||
l.FlipVertices();
|
||||
l.FlipSidedefs();
|
||||
Linedef l = s.Line;
|
||||
|
||||
// Remove the sidedef
|
||||
s.Dispose();
|
||||
|
||||
// Correct the linedef
|
||||
if((l.Front == null) && (l.Back != null))
|
||||
{
|
||||
l.FlipVertices();
|
||||
l.FlipSidedefs();
|
||||
}
|
||||
|
||||
// Correct the sided flags
|
||||
l.ApplySidedFlags();
|
||||
}
|
||||
}
|
||||
|
||||
// Missing sector on the back?
|
||||
if((l.Back == null) && l.Marked && l.IsFlagSet(General.Map.Config.DoubleSidedFlag))
|
||||
{
|
||||
bool joined = false;
|
||||
|
||||
// Find a way to join a sector here
|
||||
List<LinedefSide> sectorlines = SectorTools.FindPotentialSectorAt(l, false);
|
||||
if(sectorlines != null)
|
||||
{
|
||||
// We don't always want to join a sector
|
||||
// So first check if any of the surrounding lines originally have sidedefs
|
||||
Sidedef joinsidedef = null;
|
||||
foreach(LinedefSide ls in sectorlines)
|
||||
{
|
||||
if(ls.Front && (ls.Line.Front != null))
|
||||
{
|
||||
joinsidedef = ls.Line.Front;
|
||||
break;
|
||||
}
|
||||
else if(!ls.Front && (ls.Line.Back != null))
|
||||
{
|
||||
joinsidedef = ls.Line.Back;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Join?
|
||||
if(joinsidedef != null)
|
||||
{
|
||||
// Join the new sector
|
||||
Sector newsector = SectorTools.JoinSector(sectorlines, joinsidedef);
|
||||
joined = true;
|
||||
|
||||
// Remove mark from linedefs so that it is not used to join a sector again
|
||||
foreach(Sidedef sd in newsector.Sidedefs) sd.Line.Marked = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Correct the sided flags if not joined a sector
|
||||
if(!joined) l.ApplySidedFlags();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any virtual sectors
|
||||
General.Map.Map.RemoveVirtualSectors();
|
||||
}
|
||||
|
||||
// Update cached values
|
||||
|
|
|
@ -99,18 +99,15 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
// that need to be copied.
|
||||
if(General.Map.Mode.OnCopyBegin())
|
||||
{
|
||||
// Get all marked elements
|
||||
ICollection<Vertex> verts = General.Map.Map.GetMarkedVertices(true);
|
||||
ICollection<Sidedef> sides = General.Map.Map.GetMarkedSidedefs(true);
|
||||
ICollection<Sector> sectors = General.Map.Map.GetMarkedSectors(true);
|
||||
ICollection<Linedef> lines = General.Map.Map.GetMarkedLinedefs(true);
|
||||
ICollection<Thing> things = General.Map.Map.GetMarkedThings(true);
|
||||
|
||||
// Copy the marked geometry
|
||||
// This links sidedefs that are not linked to a marked sector to a virtual sector
|
||||
MapSet copyset = General.Map.Map.CloneMarked();
|
||||
|
||||
// Write data to stream
|
||||
MemoryStream memstream = new MemoryStream();
|
||||
UniversalStreamWriter writer = new UniversalStreamWriter();
|
||||
writer.RememberCustomTypes = false;
|
||||
writer.Write(verts, lines, sides, sectors, things, memstream, null);
|
||||
writer.Write(copyset, memstream, null);
|
||||
|
||||
// Set on clipboard
|
||||
Clipboard.SetData(CLIPBOARD_DATA_FORMAT, memstream);
|
||||
|
@ -151,6 +148,7 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
|
||||
// Read data stream
|
||||
UniversalStreamReader reader = new UniversalStreamReader();
|
||||
reader.StrictChecking = false;
|
||||
reader.Read(General.Map.Map, memstream);
|
||||
|
||||
// The new geometry is not marked, so invert the marks to get it marked
|
||||
|
|
|
@ -503,21 +503,33 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
{
|
||||
if(ls.Front)
|
||||
{
|
||||
// Create sidedef is needed and ensure it points to the new sector
|
||||
// Create sidedef if needed
|
||||
if(ls.Line.Front == null)
|
||||
{
|
||||
General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
|
||||
ApplyDefaultsToSidedef(ls.Line.Front, sourceside);
|
||||
}
|
||||
// Added 23-9-08, can we do this or will it break things?
|
||||
else
|
||||
{
|
||||
// Link to the new sector
|
||||
ls.Line.Front.ChangeSector(original.Sector);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create sidedef is needed and ensure it points to the new sector
|
||||
// Create sidedef if needed
|
||||
if(ls.Line.Back == null)
|
||||
{
|
||||
General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
|
||||
ApplyDefaultsToSidedef(ls.Line.Back, sourceside);
|
||||
}
|
||||
// Added 23-9-08, can we do this or will it break things?
|
||||
else
|
||||
{
|
||||
// Link to the new sector
|
||||
ls.Line.Back.ChangeSector(original.Sector);
|
||||
}
|
||||
}
|
||||
|
||||
// Update line
|
||||
|
|
|
@ -65,6 +65,9 @@ namespace CodeImp.DoomBuilder.IO
|
|||
|
||||
// Configuration root
|
||||
private UniversalCollection root = null;
|
||||
|
||||
// Settings
|
||||
private bool strictchecking = true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -75,6 +78,7 @@ namespace CodeImp.DoomBuilder.IO
|
|||
public string ErrorDescription { get { return cpErrorDescription; } }
|
||||
public int ErrorLine { get { return cpErrorLine; } }
|
||||
public UniversalCollection Root { get { return root; } }
|
||||
public bool StrictChecking { get { return strictchecking; } set { strictchecking = value; } }
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -144,15 +148,19 @@ namespace CodeImp.DoomBuilder.IO
|
|||
}
|
||||
else
|
||||
{
|
||||
// Check if all characters are valid
|
||||
foreach(char c in key)
|
||||
// Only when strict checking
|
||||
if(strictchecking)
|
||||
{
|
||||
if(KEY_CHARACTERS.IndexOf(c) == -1)
|
||||
// Check if all characters are valid
|
||||
foreach(char c in key)
|
||||
{
|
||||
// ERROR: Invalid characters in key name
|
||||
if(errorline > -1) RaiseError(errorline, ERROR_KEYCHARACTERS);
|
||||
validateresult = false;
|
||||
break;
|
||||
if(KEY_CHARACTERS.IndexOf(c) == -1)
|
||||
{
|
||||
// ERROR: Invalid characters in key name
|
||||
if(errorline > -1) RaiseError(errorline, ERROR_KEYCHARACTERS);
|
||||
validateresult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,12 +45,14 @@ namespace CodeImp.DoomBuilder.IO
|
|||
|
||||
private Configuration config;
|
||||
private bool setknowncustomtypes;
|
||||
private bool strictchecking = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public bool SetKnownCustomTypes { get { return setknowncustomtypes; } set { setknowncustomtypes = value; } }
|
||||
public bool StrictChecking { get { return strictchecking; } set { strictchecking = value; } }
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -111,7 +113,8 @@ namespace CodeImp.DoomBuilder.IO
|
|||
Dictionary<int, Vertex> vertexlink;
|
||||
Dictionary<int, Sector> sectorlink;
|
||||
UniversalParser textmap = new UniversalParser();
|
||||
|
||||
textmap.StrictChecking = strictchecking;
|
||||
|
||||
try
|
||||
{
|
||||
// Read UDMF from stream
|
||||
|
|
|
@ -28,6 +28,7 @@ using SlimDX;
|
|||
using System.Drawing;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -43,6 +44,12 @@ namespace CodeImp.DoomBuilder.Map
|
|||
// Stiching distance
|
||||
public const float STITCH_DISTANCE = 0.001f;
|
||||
|
||||
// Virtual sector identification
|
||||
// This contains a character that is invalid in the UDMF standard, but valid
|
||||
// in our parser, so that it can only be used by Doom Builder and will never
|
||||
// conflict with any other valid UDMF field.
|
||||
internal const string VIRTUAL_SECTOR_FIELD = "!virtual_sector";
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
@ -58,8 +65,9 @@ namespace CodeImp.DoomBuilder.Map
|
|||
private LinkedList<Sector> sectors;
|
||||
private LinkedList<Thing> things;
|
||||
|
||||
// Optimization
|
||||
// Statics
|
||||
private static long emptylongname;
|
||||
private static UniValue virtualsectorvalue;
|
||||
|
||||
// Disposing
|
||||
private bool isdisposed = false;
|
||||
|
@ -74,7 +82,10 @@ namespace CodeImp.DoomBuilder.Map
|
|||
public ICollection<Sector> Sectors { get { return sectors; } }
|
||||
public ICollection<Thing> Things { get { return things; } }
|
||||
public bool IsDisposed { get { return isdisposed; } }
|
||||
|
||||
public static long EmptyLongName { get { return emptylongname; } }
|
||||
public static string VirtualSectorField { get { return VIRTUAL_SECTOR_FIELD; } }
|
||||
public static UniValue VirtualSectorValue { get { return virtualsectorvalue; } }
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -144,6 +155,7 @@ namespace CodeImp.DoomBuilder.Map
|
|||
internal static void Initialize()
|
||||
{
|
||||
emptylongname = Lump.MakeLongName("-");
|
||||
virtualsectorvalue = new UniValue((int)UniversalType.Integer, (int)0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -214,6 +226,116 @@ namespace CodeImp.DoomBuilder.Map
|
|||
// Return the new set
|
||||
return newset;
|
||||
}
|
||||
|
||||
// This makes a deep copy of the marked geometry and binds missing sectors to a virtual sector
|
||||
internal MapSet CloneMarked()
|
||||
{
|
||||
Sector virtualsector = null;
|
||||
|
||||
// Create the map set
|
||||
MapSet newset = new MapSet();
|
||||
|
||||
// Get marked geometry
|
||||
ICollection<Vertex> mvertices = GetMarkedVertices(true);
|
||||
ICollection<Linedef> mlinedefs = GetMarkedLinedefs(true);
|
||||
ICollection<Sector> msectors = GetMarkedSectors(true);
|
||||
ICollection<Thing> mthings = GetMarkedThings(true);
|
||||
|
||||
// Go for all vertices
|
||||
foreach(Vertex v in mvertices)
|
||||
{
|
||||
// Make new vertex
|
||||
v.Clone = newset.CreateVertex(v.Position);
|
||||
v.CopyPropertiesTo(v.Clone);
|
||||
}
|
||||
|
||||
// Go for all sectors
|
||||
foreach(Sector s in msectors)
|
||||
{
|
||||
// Make new sector
|
||||
s.Clone = newset.CreateSector();
|
||||
s.CopyPropertiesTo(s.Clone);
|
||||
}
|
||||
|
||||
// Go for all linedefs
|
||||
foreach(Linedef l in mlinedefs)
|
||||
{
|
||||
// Make new linedef
|
||||
Linedef nl = newset.CreateLinedef(l.Start.Clone, l.End.Clone);
|
||||
l.CopyPropertiesTo(nl);
|
||||
|
||||
// Linedef has a front side?
|
||||
if(l.Front != null)
|
||||
{
|
||||
Sidedef nd;
|
||||
|
||||
// Sector on front side marked?
|
||||
if(l.Front.Sector.Marked)
|
||||
{
|
||||
// Make new sidedef
|
||||
nd = newset.CreateSidedef(nl, true, l.Front.Sector.Clone);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make virtual sector if needed
|
||||
if(virtualsector == null)
|
||||
{
|
||||
virtualsector = newset.CreateSector();
|
||||
l.Front.Sector.CopyPropertiesTo(virtualsector);
|
||||
virtualsector.Fields[VIRTUAL_SECTOR_FIELD] = new UniValue(virtualsectorvalue);
|
||||
}
|
||||
|
||||
// Make new sidedef that links to the virtual sector
|
||||
nd = newset.CreateSidedef(nl, true, virtualsector);
|
||||
}
|
||||
|
||||
l.Front.CopyPropertiesTo(nd);
|
||||
}
|
||||
|
||||
// Linedef has a back side?
|
||||
if(l.Back != null)
|
||||
{
|
||||
Sidedef nd;
|
||||
|
||||
// Sector on front side marked?
|
||||
if(l.Back.Sector.Marked)
|
||||
{
|
||||
// Make new sidedef
|
||||
nd = newset.CreateSidedef(nl, false, l.Back.Sector.Clone);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make virtual sector if needed
|
||||
if(virtualsector == null)
|
||||
{
|
||||
virtualsector = newset.CreateSector();
|
||||
l.Back.Sector.CopyPropertiesTo(virtualsector);
|
||||
virtualsector.Fields[VIRTUAL_SECTOR_FIELD] = new UniValue(virtualsectorvalue);
|
||||
}
|
||||
|
||||
// Make new sidedef that links to the virtual sector
|
||||
nd = newset.CreateSidedef(nl, false, virtualsector);
|
||||
}
|
||||
|
||||
l.Back.CopyPropertiesTo(nd);
|
||||
}
|
||||
}
|
||||
|
||||
// Go for all things
|
||||
foreach(Thing t in mthings)
|
||||
{
|
||||
// Make new thing
|
||||
Thing nt = newset.CreateThing();
|
||||
t.CopyPropertiesTo(nt);
|
||||
}
|
||||
|
||||
// Remove clone references
|
||||
foreach(Vertex v in vertices) v.Clone = null;
|
||||
foreach(Sector s in sectors) s.Clone = null;
|
||||
|
||||
// Return the new set
|
||||
return newset;
|
||||
}
|
||||
|
||||
// This creates a new vertex
|
||||
public Vertex CreateVertex(Vector2D pos)
|
||||
|
@ -713,9 +835,12 @@ namespace CodeImp.DoomBuilder.Map
|
|||
return list;
|
||||
}
|
||||
|
||||
// This marks all selected geometry, including sidedefs from sectors
|
||||
// Returns the number of selected elements
|
||||
public void MarkAllSelectedGeometry(bool mark)
|
||||
/// <summary>
|
||||
/// This marks all selected geometry, including sidedefs from sectors.
|
||||
/// When sidedefsfromsectors is true, then the sidedefs are marked according to the
|
||||
/// marked sectors. Otherwise the sidedefs are marked according to the marked linedefs.
|
||||
/// </summary>
|
||||
public void MarkAllSelectedGeometry(bool mark, bool sidedefsfromsectors)
|
||||
{
|
||||
General.Map.Map.ClearAllMarks(!mark);
|
||||
|
||||
|
@ -725,14 +850,15 @@ namespace CodeImp.DoomBuilder.Map
|
|||
// Direct linedefs
|
||||
General.Map.Map.MarkSelectedLinedefs(true, mark);
|
||||
|
||||
// Linedefs from vertices
|
||||
// We do this before "vertices from lines" because otherwise we get lines marked that we didn't select
|
||||
ICollection<Linedef> lines = General.Map.Map.LinedefsFromMarkedVertices(!mark, mark, !mark);
|
||||
foreach(Linedef l in lines) l.Marked = mark;
|
||||
|
||||
// Vertices from linedefs
|
||||
ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(mark);
|
||||
foreach(Vertex v in verts) v.Marked = mark;
|
||||
|
||||
// Linedefs from vertices
|
||||
ICollection<Linedef> lines = General.Map.Map.LinedefsFromMarkedVertices(!mark, mark, !mark);
|
||||
foreach(Linedef l in lines) l.Marked = mark;
|
||||
|
||||
// Mark sectors from linedefs (note: this must be the first to mark
|
||||
// sectors, because this clears the sector marks!)
|
||||
General.Map.Map.ClearMarkedSectors(mark);
|
||||
|
@ -751,9 +877,11 @@ namespace CodeImp.DoomBuilder.Map
|
|||
// Direct things
|
||||
General.Map.Map.MarkSelectedThings(true, mark);
|
||||
|
||||
// Sidedefs from linedefs
|
||||
//General.Map.Map.MarkSidedefsFromLinedefs(true, mark);
|
||||
General.Map.Map.MarkSidedefsFromSectors(true, mark);
|
||||
// Sidedefs from linedefs or sectors
|
||||
if(sidedefsfromsectors)
|
||||
General.Map.Map.MarkSidedefsFromSectors(true, mark);
|
||||
else
|
||||
General.Map.Map.MarkSidedefsFromLinedefs(true, mark);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -922,6 +1050,31 @@ namespace CodeImp.DoomBuilder.Map
|
|||
|
||||
#region ================== Geometry Tools
|
||||
|
||||
// This removes any virtual sectors in the map
|
||||
// Returns the number of sectors removed
|
||||
public int RemoveVirtualSectors()
|
||||
{
|
||||
int count = 0;
|
||||
LinkedListNode<Sector> n = sectors.First;
|
||||
|
||||
// Go for all sectors
|
||||
while(n != null)
|
||||
{
|
||||
LinkedListNode<Sector> nn = n.Next;
|
||||
|
||||
// Remove when virtual
|
||||
if(n.Value.Fields.ContainsKey(VIRTUAL_SECTOR_FIELD))
|
||||
{
|
||||
n.Value.Dispose();
|
||||
count++;
|
||||
}
|
||||
|
||||
n = nn;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// This joins overlapping lines together
|
||||
// Returns the number of joins made
|
||||
public static int JoinOverlappingLines(ICollection<Linedef> lines)
|
||||
|
|
|
@ -81,6 +81,16 @@ namespace CodeImp.DoomBuilder.Map
|
|||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Constructor
|
||||
public UniValue(UniValue v)
|
||||
{
|
||||
this.type = v.type;
|
||||
this.value = v.value;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Constructor
|
||||
public UniValue()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue