From 5726421c9dc506375e6dccfd0812ea2f9701fcc3 Mon Sep 17 00:00:00 2001
From: biwa <6475593+biwa@users.noreply.github.com>
Date: Sun, 31 Mar 2024 18:36:31 +0200
Subject: [PATCH 1/2] GZDoom game configuration: removed support for path
nodes, because the feature was removed from GZDoom
---
Build/Configurations/Includes/ZDoom_misc.cfg | 20 ---
.../Configurations/Includes/ZDoom_things.cfg | 35 ------
.../Scripts/Examples/GZDoom/ConnectNode.js | 114 ------------------
.../Scripts/Examples/GZDoom/NewNode.js | 87 -------------
4 files changed, 256 deletions(-)
delete mode 100644 Build/UDBScript/Scripts/Examples/GZDoom/ConnectNode.js
delete mode 100644 Build/UDBScript/Scripts/Examples/GZDoom/NewNode.js
diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg
index bc221de2..bb6165f1 100755
--- a/Build/Configurations/Includes/ZDoom_misc.cfg
+++ b/Build/Configurations/Includes/ZDoom_misc.cfg
@@ -222,26 +222,6 @@ secact_flagsrename
}
}
-pathnode_flagsrename
-{
- DoomMapSetIO
- {
- 8 = "Transition";
- }
-
- HexenMapSetIO
- {
- 8 = "Transition";
- 16384 = "Invert Size Check";
- }
-
- UniversalMapSetIO
- {
- ambush = "Transition";
- standing = "Invert Size Check";
- }
-}
-
// Default sector brightness levels
sectorbrightness
{
diff --git a/Build/Configurations/Includes/ZDoom_things.cfg b/Build/Configurations/Includes/ZDoom_things.cfg
index 6d1c2617..32780fd1 100755
--- a/Build/Configurations/Includes/ZDoom_things.cfg
+++ b/Build/Configurations/Includes/ZDoom_things.cfg
@@ -1284,41 +1284,6 @@ zdoom
}
}
- 9022
- {
- title = "Path Node";
- sprite = "internal:PathFollower";
- class = "PathNode";
- flagsrename { include("ZDoom_misc.cfg", "pathnode_flagsrename") }
- radius = 16;
- height = 56;
- arg0
- {
- title = "TID 1";
- type = 14;
- }
- arg1
- {
- title = "TID 2";
- type = 14;
- }
- arg2
- {
- title = "TID 3";
- type = 14;
- }
- arg3
- {
- title = "TID 4";
- type = 14;
- }
- arg4
- {
- title = "TID 5";
- type = 14;
- }
- }
-
9024
{
title = "Patrol Point";
diff --git a/Build/UDBScript/Scripts/Examples/GZDoom/ConnectNode.js b/Build/UDBScript/Scripts/Examples/GZDoom/ConnectNode.js
deleted file mode 100644
index 0a5c1ff9..00000000
--- a/Build/UDBScript/Scripts/Examples/GZDoom/ConnectNode.js
+++ /dev/null
@@ -1,114 +0,0 @@
-///
-
-`#version 4`;
-
-`#name Connect Nodes`;
-
-`#description Connects nodes to/from the first selected PathNode.`;
-
-`#scriptoptions
-
-direction
-{
- description = "Assignment Direction";
- default = 2;
- type = 11; // Enum
- enumvalues {
- 0 = "To First";
- 1 = "From First";
- 2 = "Both";
- }
-}
-
-doclear
-{
- description = "Clear first thing's arguments";
- default = "False";
- type = 3; // Boolean
-}
-
-`;
-
-let things = UDB.Map.getSelectedThings();
-
-if(things.length < 2)
- UDB.die('You have to select at least 2 things.');
-
-let dir = UDB.ScriptOptions.direction;
-let clr = UDB.ScriptOptions.doclear;
-
-let receiver = things[0];
-
-let pos = 0;
-
-let i = 0;
-if (clr)
-{
- for (i; i < 5; i++)
- receiver.args[i] = 0;
-}
-
-things.forEach(n =>
-{
- if (n != receiver)
- {
- if (dir > 0)
- {
- // look for the tid first, make sure it's not already assigned.
- let found = false;
- for (i = 0; i < 5; i++)
- {
- if (n.args[i] == receiver.tag)
- {
- found = true;
- break;
- }
- }
- // Not found, so assign it.
- if (!found) for (i = 0; i < 5; i++)
- {
-
- if (n.args[i] == 0)
- {
- n.args[i] = receiver.tag;
- break;
- }
- }
-
- }
- if ((dir == 0 || dir == 2) && (pos < 5 && n.tag != 0))
- {
-
- if (clr) // No special management necessary.
- {
- receiver.args[pos] = n.tag;
- pos++;
- }
- else // Look for a free spot.
- {
- let found = false;
- for (i = 0; i < 5; i++)
- {
- if (receiver.args[i] == n.tag)
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- for (i = pos; i < 5; i++)
- {
- if (receiver.args[i] == 0)
- {
- receiver.args[i] = n.tag;
- pos = i;
- found = true;
- break;
- }
- }
- }
- }
- }
- }
-});
\ No newline at end of file
diff --git a/Build/UDBScript/Scripts/Examples/GZDoom/NewNode.js b/Build/UDBScript/Scripts/Examples/GZDoom/NewNode.js
deleted file mode 100644
index dabd96d8..00000000
--- a/Build/UDBScript/Scripts/Examples/GZDoom/NewNode.js
+++ /dev/null
@@ -1,87 +0,0 @@
-///
-
-`#version 4`;
-
-`#name New Path Node`;
-
-`#description Creates a new node and assigns it a TID. If a Path Node is already selected, connects the two automatically.`;
-
-`#scriptoptions
-
-gridsnap
-{
- description = "Grid Snap";
- default = 1;
- type = 11; // enum
- enumvalues {
- 0 = "Disabled";
- 1 = "Enabled";
- }
-}
-`;
-
-
-let mpos = UDB.Map.mousePosition;
-
-if(!mpos.isFinite())
- UDB.die('Mouse cursor must be inside the map');
-
-
-let nodetype = 9022;
-let ntag = UDB.Map.getNewTag();
-let things = UDB.Map.getSelectedThings();
-
-let node = UDB.Map.createThing(mpos, nodetype);
-if (UDB.ScriptOptions.gridsnap > 0)
- node.snapToGrid();
-node.tag = ntag;
-
-let i = 0;
-let count = 0;
-if(things.length > 0)
-{
- things.forEach(n =>
- {
- if (n.type == nodetype)
- {
- // For the new node, assign the path IDs to it, up to max arguments.
- if (n.tag != 0 && count < 5)
- {
- node.args[count] = n.tag;
- count++;
- }
- // For the selected nodes, check for an empty slot.
- let pos = -1;
-
- for(i = 0; i < 5; i++)
- {
- if (n.args[i] != 0)
- continue;
-
- pos = i;
- break;
- }
-
-
-
- // Check if the tag is already used first.
- if (pos >= 0)
- {
- for (i = 0; i < 5; i++)
- {
- if (n.args[i] == ntag)
- {
- pos = -1;
- break;
- }
- }
- }
- // Free slot, and unpresent. Set it in.
- if (pos >= 0)
- n.args[pos] = ntag;
- }
- });
-}
-
-UDB.Map.clearSelectedThings();
-node.selected = true;
From df743740c0b91b152988f0d1b0a032c71da3cfd9 Mon Sep 17 00:00:00 2001
From: biwa <6475593+biwa@users.noreply.github.com>
Date: Sun, 31 Mar 2024 22:56:41 +0200
Subject: [PATCH 2/2] ZScript parser: added support for "final" and "sealed"
classes. Fixes #1033
---
Source/Core/ZDoom/ZScriptParser.cs | 99 +++++++++++++++++++++++++++---
1 file changed, 89 insertions(+), 10 deletions(-)
diff --git a/Source/Core/ZDoom/ZScriptParser.cs b/Source/Core/ZDoom/ZScriptParser.cs
index 2ffb113a..28c1cdf3 100755
--- a/Source/Core/ZDoom/ZScriptParser.cs
+++ b/Source/Core/ZDoom/ZScriptParser.cs
@@ -24,9 +24,11 @@ namespace CodeImp.DoomBuilder.ZDoom
public bool IsMixin { get; internal set; }
public bool IsExtension { get; internal set; }
public List Extensions { get; internal set; }
+ public bool IsFinal { get; internal set; }
+ public List PermittedInheritedClassNames { get; internal set; }
- // these are used for parsing and error reporting
- public ZScriptParser Parser { get; internal set; }
+ // these are used for parsing and error reporting
+ public ZScriptParser Parser { get; internal set; }
public Stream Stream { get; internal set; }
public long Position { get; internal set; }
public BinaryReader DataReader { get; internal set; }
@@ -36,7 +38,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// textresourcepath
public string TextResourcePath { get; internal set; }
- internal ZScriptClassStructure(ZScriptParser parser, string classname, string replacesname, string parentname, bool ismixin, bool isextension, DecorateCategoryInfo region)
+ internal ZScriptClassStructure(ZScriptParser parser, string classname, DecorateCategoryInfo region, string replacesname=null, string parentname=null, bool ismixin=false, bool isextension=false, bool isfinal=false, List permittedinheritedclassnames=null)
{
Parser = parser;
@@ -56,6 +58,8 @@ namespace CodeImp.DoomBuilder.ZDoom
IsMixin = ismixin;
IsExtension = isextension;
Extensions = new List();
+ IsFinal = isfinal;
+ PermittedInheritedClassNames = permittedinheritedclassnames == null ? new List() : new List(permittedinheritedclassnames); // for the "sealed" class modifier
}
internal void RestoreStreamData()
@@ -100,6 +104,20 @@ namespace CodeImp.DoomBuilder.ZDoom
Parser.ReportError("Fatal: Class \"" + _cname + "\" is trying to inherit from \"" + _pname + "\" which does not exist.");
return false;
}
+
+ // Make sure that the parent class isn't "final"
+ if(_pstruct.IsFinal)
+ {
+ Parser.ReportError($"Fatal: Class \"{_cname}\" is trying to inherit from \"{_pname}\" which is final");
+ return false;
+ }
+
+ // Make sure we're allowed to inherit from parent class
+ if(_pstruct.PermittedInheritedClassNames.Count > 0 && !_pstruct.PermittedInheritedClassNames.Contains(_cname.ToLowerInvariant()))
+ {
+ Parser.ReportError($"Fatal: Class \"{_cname}\" is not allowed to inherit from \"{_pname}\"");
+ return false;
+ }
}
else _pstruct = null;
}
@@ -730,8 +748,10 @@ namespace CodeImp.DoomBuilder.ZDoom
ZScriptToken tok_native = null;
ZScriptToken tok_scope = null;
ZScriptToken tok_version = null;
+ ZScriptToken tok_final = null;
string[] class_scope_modifiers = new string[] { "clearscope", "ui", "play" };
string[] other_modifiers = new string[] { "abstract" };
+ List permitted_inherited_class_names = new List();
while (true)
{
tokenizer.SkipWhitespace();
@@ -777,6 +797,20 @@ namespace CodeImp.DoomBuilder.ZDoom
tok_native = token;
}
+ else if(token.Value.ToLowerInvariant() == "final")
+ {
+ if(tok_final != null)
+ {
+ ReportError("Cannot have two final keywords");
+ return false;
+ }
+
+ tok_final = token;
+ }
+ else if(token.Value.ToLowerInvariant() == "sealed")
+ {
+ permitted_inherited_class_names = ParseSealed();
+ }
else if (Array.IndexOf(class_scope_modifiers, token.Value.ToLowerInvariant()) >= 0)
{
if (tok_scope != null)
@@ -874,7 +908,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// now if we are a class, and we inherit actor, parse this entry as an actor. don't process extensions.
if (!isstruct && !extend && !mixin)
{
- ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, (tok_replacename != null) ? tok_replacename.Value : null, (tok_parentname != null) ? tok_parentname.Value : null, false, false, region);
+ ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, region, (tok_replacename != null) ? tok_replacename.Value : null, (tok_parentname != null) ? tok_parentname.Value : null, false, false, tok_final != null, permitted_inherited_class_names);
cls.Position = cpos;
string clskey = cls.ClassName.ToLowerInvariant();
if (allclasses.ContainsKey(clskey))
@@ -904,7 +938,7 @@ namespace CodeImp.DoomBuilder.ZDoom
return false;
}
- ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, false, true, region);
+ ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, region, isextension: true);
cls.Position = cpos;
allclasses[clskey].Extensions.Add(cls);
}
@@ -912,7 +946,8 @@ namespace CodeImp.DoomBuilder.ZDoom
{
// This is a bit ugly. We're treating mixin classes as actors, even though they aren't. But otherwise the parser
// doesn't parse all the actor info we need
- ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, true, false, region);
+ // ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, true, false, false, null, region);
+ ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, region, ismixin: true);
cls.Position = cpos;
string clskey = cls.ClassName.ToLowerInvariant();
if(mixinclasses.ContainsKey(clskey))
@@ -930,9 +965,9 @@ namespace CodeImp.DoomBuilder.ZDoom
return true;
}
- // This parses the given decorate stream
- // Returns false on errors
- public override bool Parse(TextResourceData data, bool clearerrors)
+ // This parses the given decorate stream
+ // Returns false on errors
+ public override bool Parse(TextResourceData data, bool clearerrors)
{
if (clearerrors) LastClasses = new HashSet();
@@ -1136,7 +1171,51 @@ namespace CodeImp.DoomBuilder.ZDoom
return true;
}
- public bool Finalize()
+ ///
+ /// Parses the class names after the "sealed" class modifier.
+ ///
+ /// A list of strings with the class names that can inherit this class
+ private List ParseSealed()
+ {
+ ZScriptToken token;
+ List permittedinheritedclassnames = new List();
+
+ tokenizer.SkipWhitespace();
+ token = tokenizer.ExpectToken(ZScriptTokenType.OpenParen);
+ if(token == null || !token.IsValid)
+ {
+ ReportError("Expected (, got " + ((Object)token ?? "").ToString());
+ return null;
+ }
+
+ while(true)
+ {
+ tokenizer.SkipWhitespace();
+ token = tokenizer.ExpectToken(ZScriptTokenType.Identifier);
+ if(token == null || !token.IsValid)
+ {
+ ReportError("Expected class name, got " + ((Object)token ?? "").ToString());
+ return null;
+ }
+
+ permittedinheritedclassnames.Add(token.Value.ToLowerInvariant());
+
+ tokenizer.SkipWhitespace();
+ token = tokenizer.ExpectToken(ZScriptTokenType.Comma, ZScriptTokenType.CloseParen);
+ if(token == null || !token.IsValid)
+ {
+ ReportError("Expected , or ), got " + ((Object)token ?? "").ToString());
+ return null;
+ }
+
+ if (token.Type == ZScriptTokenType.CloseParen)
+ break;
+ }
+
+ return permittedinheritedclassnames;
+ }
+
+ public bool Finalize()
{
ClearError();