Added maximum number of map element checks (now you can't corrupt your map when exceeding the format's limits)

This commit is contained in:
codeimp 2010-08-15 19:43:00 +00:00
parent 9934ddad25
commit 7f685b4c77
19 changed files with 433 additions and 201 deletions

View file

@ -289,12 +289,22 @@ namespace CodeImp.DoomBuilder.Editing
if(options.ChangeTags == PasteOptions.TAGS_RENUMBER) Tools.RenumberMarkedTags();
if(options.RemoveActions) Tools.RemoveMarkedActions();
// Done
// Clean up
memstream.Dispose();
General.Map.Map.UpdateConfiguration();
General.Map.ThingsFilter.Update();
General.Editing.Mode.OnPasteEnd(options.Copy());
General.Plugins.OnPasteEnd(options);
// Check if anything was pasted
int totalpasted = General.Map.Map.GetMarkedThings(true).Count;
totalpasted += General.Map.Map.GetMarkedVertices(true).Count;
totalpasted += General.Map.Map.GetMarkedLinedefs(true).Count;
totalpasted += General.Map.Map.GetMarkedSidedefs(true).Count;
totalpasted += General.Map.Map.GetMarkedSectors(true).Count;
if(totalpasted > 0)
{
General.Map.Map.UpdateConfiguration();
General.Map.ThingsFilter.Update();
General.Editing.Mode.OnPasteEnd(options.Copy());
General.Plugins.OnPasteEnd(options);
}
return true;
}
}

View file

@ -571,7 +571,7 @@ namespace CodeImp.DoomBuilder.Editing
General.Plugins.OnUndoWithdrawn();
}
// This performs an undo
[BeginAction("undo")]
public void PerformUndo()

View file

@ -501,6 +501,34 @@ namespace CodeImp.DoomBuilder
return false;
}
}
// Check things
if(map.Things.Count > io.MaxThings)
{
General.ShowErrorMessage("Unable to save the map: There are too many things!", MessageBoxButtons.OK);
return false;
}
// Check sectors
if(map.Sectors.Count > io.MaxSectors)
{
General.ShowErrorMessage("Unable to save the map: There are too many sectors!", MessageBoxButtons.OK);
return false;
}
// Check linedefs
if(map.Linedefs.Count > io.MaxLinedefs)
{
General.ShowErrorMessage("Unable to save the map: There are too many linedefs!", MessageBoxButtons.OK);
return false;
}
// Check vertices
if(map.Vertices.Count > io.MaxVertices)
{
General.ShowErrorMessage("Unable to save the map: There are too many vertices!", MessageBoxButtons.OK);
return false;
}
// TODO: Check for more limitations

View file

@ -23,6 +23,7 @@ using System.Globalization;
using System.Text;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Windows;
using SlimDX;
using SlimDX.Direct3D9;
using System.Drawing;
@ -453,12 +454,18 @@ namespace CodeImp.DoomBuilder.Geometry
// If nearbylines is not null, then this method will find the default
// properties from the nearest line in this collection when the
// default properties can't be found in the alllines collection.
// Return null when no new sector could be made.
public static Sector MakeSector(List<LinedefSide> alllines, List<Linedef> nearbylines)
{
Sector newsector = General.Map.Map.CreateSector();
Sector sourcesector = null;
SidedefSettings sourceside = new SidedefSettings();
bool foundsidedefaults = false;
if(General.Map.Map.Sectors.Count >= General.Map.FormatInterface.MaxSectors)
return null;
Sector newsector = General.Map.Map.CreateSector();
if(newsector == null) return null;
// Check if any of the sides already has a sidedef
// Then we use information from that sidedef to make the others
@ -565,6 +572,7 @@ namespace CodeImp.DoomBuilder.Geometry
{
// Create sidedef is needed and ensure it points to the new sector
if(ls.Line.Front == null) General.Map.Map.CreateSidedef(ls.Line, true, newsector);
if(ls.Line.Front == null) return null;
if(ls.Line.Front.Sector != newsector) ls.Line.Front.SetSector(newsector);
ApplyDefaultsToSidedef(ls.Line.Front, sourceside);
}
@ -572,6 +580,7 @@ namespace CodeImp.DoomBuilder.Geometry
{
// Create sidedef is needed and ensure it points to the new sector
if(ls.Line.Back == null) General.Map.Map.CreateSidedef(ls.Line, false, newsector);
if(ls.Line.Back == null) return null;
if(ls.Line.Back.Sector != newsector) ls.Line.Back.SetSector(newsector);
ApplyDefaultsToSidedef(ls.Line.Back, sourceside);
}
@ -591,7 +600,7 @@ namespace CodeImp.DoomBuilder.Geometry
}
// This joins a sector with the given lines and sides
// This joins a sector with the given lines and sides. Returns null when operation could not be completed.
public static Sector JoinSector(List<LinedefSide> alllines, Sidedef original)
{
SidedefSettings sourceside = new SidedefSettings();
@ -610,7 +619,8 @@ namespace CodeImp.DoomBuilder.Geometry
// Create sidedef if needed
if(ls.Line.Front == null)
{
General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
Sidedef sd = General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
if(sd == null) return null;
ApplyDefaultsToSidedef(ls.Line.Front, sourceside);
ls.Line.ApplySidedFlags();
@ -629,7 +639,8 @@ namespace CodeImp.DoomBuilder.Geometry
// Create sidedef if needed
if(ls.Line.Back == null)
{
General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
Sidedef sd = General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
if(sd == null) return null;
ApplyDefaultsToSidedef(ls.Line.Back, sourceside);
ls.Line.ApplySidedFlags();
@ -821,8 +832,9 @@ namespace CodeImp.DoomBuilder.Geometry
/// <summary>
/// This draws lines with the given points. Note that this tool removes any existing geometry
/// marks and marks the new lines and vertices when done. Also marks the sectors that were added.
/// Returns false when the drawing failed.
/// </summary>
public static void DrawLines(IList<DrawnVertex> points)
public static bool DrawLines(IList<DrawnVertex> points)
{
List<Vertex> newverts = new List<Vertex>();
List<Vertex> intersectverts = new List<Vertex>();
@ -845,6 +857,7 @@ namespace CodeImp.DoomBuilder.Geometry
// Make first vertex
Vertex v1 = map.CreateVertex(points[0].pos);
if(v1 == null) return false;
v1.Marked = true;
// Keep references
@ -856,6 +869,7 @@ namespace CodeImp.DoomBuilder.Geometry
{
// Create vertex for point
Vertex v2 = map.CreateVertex(points[i].pos);
if(v2 == null) return false;
v2.Marked = true;
// Keep references
@ -864,6 +878,7 @@ namespace CodeImp.DoomBuilder.Geometry
// Create line between point and previous
Linedef ld = map.CreateLinedef(v1, v2);
if(ld == null) return false;
ld.Marked = true;
ld.ApplySidedFlags();
ld.UpdateCache();
@ -902,16 +917,18 @@ namespace CodeImp.DoomBuilder.Geometry
// Make the vertex
Vertex splitvertex = map.CreateVertex(splitpoint);
if(splitvertex == null) return false;
splitvertex.Marked = true;
newverts.Add(splitvertex);
mergeverts.Add(splitvertex); // <-- add to merge?
intersectverts.Add(splitvertex);
// The Split method ties the end of the original line to the given
// vertex and starts a new line at the given vertex, so continue
// splitting with the new line, because the intersections are sorted
// from low to high (beginning at the original line start)
splitline = splitline.Split(splitvertex);
if(splitline == null) return false;
splitline.ApplySidedFlags();
newlines.Add(splitline);
}
@ -1116,11 +1133,13 @@ namespace CodeImp.DoomBuilder.Geometry
// Make the new vertex
Vertex v2 = map.CreateVertex(v2pos);
if(v2 == null) return false;
v2.Marked = true;
mergeverts.Add(v2);
// Make the line
Linedef ld = map.CreateLinedef(v1, v2);
if(ld == null) return false;
ld.Marked = true;
ld.ApplySidedFlags();
ld.UpdateCache();
@ -1137,6 +1156,8 @@ namespace CodeImp.DoomBuilder.Geometry
else
lld = map.CreateLinedef(v1, firstline.Start);
if(lld == null) return false;
// Setup line
lld.Marked = true;
lld.ApplySidedFlags();
@ -1282,6 +1303,8 @@ namespace CodeImp.DoomBuilder.Geometry
{
// Make the new sector
Sector newsector = Tools.MakeSector(sectorlines, oldlines);
if(newsector == null) return false;
if(istruenewsector) newsector.Marked = true;
// Go for all sidedefs in this new sector
@ -1354,7 +1377,8 @@ namespace CodeImp.DoomBuilder.Geometry
}
// Have our new lines join the existing sector
Tools.JoinSector(newsectorlines, joinsidedef);
if(Tools.JoinSector(newsectorlines, joinsidedef) == null)
return false;
}
}
}
@ -1384,6 +1408,8 @@ namespace CodeImp.DoomBuilder.Geometry
foreach(Vertex v in newverts) v.Marked = true;
foreach(Linedef l in newlines) l.Marked = true;
}
return true;
}
#endregion

View file

@ -196,10 +196,13 @@ namespace CodeImp.DoomBuilder.IO
// Create new item
Thing t = map.CreateThing();
t.Update(type, x, y, height, Angle2D.DoomToReal(angledeg), stringflags, tag, special, args);
if(t != null)
{
t.Update(type, x, y, height, Angle2D.DoomToReal(angledeg), stringflags, tag, special, args);
// Custom fields
ReadCustomFields(c, t, "thing");
// Custom fields
ReadCustomFields(c, t, "thing");
}
}
}
@ -252,27 +255,30 @@ namespace CodeImp.DoomBuilder.IO
if(Vector2D.ManhattanDistance(vertexlink[v1].Position, vertexlink[v2].Position) > 0.0001f)
{
Linedef l = map.CreateLinedef(vertexlink[v1], vertexlink[v2]);
l.Update(stringflags, 0, tag, special, args);
l.UpdateCache();
// Custom fields
ReadCustomFields(lc, l, "linedef");
// Read sidedefs and connect them to the line
if(s1 > -1)
if(l != null)
{
if(s1 < sidescolls.Count)
ReadSidedef(map, sidescolls[s1], l, true, sectorlink, s1);
else
General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed.");
}
if(s2 > -1)
{
if(s2 < sidescolls.Count)
ReadSidedef(map, sidescolls[s2], l, false, sectorlink, s2);
else
General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed.");
l.Update(stringflags, 0, tag, special, args);
l.UpdateCache();
// Custom fields
ReadCustomFields(lc, l, "linedef");
// Read sidedefs and connect them to the line
if(s1 > -1)
{
if(s1 < sidescolls.Count)
ReadSidedef(map, sidescolls[s1], l, true, sectorlink, s1);
else
General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed.");
}
if(s2 > -1)
{
if(s2 < sidescolls.Count)
ReadSidedef(map, sidescolls[s2], l, false, sectorlink, s2);
else
General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed.");
}
}
}
else
@ -304,10 +310,13 @@ namespace CodeImp.DoomBuilder.IO
if(sectorlink.ContainsKey(sector))
{
Sidedef s = map.CreateSidedef(ld, front, sectorlink[sector]);
s.Update(offsetx, offsety, thigh, tmid, tlow);
if(s != null)
{
s.Update(offsetx, offsety, thigh, tmid, tlow);
// Custom fields
ReadCustomFields(sc, s, "sidedef");
// Custom fields
ReadCustomFields(sc, s, "sidedef");
}
}
else
{
@ -343,13 +352,16 @@ namespace CodeImp.DoomBuilder.IO
// Create new item
Sector s = map.CreateSector();
s.Update(hfloor, hceil, tfloor, tceil, special, tag, bright);
if(s != null)
{
s.Update(hfloor, hceil, tfloor, tceil, special, tag, bright);
// Custom fields
ReadCustomFields(c, s, "sector");
// Custom fields
ReadCustomFields(c, s, "sector");
// Add it to the lookup table
link.Add(i, s);
// Add it to the lookup table
link.Add(i, s);
}
}
// Return lookup table
@ -379,12 +391,14 @@ namespace CodeImp.DoomBuilder.IO
// Create new item
Vertex v = map.CreateVertex(new Vector2D(x, y));
if(v != null)
{
// Custom fields
ReadCustomFields(c, v, "vertex");
// Custom fields
ReadCustomFields(c, v, "vertex");
// Add it to the lookup table
link.Add(i, v);
// Add it to the lookup table
link.Add(i, v);
}
}
// Return lookup table

View file

@ -774,7 +774,7 @@ namespace CodeImp.DoomBuilder.Map
}
// This splits this line by vertex v
// Returns the new line resulting from the split
// Returns the new line resulting from the split, or null when it failed
public Linedef Split(Vertex v)
{
Linedef nl;
@ -782,6 +782,7 @@ namespace CodeImp.DoomBuilder.Map
// Copy linedef and change vertices
nl = map.CreateLinedef(v, end);
if(nl == null) return null;
CopyPropertiesTo(nl);
SetEndVertex(v);
nl.Selected = this.Selected;
@ -791,6 +792,7 @@ namespace CodeImp.DoomBuilder.Map
if(front != null)
{
nsd = map.CreateSidedef(nl, true, front.Sector);
if(nsd == null) return null;
front.CopyPropertiesTo(nsd);
nsd.Marked = front.Marked;
@ -802,6 +804,7 @@ namespace CodeImp.DoomBuilder.Map
if(back != null)
{
nsd = map.CreateSidedef(nl, false, back.Sector);
if(nsd == null) return null;
back.CopyPropertiesTo(nsd);
nsd.Marked = back.Marked;
@ -816,7 +819,8 @@ namespace CodeImp.DoomBuilder.Map
// This joins the line with another line
// This line will be disposed
public void Join(Linedef other)
// Returns false when the operation could not be completed
public bool Join(Linedef other)
{
Sector l1fs, l1bs, l2fs, l2bs;
bool l1was2s, l2was2s;
@ -844,13 +848,13 @@ namespace CodeImp.DoomBuilder.Map
// Copy my sidedefs to the other
if(this.Start == other.Start)
{
JoinChangeSidedefs(other, true, front);
JoinChangeSidedefs(other, false, back);
if(!JoinChangeSidedefs(other, true, front)) return false;
if(!JoinChangeSidedefs(other, false, back)) return false;
}
else
{
JoinChangeSidedefs(other, false, front);
JoinChangeSidedefs(other, true, back);
if(!JoinChangeSidedefs(other, false, front)) return false;
if(!JoinChangeSidedefs(other, true, back)) return false;
}
// Copy my properties to the other
@ -866,7 +870,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.front != null) this.front.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, back);
if(!JoinChangeSidedefs(other, true, back)) return false;
}
// Compare back sectors
else if((l1bs != null) && (l1bs == l2bs))
@ -876,7 +880,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
if(!JoinChangeSidedefs(other, false, front)) return false;
}
// Compare front and back
else if((l1fs != null) && (l1fs == l2bs))
@ -886,7 +890,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.back != null) this.back.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, front);
if(!JoinChangeSidedefs(other, true, front)) return false;
}
// Compare back and front
else if((l1bs != null) && (l1bs == l2fs))
@ -896,7 +900,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
if(!JoinChangeSidedefs(other, false, back)) return false;
}
else
{
@ -911,7 +915,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
if(!JoinChangeSidedefs(other, false, front)) return false;
}
else
{
@ -920,7 +924,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
if(!JoinChangeSidedefs(other, false, back)) return false;
}
}
// This line single sided?
@ -934,7 +938,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
if(!JoinChangeSidedefs(other, false, front)) return false;
}
else
{
@ -943,7 +947,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.back != null) this.back.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, front);
if(!JoinChangeSidedefs(other, true, front)) return false;
}
}
else
@ -956,7 +960,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
if(!JoinChangeSidedefs(other, false, front)) return false;
}
else
{
@ -965,7 +969,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
if(!JoinChangeSidedefs(other, false, back)) return false;
}
}
}
@ -987,6 +991,7 @@ namespace CodeImp.DoomBuilder.Map
// I got killed by the other.
this.Dispose();
General.Map.IsChanged = true;
return true;
}
// This changes sidedefs (used for joining lines)
@ -994,7 +999,8 @@ namespace CodeImp.DoomBuilder.Map
// front: Side on which to remove or create the sidedef (true for front side)
// newside: The side from which to copy the properties to the new sidedef.
// If this is null, no sidedef will be created (only removed)
private void JoinChangeSidedefs(Linedef target, bool front, Sidedef newside)
// Returns false when the operation could not be completed.
private bool JoinChangeSidedefs(Linedef target, bool front, Sidedef newside)
{
Sidedef sd;
@ -1011,9 +1017,12 @@ namespace CodeImp.DoomBuilder.Map
if(newside != null)
{
sd = map.CreateSidedef(target, front, newside.Sector);
if(sd == null) return false;
newside.CopyPropertiesTo(sd);
sd.Marked = newside.Marked;
}
return true;
}
// String representation

View file

@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Text;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Windows;
using SlimDX.Direct3D9;
using CodeImp.DoomBuilder.Rendering;
using SlimDX;
@ -513,6 +514,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new vertex and returns it.</summary>
public Vertex CreateVertex(Vector2D pos)
{
if(numvertices == General.Map.FormatInterface.MaxVertices)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of vertices reached.");
return null;
}
// Make the vertex
Vertex v = new Vertex(this, numvertices, pos);
AddItem(v, ref vertices, numvertices, ref numvertices);
@ -522,6 +529,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new vertex and returns it.</summary>
public Vertex CreateVertex(int index, Vector2D pos)
{
if(numvertices == General.Map.FormatInterface.MaxVertices)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of vertices reached.");
return null;
}
// Make the vertex
Vertex v = new Vertex(this, index, pos);
AddItem(v, ref vertices, index, ref numvertices);
@ -531,6 +544,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new linedef and returns it.</summary>
public Linedef CreateLinedef(Vertex start, Vertex end)
{
if(numlinedefs == General.Map.FormatInterface.MaxLinedefs)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of linedefs reached.");
return null;
}
// Make the linedef
Linedef l = new Linedef(this, numlinedefs, start, end);
AddItem(l, ref linedefs, numlinedefs, ref numlinedefs);
@ -540,6 +559,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new linedef and returns it.</summary>
public Linedef CreateLinedef(int index, Vertex start, Vertex end)
{
if(numlinedefs == General.Map.FormatInterface.MaxLinedefs)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of linedefs reached.");
return null;
}
// Make the linedef
Linedef l = new Linedef(this, index, start, end);
AddItem(l, ref linedefs, index, ref numlinedefs);
@ -549,6 +574,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new sidedef and returns it.</summary>
public Sidedef CreateSidedef(Linedef l, bool front, Sector s)
{
if(numsidedefs == int.MaxValue)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sidedefs reached.");
return null;
}
// Make the sidedef
Sidedef sd = new Sidedef(this, numsidedefs, l, front, s);
AddItem(sd, ref sidedefs, numsidedefs, ref numsidedefs);
@ -558,6 +589,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new sidedef and returns it.</summary>
public Sidedef CreateSidedef(int index, Linedef l, bool front, Sector s)
{
if(numsidedefs == int.MaxValue)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sidedefs reached.");
return null;
}
// Make the sidedef
Sidedef sd = new Sidedef(this, index, l, front, s);
AddItem(sd, ref sidedefs, index, ref numsidedefs);
@ -575,7 +612,13 @@ namespace CodeImp.DoomBuilder.Map
public Sector CreateSector(int index)
{
int fixedindex;
if(numsectors == General.Map.FormatInterface.MaxSectors)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sectors reached.");
return null;
}
// Do we have any index holes we can use?
if(indexholes.Count > 0)
{
@ -596,6 +639,12 @@ namespace CodeImp.DoomBuilder.Map
// This creates a new sector with a specific fixed index
private Sector CreateSectorEx(int fixedindex, int index)
{
if(numsectors == General.Map.FormatInterface.MaxSectors)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sectors reached.");
return null;
}
// Make the sector
Sector s = new Sector(this, index, fixedindex);
AddItem(s, ref sectors, index, ref numsectors);
@ -605,6 +654,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new thing and returns it.</summary>
public Thing CreateThing()
{
if(numthings == General.Map.FormatInterface.MaxThings)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached.");
return null;
}
// Make the thing
Thing t = new Thing(this, numthings);
AddItem(t, ref things, numthings, ref numthings);
@ -614,6 +669,12 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This creates a new thing and returns it.</summary>
public Thing CreateThing(int index)
{
if(numthings == General.Map.FormatInterface.MaxThings)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached.");
return null;
}
// Make the thing
Thing t = new Thing(this, index);
AddItem(t, ref things, index, ref numthings);
@ -1841,9 +1902,9 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Stitching
/// <summary>
/// Stitches marked geometry with non-marked geometry. Returns the number of stitches made.
/// Stitches marked geometry with non-marked geometry. Returns false when the operation failed.
/// </summary>
public int StitchGeometry()
public bool StitchGeometry()
{
ICollection<Linedef> movinglines;
ICollection<Linedef> fixedlines;
@ -1851,7 +1912,6 @@ namespace CodeImp.DoomBuilder.Map
ICollection<Vertex> movingverts;
ICollection<Vertex> fixedverts;
RectangleF editarea;
int stitches = 0;
int stitchundo;
// Find vertices
@ -1871,7 +1931,7 @@ namespace CodeImp.DoomBuilder.Map
// Join nearby vertices
BeginAddRemove();
stitches += MapSet.JoinVertices(fixedverts, movingverts, true, MapSet.STITCH_DISTANCE);
MapSet.JoinVertices(fixedverts, movingverts, true, MapSet.STITCH_DISTANCE);
EndAddRemove();
// Update cached values of lines because we need their length/angle
@ -1881,21 +1941,24 @@ namespace CodeImp.DoomBuilder.Map
// Split moving lines with unselected vertices
nearbyfixedverts = MapSet.FilterByArea(fixedverts, ref editarea);
stitches += MapSet.SplitLinesByVertices(movinglines, nearbyfixedverts, MapSet.STITCH_DISTANCE, movinglines);
if(!MapSet.SplitLinesByVertices(movinglines, nearbyfixedverts, MapSet.STITCH_DISTANCE, movinglines))
return false;
// Split non-moving lines with selected vertices
fixedlines = MapSet.FilterByArea(fixedlines, ref editarea);
stitches += MapSet.SplitLinesByVertices(fixedlines, movingverts, MapSet.STITCH_DISTANCE, movinglines);
if(!MapSet.SplitLinesByVertices(fixedlines, movingverts, MapSet.STITCH_DISTANCE, movinglines))
return false;
// Remove looped linedefs
stitches += MapSet.RemoveLoopedLinedefs(movinglines);
MapSet.RemoveLoopedLinedefs(movinglines);
// Join overlapping lines
stitches += MapSet.JoinOverlappingLines(movinglines);
if(!MapSet.JoinOverlappingLines(movinglines))
return false;
EndAddRemove();
return stitches;
return true;
}
#endregion
@ -1951,10 +2014,9 @@ namespace CodeImp.DoomBuilder.Map
return count;
}
/// <summary>This joins overlapping lines together and returns the number of joins made.</summary>
public static int JoinOverlappingLines(ICollection<Linedef> lines)
/// <summary>This joins overlapping lines together. Returns false when the operation failed.</summary>
public static bool JoinOverlappingLines(ICollection<Linedef> lines)
{
int joinsdone = 0;
bool joined;
do
@ -1980,7 +2042,7 @@ namespace CodeImp.DoomBuilder.Map
// Merge these two linedefs
while(lines.Remove(l2)) ;
l2.Join(l1);
if(!l2.Join(l1)) return false;
// If l2 was marked as new geometry, we have to make sure
// that l1's FrontInterior is correct for the drawing procedure
@ -1999,7 +2061,6 @@ namespace CodeImp.DoomBuilder.Map
}
}
joinsdone++;
joined = true;
break;
}
@ -2024,7 +2085,7 @@ namespace CodeImp.DoomBuilder.Map
// Merge these two linedefs
while(lines.Remove(l2)) ;
l2.Join(l1);
if(!l2.Join(l1)) return false;
// If l2 was marked as new geometry, we have to make sure
// that l1's FrontInterior is correct for the drawing procedure
@ -2043,7 +2104,6 @@ namespace CodeImp.DoomBuilder.Map
}
}
joinsdone++;
joined = true;
break;
}
@ -2057,7 +2117,7 @@ namespace CodeImp.DoomBuilder.Map
while(joined);
// Return result
return joinsdone;
return true;
}
/// <summary>This removes looped linedefs (linedefs which reference the same vertex for
@ -2184,11 +2244,10 @@ namespace CodeImp.DoomBuilder.Map
}
/// <summary>This splits the given lines with the given vertices. All affected lines
/// will be added to changedlines. Returns the number of splits made</summary>
public static int SplitLinesByVertices(ICollection<Linedef> lines, ICollection<Vertex> verts, float splitdist, ICollection<Linedef> changedlines)
/// will be added to changedlines. Returns false when the operation failed.</summary>
public static bool SplitLinesByVertices(ICollection<Linedef> lines, ICollection<Vertex> verts, float splitdist, ICollection<Linedef> changedlines)
{
float splitdist2 = splitdist * splitdist;
int splitsdone = 0;
bool splitted;
do
@ -2215,6 +2274,7 @@ namespace CodeImp.DoomBuilder.Map
{
// Split line l with vertex v
Linedef nl = l.Split(v);
if(nl == null) return false;
// Add the new line to the list
lines.Add(nl);
@ -2232,7 +2292,6 @@ namespace CodeImp.DoomBuilder.Map
}
// Count the split
splitsdone++;
splitted = true;
break;
}
@ -2246,9 +2305,8 @@ namespace CodeImp.DoomBuilder.Map
}
}
while(splitted);
// Return result
return splitsdone;
return true;
}
/// <summary>This finds the side closest to the specified position.</summary>

View file

@ -397,21 +397,29 @@ namespace CodeImp.DoomBuilder.Windows
{
// Make sure we have a valid sector (make a new one if needed)
if(l.Front != null) index = l.Front.Sector.Index; else index = -1;
s = General.Map.Map.GetSectorByIndex(frontsector.GetResult(index));
if(s == null) s = General.Map.Map.CreateSector();
// Create new sidedef?
if(l.Front == null) General.Map.Map.CreateSidedef(l, true, s);
index = frontsector.GetResult(index);
if((index > -1) && (index < General.Map.Map.Sectors.Count))
{
s = General.Map.Map.GetSectorByIndex(index);
if(s == null) s = General.Map.Map.CreateSector();
if(s != null)
{
// Create new sidedef?
if(l.Front == null) General.Map.Map.CreateSidedef(l, true, s);
if(l.Front != null)
{
// Change sector?
if(l.Front.Sector != s) l.Front.SetSector(s);
// Change sector?
if(l.Front.Sector != s) l.Front.SetSector(s);
// Apply settings
l.Front.OffsetX = General.Clamp(frontoffsetx.GetResult(l.Front.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Front.OffsetY = General.Clamp(frontoffsety.GetResult(l.Front.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
// Apply settings
l.Front.OffsetX = General.Clamp(frontoffsetx.GetResult(l.Front.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Front.OffsetY = General.Clamp(frontoffsety.GetResult(l.Front.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
}
}
}
}
// Remove back side?
@ -424,21 +432,29 @@ namespace CodeImp.DoomBuilder.Windows
{
// Make sure we have a valid sector (make a new one if needed)
if(l.Back != null) index = l.Back.Sector.Index; else index = -1;
s = General.Map.Map.GetSectorByIndex(backsector.GetResult(index));
if(s == null) s = General.Map.Map.CreateSector();
index = backsector.GetResult(index);
if((index > -1) && (index < General.Map.Map.Sectors.Count))
{
s = General.Map.Map.GetSectorByIndex(index);
if(s == null) s = General.Map.Map.CreateSector();
if(s != null)
{
// Create new sidedef?
if(l.Back == null) General.Map.Map.CreateSidedef(l, false, s);
if(l.Back != null)
{
// Change sector?
if(l.Back.Sector != s) l.Back.SetSector(s);
// Create new sidedef?
if(l.Back == null) General.Map.Map.CreateSidedef(l, false, s);
// Change sector?
if(l.Back.Sector != s) l.Back.SetSector(s);
// Apply settings
l.Back.OffsetX = General.Clamp(backoffsetx.GetResult(l.Back.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Back.OffsetY = General.Clamp(backoffsety.GetResult(l.Back.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
// Apply settings
l.Back.OffsetX = General.Clamp(backoffsetx.GetResult(l.Back.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Back.OffsetY = General.Clamp(backoffsety.GetResult(l.Back.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
}
}
}
}
// Custom fields

View file

@ -174,21 +174,27 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Make a new one
Thing t = General.Map.Map.CreateThing();
t.Type = General.Map.Config.Start3DModeThingType;
t.Move(mousemappos);
t.UpdateConfiguration();
General.Map.ThingsFilter.Update();
thingfound = t;
if(t != null)
{
t.Type = General.Map.Config.Start3DModeThingType;
t.Move(mousemappos);
t.UpdateConfiguration();
General.Map.ThingsFilter.Update();
thingfound = t;
}
}
// Make sure that the found thing is between ceiling and floor
thingfound.DetermineSector();
if(thingfound.Position.z < 0.0f) thingfound.Move(thingfound.Position.x, thingfound.Position.y, 0.0f);
if(thingfound.Sector != null)
if(thingfound != null)
{
if((thingfound.Position.z + 50.0f) > (thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight))
thingfound.Move(thingfound.Position.x, thingfound.Position.y,
thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight - 50.0f);
// Make sure that the found thing is between ceiling and floor
thingfound.DetermineSector();
if(thingfound.Position.z < 0.0f) thingfound.Move(thingfound.Position.x, thingfound.Position.y, 0.0f);
if(thingfound.Sector != null)
{
if((thingfound.Position.z + 50.0f) > (thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight))
thingfound.Move(thingfound.Position.x, thingfound.Position.y,
thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight - 50.0f);
}
}
// Update Visual Mode camera

View file

@ -211,9 +211,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Make vertex
Vertex v = General.Map.Map.CreateVertex(points[i]);
if(v == null)
{
General.Map.UndoRedo.WithdrawUndo();
return;
}
// Split the line and move on with this line
splitline = splitline.Split(v);
if(splitline == null)
{
General.Map.UndoRedo.WithdrawUndo();
return;
}
}
}
}

View file

@ -460,7 +460,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " drawing.");
// Make the drawing
Tools.DrawLines(points);
if(!Tools.DrawLines(points))
{
// Drawing failed
// NOTE: I have to call this twice, because the first time only cancels this volatile mode
General.Map.UndoRedo.WithdrawUndo();
General.Map.UndoRedo.WithdrawUndo();
return;
}
// Snap to map format accuracy
General.Map.Map.SnapAllToAccuracy();

View file

@ -894,7 +894,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
else
{
General.Interface.DisplayStatus(StatusType.Warning, "Please make a selection first!");
General.Interface.MessageBeep(MessageBeepType.Default);
// Cancel now
General.Editing.CancelMode();

View file

@ -743,12 +743,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Split in middle of line
splitvertex = General.Map.Map.CreateVertex(ld.GetCenterPoint());
}
if(splitvertex == null)
{
General.Map.UndoRedo.WithdrawUndo();
break;
}
// Snap to map format accuracy
splitvertex.SnapToAccuracy();
// Split the line
ld.Split(splitvertex);
Linedef sld = ld.Split(splitvertex);
if(sld == null)
{
General.Map.UndoRedo.WithdrawUndo();
break;
}
}
// Update cache values

View file

@ -242,23 +242,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Make the sector
Sector s = Tools.MakeSector(allsides, oldlines);
// Now we go for all the lines along the sector to
// see if they only have a back side. In that case we want
// to flip the linedef to that it only has a front side.
foreach(Sidedef sd in s.Sidedefs)
if(s != null)
{
if((sd.Line.Front == null) && (sd.Line.Back != null))
// Now we go for all the lines along the sector to
// see if they only have a back side. In that case we want
// to flip the linedef to that it only has a front side.
foreach(Sidedef sd in s.Sidedefs)
{
// Flip linedef
sd.Line.FlipVertices();
sd.Line.FlipSidedefs();
if((sd.Line.Front == null) && (sd.Line.Back != null))
{
// Flip linedef
sd.Line.FlipVertices();
sd.Line.FlipSidedefs();
}
}
General.Map.Data.UpdateUsedTextures();
General.Interface.SetCursor(Cursors.Default);
return s;
}
else
{
General.Map.UndoRedo.WithdrawUndo();
return null;
}
General.Map.Data.UpdateUsedTextures();
General.Interface.SetCursor(Cursors.Default);
return s;
}
#endregion
@ -376,17 +383,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Make the sector
Sector s = MakeSector();
if(s != null)
{
// Quickly flash this sector to indicate it was created
General.Map.IsChanged = true;
General.Map.Map.Update();
General.Interface.RedrawDisplay();
flashpolygon = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(flashpolygon, 0);
flashintensity = 1.0f;
flashstarttime = (double)General.Clock.GetCurrentTime();
General.Interface.EnableProcessing();
}
// Quickly flash this sector to indicate it was created
General.Map.IsChanged = true;
General.Map.Map.Update();
General.Interface.RedrawDisplay();
flashpolygon = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(flashpolygon, 0);
flashintensity = 1.0f;
flashstarttime = (double)General.Clock.GetCurrentTime();
General.Interface.EnableProcessing();
// Redraw overlay
DrawGeometry();
DrawOverlay();
@ -418,28 +427,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Make the sector
Sector s = MakeSector();
General.Map.Map.Update();
// Edit the sector
List<Sector> secs = new List<Sector>(); secs.Add(s);
if(General.Interface.ShowEditSectors(secs) == DialogResult.OK)
if(s != null)
{
// Quickly flash this sector to indicate it was created
General.Map.IsChanged = true;
General.Map.Map.Update();
flashpolygon = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(flashpolygon, 0);
flashintensity = 1.0f;
flashstarttime = (double)General.Clock.GetCurrentTime();
General.Interface.EnableProcessing();
}
else
{
// Undo
General.Map.UndoRedo.PerformUndo();
General.Map.UndoRedo.ClearAllRedos();
}
// Edit the sector
List<Sector> secs = new List<Sector>(); secs.Add(s);
if(General.Interface.ShowEditSectors(secs) == DialogResult.OK)
{
// Quickly flash this sector to indicate it was created
General.Map.IsChanged = true;
General.Map.Map.Update();
flashpolygon = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(flashpolygon, 0);
flashintensity = 1.0f;
flashstarttime = (double)General.Clock.GetCurrentTime();
General.Interface.EnableProcessing();
}
else
{
// Undo
General.Map.UndoRedo.WithdrawUndo();
}
}
// Redraw overlay
DrawGeometry();
DrawOverlay();

View file

@ -649,27 +649,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
return null;
}
// Create things at mouse position
// Create thing
Thing t = General.Map.Map.CreateThing();
General.Settings.ApplyDefaultThingSettings(t);
t.Move(pos);
t.UpdateConfiguration();
// Update things filter so that it includes this thing
General.Map.ThingsFilter.Update();
// Snap to grid enabled?
if(General.Interface.SnapToGrid)
if(t != null)
{
// Snap to grid
t.SnapToGrid();
}
else
{
// Snap to map format accuracy
t.SnapToAccuracy();
}
General.Settings.ApplyDefaultThingSettings(t);
t.Move(pos);
t.UpdateConfiguration();
// Update things filter so that it includes this thing
General.Map.ThingsFilter.Update();
// Snap to grid enabled?
if(General.Interface.SnapToGrid)
{
// Snap to grid
t.SnapToGrid();
}
else
{
// Snap to map format accuracy
t.SnapToAccuracy();
}
}
return t;
}

View file

@ -309,16 +309,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Make the vertex
Vertex v = General.Map.Map.CreateVertex(insertpos);
if(v == null)
{
General.Map.UndoRedo.WithdrawUndo();
return;
}
// Snap to map format accuracy
v.SnapToAccuracy();
// Split the line with this vertex
l.Split(v);
Linedef sld = l.Split(v);
if(sld == null)
{
General.Map.UndoRedo.WithdrawUndo();
return;
}
// Update
General.Map.Map.Update();
// Highlight it
Highlight(v);
@ -616,9 +626,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Just insert here, don't snap to anything
insertpos = mousemappos;
}
// Make the vertex
Vertex v = General.Map.Map.CreateVertex(insertpos);
if(v == null)
{
General.Map.UndoRedo.WithdrawUndo();
return;
}
// Snap to map format accuracy
v.SnapToAccuracy();
@ -636,7 +651,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Update
General.Map.Map.Update();
// Redraw screen
General.Interface.RedrawDisplay();
}

View file

@ -134,6 +134,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
General.Map.UndoRedo.CreateUndo("Create front sidedef");
Sidedef newside = General.Map.Map.CreateSidedef(line, true, copysidedef.Sector);
if(newside == null) return false;
copysidedef.CopyPropertiesTo(newside);
line.ApplySidedFlags();
General.Map.Map.Update();

View file

@ -163,6 +163,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Front
General.Map.UndoRedo.CreateUndo("Create front sidedef");
Sidedef newside = General.Map.Map.CreateSidedef(line, true, copysidedeffront.Sector);
if(newside == null) return false;
copysidedeffront.CopyPropertiesTo(newside);
}
else if(copysidedefback != null)
@ -172,6 +173,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// We will then flip it to make sure to ends up in the right position.
General.Map.UndoRedo.CreateUndo("Create front sidedef");
Sidedef newside = General.Map.Map.CreateSidedef(line, true, copysidedefback.Sector);
if(newside == null) return false;
copysidedefback.CopyPropertiesTo(newside);
line.FlipVertices();
}
@ -189,10 +191,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Front
newside = General.Map.Map.CreateSidedef(line, true, copysidedeffront.Sector);
if(newside == null) return false;
copysidedeffront.CopyPropertiesTo(newside);
// Back
newside = General.Map.Map.CreateSidedef(line, false, copysidedefback.Sector);
if(newside == null) return false;
copysidedefback.CopyPropertiesTo(newside);
line.ApplySidedFlags();

View file

@ -133,6 +133,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
General.Map.UndoRedo.CreateUndo("Create back sidedef");
Sidedef newside = General.Map.Map.CreateSidedef(line, false, copysidedef.Sector);
if(newside == null) return false;
copysidedef.CopyPropertiesTo(newside);
line.ApplySidedFlags();
General.Map.Map.Update();