From 349a6b095302cbdfeaabe2b35c3d6f271af2e852 Mon Sep 17 00:00:00 2001 From: samwiddowson <36040364+samwiddowson@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:47:24 +0100 Subject: [PATCH 1/3] Fixed a crash when adding opening the dialog to add a directory resource on Mono Winforms --- Source/Core/Controls/FolderSelectDialog.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/Controls/FolderSelectDialog.cs b/Source/Core/Controls/FolderSelectDialog.cs index 9c80ef62..b20c8955 100755 --- a/Source/Core/Controls/FolderSelectDialog.cs +++ b/Source/Core/Controls/FolderSelectDialog.cs @@ -283,6 +283,7 @@ namespace CodeImp.DoomBuilder.Controls { bool flag = false; +#if !MONO_WINFORMS if (Environment.OSVersion.Version.Major >= 6) { var r = new Reflector("System.Windows.Forms"); @@ -313,6 +314,7 @@ namespace CodeImp.DoomBuilder.Controls } else { +#endif var fbd = new FolderBrowserDialog(); fbd.Description = this.Title; fbd.SelectedPath = this.InitialDirectory; @@ -320,7 +322,9 @@ namespace CodeImp.DoomBuilder.Controls if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK) return false; ofd.FileName = fbd.SelectedPath; flag = true; +#if !MONO_WINFORMS } +#endif return flag; } From 8aa5e9b5ea312a38a0e9bc034aef2c4c3924329f Mon Sep 17 00:00:00 2001 From: samwiddowson <36040364+samwiddowson@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:47:51 +0100 Subject: [PATCH 2/3] Updated README file with additional advice building on Linux --- README.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index eed6c11f..0d5f1c10 100755 --- a/README.md +++ b/README.md @@ -1,22 +1,32 @@ -**System requirements:** +# Ultimate Doom Builder + +## System requirements - 2.4 GHz CPU or faster (multi-core recommended) - Windows 7, 8 or 10 - Graphics card with OpenGL 3.2 support -**Required software on Windows:** +### Required software on Windows - [Microsoft .Net Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472) -**Building on Linux:** +## Building on Linux +These instructions are for Debian-based distros and were tested with Ubuntu 24.04 LTS and Arch. -These instructions are for Debian-based distros and were tested with Ubuntu 24.04 LTS. For others it should be similar. +__Note:__ this is experimental. None of the main developers are using Linux as a desktop OS, so you're pretty much on your own if you encounter any problems with running the application. -__Note:__ this is experimental. None of the developers are using Linux as a desktop OS, so you're pretty much on your own if you encounter any problems with running the application. - -- Install Mono. The `mono-complete` package from the Debian repo doesn't include `msbuild`, so you have to install `mono-complete` by following the instructions on the Mono project's website: https://www.mono-project.com/download/stable/#download-lin -- Install additional required packages: `sudo apt install make g++ git libx11-dev libxfixes-dev mesa-common-dev` +- Install Mono + - **Ubuntu:** The `mono-complete` package from the Debian repo doesn't include `msbuild`, so you have to install `mono-complete` by following the instructions on the Mono project's website: https://www.mono-project.com/download/stable/#download-lin + - **Arch:** mono (and msbuild which is also required) is in the *extra/* repo, which is enabled by default. `sudo pacman -S mono mono-msbuild` +- Install additional required packages + - **Ubuntu:** `sudo apt install make g++ git libx11-dev libxfixes-dev mesa-common-dev` + - **Arch:** `sudo pacman -S base-devel` + - If you're using X11 display manager you may need to install these packages: `libx11 libxfixes` + - If you are not using the proprietary nvidia driver you may need to install `mesa` - Go to a directory of your choice and clone the repository (it'll automatically create an `UltimateDoomBuilder` directory in the current directory): `git clone https://github.com/jewalky/UltimateDoomBuilder.git` - Compile UDB: `cd UltimateDoomBuilder && make` - Run UDB: `cd Build && ./builder` +- Alternatively, to compile UDB in debug mode: + - Run `make BUILDTYPE=Debug` in the root project directory + - This includes a debug output terminal in the bottom panel **Links:** - [Official thread link](https://forum.zdoom.org/viewtopic.php?f=232&t=66745) From 7fd219c2c36cbaad488bf3802375de892644d95f Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Sat, 13 Jul 2024 16:30:31 +0200 Subject: [PATCH 3/3] Fixed an issue where unknown linedef and thing flags were lost when loading the map with the wrong game configuration, or switching between game configurations in the binary map formats. Fixes #1072 (#1083) --- Source/Core/General/MapManager.cs | 20 +++++++++++ Source/Core/IO/ClipboardStreamReader.cs | 4 +-- Source/Core/IO/DoomMapSetIO.cs | 31 +++++------------ Source/Core/IO/HexenMapSetIO.cs | 33 ++++++------------ Source/Core/IO/UniversalStreamReader.cs | 4 +-- Source/Core/Map/Linedef.cs | 41 +++++++++++++++++++++-- Source/Core/Map/Thing.cs | 39 ++++++++++++++++++++- Source/Plugins/3DFloorMode/ThreeDFloor.cs | 2 +- 8 files changed, 121 insertions(+), 53 deletions(-) diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index 37086126..01d41845 100755 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -2553,6 +2553,16 @@ namespace CodeImp.DoomBuilder foreach(Thing t in General.Map.Map.Things) t.TranslateToUDMF(); } + // Make sure the raw flags are up to date + if (oldiotype == typeof(DoomMapSetIO) || oldiotype == typeof(HexenMapSetIO)) + { + foreach (Thing t in General.Map.map.Things) + t.UpdateRawFlagsFromFlags(); + + foreach (Linedef ld in General.Map.Map.Linedefs) + ld.UpdateRawFlagsFromFlags(); + } + config = new GameConfiguration(configinfo.Configuration); //mxd configinfo.ApplyDefaults(config); General.Editing.UpdateCurrentEditModes(); @@ -2607,6 +2617,16 @@ namespace CodeImp.DoomBuilder for(int i = 0; i < t.Args.Length; i++) t.Args[i] = 0; } + // Make sure the flags dictionary is up to date with flags that did not exist in the old game configuration + if ((oldiotype == typeof(DoomMapSetIO) || oldiotype == typeof(HexenMapSetIO)) && (io is DoomMapSetIO || io is HexenMapSetIO)) + { + foreach (Thing t in General.Map.Map.Things) + t.UpdateFlagsFromRawFlags(); + + foreach (Linedef ld in General.Map.Map.Linedefs) + ld.UpdateFlagsFromRawFlags(); + } + map.UpdateCustomLinedefColors(); // Reload resources diff --git a/Source/Core/IO/ClipboardStreamReader.cs b/Source/Core/IO/ClipboardStreamReader.cs index ce4106d8..24fdd6ab 100755 --- a/Source/Core/IO/ClipboardStreamReader.cs +++ b/Source/Core/IO/ClipboardStreamReader.cs @@ -248,7 +248,7 @@ namespace CodeImp.DoomBuilder.IO Linedef l = map.CreateLinedef(vertexlink[v1], vertexlink[v2]); if(l != null) { - l.Update(stringflags, 0, tags, special, args); + l.Update(stringflags, 0, 0, tags, special, args); l.UpdateCache(); // Add custom fields @@ -381,7 +381,7 @@ namespace CodeImp.DoomBuilder.IO Thing t = map.CreateThing(); if(t != null) { - t.Update(type, x, y, height, angledeg, pitch, roll, scaleX, scaleY, stringflags, tag, special, args); + t.Update(type, x, y, height, angledeg, pitch, roll, scaleX, scaleY, stringflags, 0, tag, special, args); // Add custom fields t.Fields.BeforeFieldsChange(); diff --git a/Source/Core/IO/DoomMapSetIO.cs b/Source/Core/IO/DoomMapSetIO.cs index 6aee0b66..3a954039 100755 --- a/Source/Core/IO/DoomMapSetIO.cs +++ b/Source/Core/IO/DoomMapSetIO.cs @@ -141,19 +141,18 @@ namespace CodeImp.DoomBuilder.IO int y = reader.ReadInt16(); int angle = reader.ReadInt16(); int type = reader.ReadUInt16(); - int flags = reader.ReadUInt16(); + ushort flags = reader.ReadUInt16(); // Make string flags Dictionary stringflags = new Dictionary(StringComparer.Ordinal); foreach(KeyValuePair f in manager.Config.ThingFlags) { - int fnum; - if(int.TryParse(f.Key, out fnum)) stringflags[f.Key] = ((flags & fnum) == fnum); + if (int.TryParse(f.Key, out int fnum)) stringflags[f.Key] = ((flags & fnum) == fnum); } // Create new item Thing t = map.CreateThing(); - t.Update(type, x, y, 0, angle, 0, 0, 1.0f, 1.0f, stringflags, 0, 0, new int[Thing.NUM_ARGS]); + t.Update(type, x, y, 0, angle, 0, 0, 1.0f, 1.0f, stringflags, flags, 0, 0, new int[Thing.NUM_ARGS]); } // Done @@ -299,7 +298,7 @@ namespace CodeImp.DoomBuilder.IO // Read properties from stream int v1 = readline.ReadUInt16(); int v2 = readline.ReadUInt16(); - int flags = readline.ReadUInt16(); + ushort flags = readline.ReadUInt16(); int action = readline.ReadUInt16(); int tag = readline.ReadUInt16(); int s1 = readline.ReadUInt16(); @@ -320,7 +319,7 @@ 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, new List { tag }, action, new int[Linedef.NUM_ARGS]); + l.Update(stringflags, flags, 0, new List { tag }, action, new int[Linedef.NUM_ARGS]); l.UpdateCache(); string thigh, tmid, tlow; @@ -440,20 +439,14 @@ namespace CodeImp.DoomBuilder.IO // Go for all things foreach(Thing t in map.Things) { - // Convert flags - int flags = 0; - foreach(KeyValuePair f in t.Flags) - { - int fnum; - if(f.Value && int.TryParse(f.Key, out fnum)) flags |= fnum; - } + t.UpdateRawFlagsFromFlags(); // Write properties to stream writer.Write((Int16)t.Position.x); writer.Write((Int16)t.Position.y); writer.Write((Int16)t.AngleDoom); writer.Write((UInt16)t.Type); - writer.Write((UInt16)flags); + writer.Write(t.RawFlags); } // Find insert position and remove old lump @@ -505,18 +498,12 @@ namespace CodeImp.DoomBuilder.IO // Go for all lines foreach(Linedef l in map.Linedefs) { - // Convert flags - int flags = 0; - foreach(KeyValuePair f in l.Flags) - { - int fnum; - if(f.Value && int.TryParse(f.Key, out fnum)) flags |= fnum; - } + l.UpdateRawFlagsFromFlags(); // Write properties to stream writer.Write((UInt16)vertexids[l.Start]); writer.Write((UInt16)vertexids[l.End]); - writer.Write((UInt16)flags); + writer.Write(l.RawFlags); writer.Write((UInt16)l.Action); writer.Write((UInt16)l.Tag); diff --git a/Source/Core/IO/HexenMapSetIO.cs b/Source/Core/IO/HexenMapSetIO.cs index 5bbff679..52910f9c 100755 --- a/Source/Core/IO/HexenMapSetIO.cs +++ b/Source/Core/IO/HexenMapSetIO.cs @@ -143,7 +143,7 @@ namespace CodeImp.DoomBuilder.IO int z = reader.ReadInt16(); int angle = reader.ReadInt16(); int type = reader.ReadUInt16(); - int flags = reader.ReadUInt16(); + ushort flags = reader.ReadUInt16(); int action = reader.ReadByte(); args[0] = reader.ReadByte(); args[1] = reader.ReadByte(); @@ -155,13 +155,12 @@ namespace CodeImp.DoomBuilder.IO Dictionary stringflags = new Dictionary(StringComparer.Ordinal); foreach(KeyValuePair f in manager.Config.ThingFlags) { - int fnum; - if(int.TryParse(f.Key, out fnum)) stringflags[f.Key] = ((flags & fnum) == fnum); + if (int.TryParse(f.Key, out int fnum)) stringflags[f.Key] = ((flags & fnum) == fnum); } // Create new item Thing t = map.CreateThing(); - t.Update(type, x, y, z, angle, 0, 0, 1.0f, 1.0f, stringflags, tag, action, args); + t.Update(type, x, y, z, angle, 0, 0, 1.0f, 1.0f, stringflags, flags, tag, action, args); } // Done @@ -309,7 +308,7 @@ namespace CodeImp.DoomBuilder.IO // Read properties from stream int v1 = readline.ReadUInt16(); int v2 = readline.ReadUInt16(); - int flags = readline.ReadUInt16(); + ushort flags = readline.ReadUInt16(); int action = readline.ReadByte(); args[0] = readline.ReadByte(); args[1] = readline.ReadByte(); @@ -334,7 +333,7 @@ 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, (flags & manager.Config.LinedefActivationsFilter), new List { 0 }, action, args); + l.Update(stringflags, flags, (flags & manager.Config.LinedefActivationsFilter), new List { 0 }, action, args); l.UpdateCache(); Sidedef s; @@ -454,15 +453,8 @@ namespace CodeImp.DoomBuilder.IO // Go for all things foreach(Thing t in map.Things) { - // Convert flags - int flags = 0; - foreach(KeyValuePair f in t.Flags) - { - int fnum; - if(f.Value && int.TryParse(f.Key, out fnum)) flags |= fnum; - } + t.UpdateRawFlagsFromFlags(); - // Write properties to stream // Write properties to stream writer.Write((UInt16)t.Tag); writer.Write((Int16)t.Position.x); @@ -470,7 +462,7 @@ namespace CodeImp.DoomBuilder.IO writer.Write((Int16)t.Position.z); writer.Write((Int16)t.AngleDoom); writer.Write((UInt16)t.Type); - writer.Write((UInt16)flags); + writer.Write(t.RawFlags); writer.Write((Byte)t.Action); writer.Write((Byte)t.Args[0]); writer.Write((Byte)t.Args[1]); @@ -526,16 +518,11 @@ namespace CodeImp.DoomBuilder.IO // Go for all lines foreach(Linedef l in map.Linedefs) { - // Convert flags - int flags = 0; - foreach(KeyValuePair f in l.Flags) - { - int fnum; - if(f.Value && int.TryParse(f.Key, out fnum)) flags |= fnum; - } + l.UpdateRawFlagsFromFlags(); + ushort flags = l.RawFlags; // Add activates to flags - flags |= (l.Activate & manager.Config.LinedefActivationsFilter); + flags |= (ushort)(l.Activate & manager.Config.LinedefActivationsFilter); // Write properties to stream writer.Write((UInt16)vertexids[l.Start]); diff --git a/Source/Core/IO/UniversalStreamReader.cs b/Source/Core/IO/UniversalStreamReader.cs index e31fe56c..d41e2233 100755 --- a/Source/Core/IO/UniversalStreamReader.cs +++ b/Source/Core/IO/UniversalStreamReader.cs @@ -220,7 +220,7 @@ namespace CodeImp.DoomBuilder.IO Thing t = map.CreateThing(); if(t != null) { - t.Update(type, x, y, height, angledeg, pitch, roll, scaleX, scaleY, stringflags, tag, special, args); + t.Update(type, x, y, height, angledeg, pitch, roll, scaleX, scaleY, stringflags, 0, tag, special, args); // Custom fields ReadCustomFields(c, t, "thing"); @@ -302,7 +302,7 @@ namespace CodeImp.DoomBuilder.IO Linedef l = map.CreateLinedef(vertexlink[v1], vertexlink[v2]); if(l != null) { - l.Update(stringflags, 0, tags, special, args); + l.Update(stringflags, 0, 0,tags, special, args); l.UpdateCache(); // Custom fields diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs index 553ac189..8fa33eb1 100755 --- a/Source/Core/Map/Linedef.cs +++ b/Source/Core/Map/Linedef.cs @@ -67,6 +67,7 @@ namespace CodeImp.DoomBuilder.Map // Properties private Dictionary flags; + private ushort rawflags; // The actual flags bitmap that also might include unknown flags private int action; private int activate; private List tags; //mxd @@ -91,6 +92,7 @@ namespace CodeImp.DoomBuilder.Map public Sidedef Back { get { return back; } } public Line2D Line { get { return new Line2D(start.Position, end.Position); } } internal Dictionary Flags { get { return flags; } } + public ushort RawFlags { get { return rawflags; } } public int Action { get { return action; } set { BeforePropsChange(); action = value; UpdateColorPreset(); } } public int Activate { get { return activate; } set { BeforePropsChange(); activate = value; UpdateColorPreset(); } } @@ -309,6 +311,7 @@ namespace CodeImp.DoomBuilder.Map l.action = action; l.args = (int[])args.Clone(); l.flags = new Dictionary(flags); + l.rawflags = rawflags; l.tags = new List(tags); //mxd l.updateneeded = true; l.activate = activate; @@ -316,7 +319,40 @@ namespace CodeImp.DoomBuilder.Map l.UpdateColorPreset();//mxd base.CopyPropertiesTo(l); } - + + /// + /// Updates the raw flag bit map from the flags dictionary. Has to be called before the flags in the game config changed. Has to be called in conjunction with UpdateFlagsFromRawFlags. + /// + internal void UpdateRawFlagsFromFlags() + { + foreach (KeyValuePair f in flags) + { + if (ushort.TryParse(f.Key, out ushort fnum)) + { + // Set bit to 0 + rawflags &= (ushort)~fnum; + + // Set bit if necessary + if (f.Value) + rawflags |= fnum; + } + } + } + + /// + /// Updates the flags dictionary from the raw flags. Has to be called after the flags in the game config changed. Has to be called in conjunction with UpdateRawFlagsFromFlags. + /// + internal void UpdateFlagsFromRawFlags() + { + foreach (string fname in General.Map.Config.LinedefFlags.Keys) + { + if (ushort.TryParse(fname, out ushort fnum)) + { + flags[fname] = (rawflags & fnum) == fnum; + } + } + } + // This attaches a sidedef on the front internal void AttachFront(Sidedef s) { @@ -1391,12 +1427,13 @@ namespace CodeImp.DoomBuilder.Map #region ================== Changes // This updates all properties - public void Update(Dictionary flags, int activate, List tags, int action, int[] args) + public void Update(Dictionary flags, ushort rawflags, int activate, List tags, int action, int[] args) { BeforePropsChange(); // Apply changes this.flags = new Dictionary(flags); + this.rawflags = rawflags; this.tags = new List(tags); //mxd this.activate = activate; this.action = action; diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index f2119590..a422abd9 100755 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -62,6 +62,7 @@ namespace CodeImp.DoomBuilder.Map private int angledoom; // Angle as entered / stored in file private double anglerad; // Angle in radians private Dictionary flags; + private ushort rawflags; // The actual flags bitmap that also might include unknown flags private int tag; private int action; private int[] args; @@ -110,6 +111,7 @@ namespace CodeImp.DoomBuilder.Map public double Angle { get { return anglerad; } } public int AngleDoom { get { return angledoom; } } internal Dictionary Flags { get { return flags; } } + public ushort RawFlags { get { return rawflags; } } public int Action { get { return action; } set { BeforePropsChange(); action = value; } } public int[] Args { get { return args; } } public float Size { get { return size; } } @@ -248,6 +250,7 @@ namespace CodeImp.DoomBuilder.Map t.spritescale = spritescale; //mxd t.pos = pos; t.flags = new Dictionary(flags); + t.rawflags = rawflags; t.tag = tag; t.action = action; t.args = (int[])args.Clone(); @@ -263,6 +266,39 @@ namespace CodeImp.DoomBuilder.Map base.CopyPropertiesTo(t); } + /// + /// Updates the raw flag bit map from the flags dictionary. Has to be called before the flags in the game config changed. Has to be called in conjunction with UpdateFlagsFromRawFlags. + /// + internal void UpdateRawFlagsFromFlags() + { + foreach (KeyValuePair f in flags) + { + if (ushort.TryParse(f.Key, out ushort fnum)) + { + // Set bit to 0 + rawflags &= (ushort)~fnum; + + // Set bit if necessary + if (f.Value) + rawflags |= fnum; + } + } + } + + /// + /// Updates the flags dictionary from the raw flags. Has to be called after the flags in the game config changed. Has to be called in conjunction with UpdateRawFlagsFromFlags. + /// + internal void UpdateFlagsFromRawFlags() + { + foreach (string fname in General.Map.Config.ThingFlags.Keys) + { + if (ushort.TryParse(fname, out ushort fnum)) + { + flags[fname] = (rawflags & fnum) == fnum; + } + } + } + // This determines which sector the thing is in and links it public void DetermineSector() { @@ -544,7 +580,7 @@ namespace CodeImp.DoomBuilder.Map // This updates all properties // NOTE: This does not update sector! (call DetermineSector) public void Update(int type, double x, double y, double zoffset, int angle, int pitch, int roll, double scaleX, double scaleY, - Dictionary flags, int tag, int action, int[] args) + Dictionary flags, ushort rawflags, int tag, int action, int[] args) { // Apply changes this.type = type; @@ -555,6 +591,7 @@ namespace CodeImp.DoomBuilder.Map this.scaleX = (scaleX == 0 ? 1.0f : scaleX); //mxd this.scaleY = (scaleY == 0 ? 1.0f : scaleY); //mxd this.flags = new Dictionary(flags); + this.rawflags = rawflags; this.tag = tag; this.action = action; this.args = new int[NUM_ARGS]; diff --git a/Source/Plugins/3DFloorMode/ThreeDFloor.cs b/Source/Plugins/3DFloorMode/ThreeDFloor.cs index c102c5ed..48799940 100644 --- a/Source/Plugins/3DFloorMode/ThreeDFloor.cs +++ b/Source/Plugins/3DFloorMode/ThreeDFloor.cs @@ -228,7 +228,7 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode { // We need to update the linedef's args, but we can't do it directly because otherwise their state will not be saved for the undo snapshot, // so we're using the linedef's update method - sd.Line.Update(sd.Line.GetFlags(), sd.Line.Activate, sd.Line.Tags, sd.Line.Action, new int[] { sd.Line.Args[0], type, flags, alpha, sd.Line.Args[4] }); + sd.Line.Update(sd.Line.GetFlags(), sd.Line.RawFlags, sd.Line.Activate, sd.Line.Tags, sd.Line.Action, new int[] { sd.Line.Args[0], type, flags, alpha, sd.Line.Args[4] }); } } }