Started to add support for arbitrary UDMF field associations (#401)

This commit is contained in:
biwa 2021-03-14 15:58:40 +01:00
parent 608d1e6ca2
commit 5addd6508c
4 changed files with 230 additions and 4 deletions

View file

@ -127,10 +127,44 @@ floorterain, ceilingterrain, floor/ceiling panning/rotation */
portalfloor
{
type = 0;
//associations
//{
// 0
// {
// elements { sector; }
// property = "portalfloor";
// modify = "abs";
// nevershoweventlines = true;
// }
// 1
// {
// elements { sector; }
// property = "portalceiling";
// modify = "abs";
// nevershoweventlines = true;
// }
//}
}
portalceiling
{
type = 0;
//associations
//{
// 0
// {
// elements { sector; }
// property = "portalfloor";
// modify = "abs";
// nevershoweventlines = true;
// }
// 1
// {
// elements { sector; }
// property = "portalceiling";
// modify = "abs";
// nevershoweventlines = true;
// }
//}
}
floorid

View file

@ -26,6 +26,26 @@ using CodeImp.DoomBuilder.Types;
namespace CodeImp.DoomBuilder.Config
{
public enum UDMFFieldAssociationModifier
{
None,
Absolute
}
public struct UDMFFieldAssociation
{
public string Property;
public UDMFFieldAssociationModifier Modify;
public bool NeverShowEventLines;
public UDMFFieldAssociation(string property, UDMFFieldAssociationModifier modify, bool nevershoweventlines)
{
Property = property;
Modify = modify;
NeverShowEventLines = nevershoweventlines;
}
}
public class UniversalFieldInfo : IComparable<UniversalFieldInfo>
{
#region ================== Constants
@ -39,6 +59,7 @@ namespace CodeImp.DoomBuilder.Config
private int type;
private object defaultvalue;
private EnumList enumlist;
private Dictionary<string, UDMFFieldAssociation> associations;
#endregion
@ -48,6 +69,7 @@ namespace CodeImp.DoomBuilder.Config
public int Type { get { return type; } }
public object Default { get { return defaultvalue; } }
public EnumList Enum { get { return enumlist; } }
public Dictionary<string, UDMFFieldAssociation> Associations { get { return associations; } }
#endregion
@ -60,6 +82,7 @@ namespace CodeImp.DoomBuilder.Config
// Initialize
this.name = name.ToLowerInvariant();
associations = new Dictionary<string, UDMFFieldAssociation>();
// Read type
this.type = cfg.ReadSetting(setting + ".type", int.MinValue);
@ -99,7 +122,29 @@ namespace CodeImp.DoomBuilder.Config
enumlist = new EnumList(enumsetting as IDictionary);
}
}
// Read associations
IDictionary assocdict = cfg.ReadSetting(setting + ".associations", new Hashtable());
foreach (DictionaryEntry section in assocdict)
{
string property = cfg.ReadSetting(setting + ".associations." + section.Key + ".property", string.Empty);
string modifystr = cfg.ReadSetting(setting + ".associations." + section.Key + ".modify", string.Empty);
bool nevershoweventlines = cfg.ReadSetting(setting + ".associations." + section.Key + ".nevershoweventlines", false);
UDMFFieldAssociationModifier ufam = UDMFFieldAssociationModifier.None;
if(!string.IsNullOrWhiteSpace(property))
{
switch (modifystr)
{
case "abs":
ufam = UDMFFieldAssociationModifier.Absolute;
break;
}
associations[property] = new UDMFFieldAssociation(property, ufam, nevershoweventlines);
}
}
// We have no destructor
GC.SuppressFinalize(this);
}

View file

@ -441,10 +441,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
bool completeredraw = (highlighted != null) && (highlighted.Tag != 0);
bool completeredraw = (highlighted != null) && (highlighted.Tag != 0 || Association.SectorHasUDMFFieldAssociations(highlighted));
// Set highlight association
if(s != null && s.Tag != 0)
if(s != null && (s.Tag != 0 || Association.SectorHasUDMFFieldAssociations(s)))
{
highlightasso.Set(s);
}
@ -454,7 +454,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// New association highlights something?
if((s != null) && (s.Tag != 0)) completeredraw = true;
if((s != null) && (s.Tag != 0 || Association.SectorHasUDMFFieldAssociations(s))) completeredraw = true;
// Change label color
if((highlighted != null) && !highlighted.IsDisposed)

View file

@ -31,6 +31,31 @@ using CodeImp.DoomBuilder.Windows;
namespace CodeImp.DoomBuilder.BuilderModes
{
public struct UDMFFieldAssociationX
{
public string Property;
public string Modify;
public UniValue Value;
public UDMFFieldAssociationX(string property, string modify, UniValue value)
{
Property = property;
Modify = modify;
Value = value;
}
public UniValue GetValue()
{
if(Value.Type == 0)
{
if (Modify == "abs")
return new UniValue(0, Math.Abs((int)Value.Value));
}
return new UniValue(0, 0);
}
}
public class Association
{
private HashSet<int> tags;
@ -264,6 +289,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
bool addforward = false;
bool addreverse = false;
if (s == element)
continue;
// Check for forward association (from the element to the sector)
if (hassectortags && actiontags[(int)UniversalType.SectorTag].Overlaps(s.Tags))
addforward = true;
@ -283,6 +311,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
if (addreverse)
AddLineToAction(showreverselabel ? GetActionDescription(element) : string.Empty, sectorcenter, center);
}
// Check arbitrary UDMF field associations
foreach (UniversalFieldInfo ufi in General.Map.Config.SectorFields)
{
if (ufi.Associations.Count == 0)
continue;
UniValue ouv;
if (element.Fields.TryGetValue(ufi.Name, out ouv))
{
foreach (KeyValuePair<string, UDMFFieldAssociation> kvp in ufi.Associations)
{
UniValue uv;
if (s.Fields.TryGetValue(kvp.Key, out uv))
{
if(UniValuesMatch(uv, ouv, kvp.Value.Modify, ufi.Default))
{
Vector2D sectorcenter = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2));
if(showforwardlabel && kvp.Value.NeverShowEventLines == false)
AddLineToAction(kvp.Key + ": " + uv.Value, center, sectorcenter);
sectors.Add(s);
}
}
}
}
}
}
// Process all linedefs in the map
@ -717,6 +774,96 @@ namespace CodeImp.DoomBuilder.BuilderModes
return newpositions;
}
/// <summary>
/// Checks if the type and value of two UniValues match. Takes modifiers into account
/// </summary>
/// <param name="uv1">First UniValue</param>
/// <param name="uv2">Second UniValue</param>
/// <param name="ufam">Modifier</param>
/// <returns>True if values match</returns>
private bool UniValuesMatch(UniValue uv1, UniValue uv2, UDMFFieldAssociationModifier ufam, object def)
{
if (uv1.Type != uv2.Type)
return false;
switch ((UniversalType)uv1.Type)
{
case UniversalType.AngleRadians:
case UniversalType.AngleDegreesFloat:
case UniversalType.Float:
double d1 = (double)uv1.Value;
double d2 = (double)uv2.Value;
if(ufam == UDMFFieldAssociationModifier.Absolute)
{
d1 = Math.Abs(d1);
d2 = Math.Abs(d2);
}
if (d1 == d2)
return true;
break;
case UniversalType.AngleDegrees:
case UniversalType.AngleByte:
case UniversalType.Color:
case UniversalType.EnumBits:
case UniversalType.EnumOption:
case UniversalType.Integer:
case UniversalType.LinedefTag:
case UniversalType.LinedefType:
case UniversalType.SectorEffect:
case UniversalType.SectorTag:
case UniversalType.ThingTag:
case UniversalType.ThingType:
int i1 = (int)uv1.Value;
int i2 = (int)uv2.Value;
if (ufam == UDMFFieldAssociationModifier.Absolute)
{
i1 = Math.Abs(i1);
i2 = Math.Abs(i2);
}
if (i1 == i2 && i1 != (int)def)
return true;
break;
case UniversalType.Boolean:
if ((bool)uv1.Value == (bool)uv2.Value)
return true;
break;
case UniversalType.Flat:
case UniversalType.String:
case UniversalType.Texture:
case UniversalType.EnumStrings:
case UniversalType.ThingClass:
if ((string)uv1.Value == (string)uv2.Value)
return true;
break;
}
return false;
}
/// <summary>
/// Checks if the given sector has UDMF fields that have associations
/// </summary>
/// <param name="sector">Sector to check</param>
/// <returns>True if the sector has UDMF fiels associations</returns>
public static bool SectorHasUDMFFieldAssociations(Sector sector)
{
foreach (UniversalFieldInfo ufi in General.Map.Config.SectorFields)
{
if (sector.Fields.ContainsKey(ufi.Name))
return true;
}
return false;
}
/// <summary>
/// Renders associated things and sectors in the indication color.