feat: add selective field updates

Also reverse Unknown4 to MeasuredFrom.

Also rework UI slightly.
This commit is contained in:
Anna 2021-03-13 16:10:23 -05:00
parent fc64403b89
commit 81cf14f3ed
9 changed files with 481 additions and 139 deletions

View File

@ -6,7 +6,9 @@ using Dalamud.Plugin;
namespace HUD_Manager.Configuration {
[Serializable]
public class Config : IPluginConfiguration {
public int Version { get; set; } = 3;
public const int LatestVersion = 4;
public int Version { get; set; } = LatestVersion;
private DalamudPluginInterface Interface { get; set; } = null!;
@ -18,6 +20,8 @@ namespace HUD_Manager.Configuration {
public HudSlot StagingSlot { get; set; } = HudSlot.Four;
public PositioningMode PositioningMode { get; set; } = PositioningMode.Percentage;
public Dictionary<Guid, SavedLayout> Layouts { get; } = new();
public List<HudConditionMatch> HudConditionMatches { get; } = new();

View File

@ -2,6 +2,7 @@
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Dalamud.Plugin;
using HUD_Manager.Structs;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@ -31,7 +32,7 @@ namespace HUD_Manager.Configuration {
return config;
}
private static Config MigrateV2(JObject old) {
private static void WithEachElement(JObject old, Action<JObject> action) {
foreach (var property in old["Layouts"].Children<JProperty>()) {
if (property.Name == "$type") {
continue;
@ -46,26 +47,41 @@ namespace HUD_Manager.Configuration {
}
var element = (JObject) elementProp.Value;
var bytes = element["Unknown4"].ToObject<byte[]>();
var options = new byte[4];
Buffer.BlockCopy(bytes, 0, options, 0, 4);
var width = BitConverter.ToUInt16(bytes, 4);
var height = BitConverter.ToUInt16(bytes, 6);
var unknown4 = bytes[8];
element.Remove("Unknown4");
element["Options"] = options;
element["Width"] = width;
element["Height"] = height;
element["Unknown4"] = unknown4;
action(element);
}
}
}
private static void MigrateV2(JObject old) {
WithEachElement(old, element => {
var bytes = element["Unknown4"].ToObject<byte[]>();
var options = new byte[4];
Buffer.BlockCopy(bytes, 0, options, 0, 4);
var width = BitConverter.ToUInt16(bytes, 4);
var height = BitConverter.ToUInt16(bytes, 6);
var unknown4 = bytes[8];
element.Remove("Unknown4");
element["Options"] = options;
element["Width"] = width;
element["Height"] = height;
element["Unknown4"] = unknown4;
});
old["Version"] = 3;
}
return old.ToObject<Config>();
private static void MigrateV3(JObject old) {
WithEachElement(old, element => {
var measuredFrom = element["Unknown4"].ToObject<byte>();
element.Remove("Unknown4");
element["MeasuredFrom"] = measuredFrom;
});
old["Version"] = 4;
}
private static string PluginConfig(string? pluginName = null) {
@ -99,22 +115,50 @@ namespace HUD_Manager.Configuration {
}
var config = JsonConvert.DeserializeObject<JObject>(text);
uint version = 1;
if (config.TryGetValue("Version", out var token)) {
version = token.Value<uint>();
int GetVersion() {
if (config.TryGetValue("Version", out var token)) {
return token.Value<int>();
}
return -1;
}
switch (version) {
case 1: {
var v1 = config.ToObject<ConfigV1>(new JsonSerializer {
TypeNameHandling = TypeNameHandling.None,
});
var version = GetVersion();
if (version < 1) {
goto DefaultConfig;
}
return Migrate(v1);
}
case 2: {
return MigrateV2(config);
// v1 is a special case - this is an old HudSwap config that we can interpret as a memory chunk
// it does not need to go through migration steps after doing this, since it will be interpreted
// as the layout would be in memory, so the existing code can deal with it normally
if (version == 1) {
var v1 = config.ToObject<ConfigV1>(new JsonSerializer {
TypeNameHandling = TypeNameHandling.None,
});
return Migrate(v1);
}
// otherwise, run migrations until done
while (version < Config.LatestVersion) {
switch (version) {
case 2:
MigrateV2(config);
break;
case 3:
MigrateV3(config);
break;
default:
PluginLog.Warning($"Tried to migration from an unknown version: {version}");
goto DefaultConfig;
}
version = GetVersion();
}
if (version == Config.LatestVersion) {
return config.ToObject<Config>();
}
DefaultConfig:

View File

@ -0,0 +1,6 @@
namespace HUD_Manager.Configuration {
public enum PositioningMode {
Percentage,
Pixel,
}
}

View File

@ -114,16 +114,27 @@ namespace HUD_Manager {
}
private void WriteLayout(HudSlot slot, Layout layout, bool reloadIfNecessary = true) {
var slotPtr = this.GetLayoutPointer(slot);
this.WriteLayout(slot, layout.ToDictionary(), reloadIfNecessary);
}
var dict = layout.ToDictionary();
private void WriteLayout(HudSlot slot, IReadOnlyDictionary<ElementKind, Element> dict, bool reloadIfNecessary = true) {
var slotPtr = this.GetLayoutPointer(slot);
// update existing elements with saved data instead of wholesale overwriting
var slotLayout = this.ReadLayout(slot);
for (var i = 0; i < slotLayout.elements.Length; i++) {
if (dict.TryGetValue(slotLayout.elements[i].id, out var element)) {
slotLayout.elements[i] = new RawElement(element);
if (!dict.TryGetValue(slotLayout.elements[i].id, out var element)) {
continue;
}
// just replace the struct if all options are enabled
if (element.Enabled == Element.AllEnabled) {
slotLayout.elements[i] = new RawElement(element);
continue;
}
// otherwise only replace the enabled options
slotLayout.elements[i].UpdateEnabled(element);
}
Marshal.StructureToPtr(slotLayout, slotPtr, false);
@ -154,26 +165,26 @@ namespace HUD_Manager {
// get the ancestors and their elements for this node
foreach (var ancestor in node.Ancestors().Reverse()) {
foreach (var element in ancestor.Value.Elements) {
elements[element.Key] = element.Value;
if (element.Value.Enabled == Element.AllEnabled || !elements.ContainsKey(element.Key)) {
elements[element.Key] = element.Value.Clone();
continue;
}
elements[element.Key].UpdateEnabled(element.Value);
}
}
// apply this node's elements
foreach (var element in node.Value.Elements) {
elements[element.Key] = element.Value;
if (element.Value.Enabled == Element.AllEnabled || !elements.ContainsKey(element.Key)) {
elements[element.Key] = element.Value.Clone();
continue;
}
elements[element.Key].UpdateEnabled(element.Value);
}
var elemList = elements.Values.ToList();
while (elemList.Count < InMemoryLayoutElements) {
elemList.Add(new Element(new RawElement()));
}
var effective = new Layout {
elements = elemList.Select(elem => new RawElement(elem)).ToArray(),
};
this.WriteLayout(slot, effective);
this.WriteLayout(slot, elements);
}
}

View File

@ -306,18 +306,23 @@ namespace HUD_Manager {
ImGui.Separator();
ImGui.TextUnformatted("Search");
if (ImGui.CollapsingHeader("Options##uimanager-options")) {
ImGui.DragFloat("Slider speed", ref this._dragSpeed, 0.01f, 0.01f, 10f);
ImGui.PushItemWidth(-1);
var search = this._editorSearch ?? string.Empty;
if (ImGui.InputText("##ui-editor-search", ref search, 100)) {
this._editorSearch = string.IsNullOrWhiteSpace(search) ? null : search;
if (ImGui.BeginCombo("Positioning mode", this.Plugin.Config.PositioningMode.ToString())) {
foreach (var mode in (PositioningMode[]) Enum.GetValues(typeof(PositioningMode))) {
if (!ImGui.Selectable($"{mode}##positioning", this.Plugin.Config.PositioningMode == mode)) {
continue;
}
this.Plugin.Config.PositioningMode = mode;
this.Plugin.Config.Save();
}
ImGui.EndCombo();
}
}
ImGui.PopItemWidth();
ImGui.DragFloat("Slider speed", ref this._dragSpeed, 0.01f, 0.01f, 10f);
ImGui.Separator();
ImGui.TextUnformatted("HUD Elements");
@ -348,6 +353,11 @@ namespace HUD_Manager {
ImGui.EndPopup();
}
var search = this._editorSearch ?? string.Empty;
if (ImGui.InputText("Search##ui-editor-search", ref search, 100)) {
this._editorSearch = string.IsNullOrWhiteSpace(search) ? null : search;
}
if (ImGui.BeginChild("uimanager-layout-editor-elements", new Vector2(0, 0))) {
var toRemove = new List<ElementKind>();
@ -363,19 +373,46 @@ namespace HUD_Manager {
continue;
}
var drawVisibility = !kind.IsJobGauge();
var maxSettingWidth = 0f;
void DrawDelete() {
ImGui.SameLine(ImGui.GetContentRegionAvail().X - 30);
if (IconButton(FontAwesomeIcon.TrashAlt, $"uimanager-remove-element-{kind}")) {
toRemove.Add(kind);
}
void DrawSettingName(string name) {
maxSettingWidth = Math.Max(maxSettingWidth, ImGui.CalcTextSize(name).X);
ImGui.TextUnformatted(name);
ImGui.NextColumn();
}
if (drawVisibility) {
ImGui.TextUnformatted("Visibility");
ImGui.Columns(3);
ImGui.SetColumnWidth(0, ImGui.CalcTextSize("Enabled").X + ImGui.GetStyle().ItemSpacing.X * 2);
DrawDelete();
ImGui.TextUnformatted("Enabled");
ImGui.NextColumn();
DrawSettingName("Setting");
ImGui.TextUnformatted("Control");
ImGui.SameLine(ImGui.GetContentRegionAvail().X - 30);
if (IconButton(FontAwesomeIcon.TrashAlt, $"uimanager-remove-element-{kind}")) {
toRemove.Add(kind);
}
void DrawEnabledCheckbox(ElementKind kind, ElementComponent component) {
ImGui.NextColumn();
var enabled = element[component];
if (ImGui.Checkbox($"###{component}-enabled-{kind}", ref enabled)) {
element[component] = enabled;
this.Plugin.Config.Save();
update = true;
}
ImGui.NextColumn();
}
if (!kind.IsJobGauge()) {
DrawEnabledCheckbox(element.Id, ElementComponent.Visibility);
DrawSettingName("Visibility");
var keyboard = element[VisibilityFlags.Keyboard];
if (IconCheckbox(FontAwesomeIcon.Keyboard, ref keyboard, $"{kind}")) {
@ -391,24 +428,78 @@ namespace HUD_Manager {
}
}
var x = element.X;
if (ImGui.DragFloat($"X##{kind}", ref x, this._dragSpeed)) {
element.X = x;
update = true;
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Measured from");
ImGui.PushItemWidth(-1);
var measuredFrom = element.MeasuredFrom;
if (ImGui.BeginCombo($"##measured-from-{kind}", measuredFrom.ToString())) {
foreach (var measured in (MeasuredFrom[]) Enum.GetValues(typeof(MeasuredFrom))) {
if (!ImGui.Selectable($"{measured}##{kind}", measuredFrom == measured)) {
continue;
}
element.MeasuredFrom = measured;
update = true;
}
ImGui.EndCombo();
}
ImGui.PopItemWidth();
DrawEnabledCheckbox(element.Id, ElementComponent.X);
DrawSettingName("X");
if (this.Plugin.Config.PositioningMode == PositioningMode.Percentage) {
ImGui.PushItemWidth(-1);
var x = element.X;
if (ImGui.DragFloat($"##x-{kind}", ref x, this._dragSpeed)) {
element.X = x;
update = true;
}
ImGui.PopItemWidth();
DrawEnabledCheckbox(element.Id, ElementComponent.Y);
DrawSettingName("Y");
ImGui.PushItemWidth(-1);
var y = element.Y;
if (ImGui.DragFloat($"##y-{kind}", ref y, this._dragSpeed)) {
element.Y = y;
update = true;
}
ImGui.PopItemWidth();
} else {
var screen = ImGui.GetIO().DisplaySize;
ImGui.PushItemWidth(-1);
var x = (int) Math.Truncate(element.X * screen.X / 100);
if (ImGui.InputInt($"##x-{kind}", ref x)) {
element.X = x / screen.X * 100;
update = true;
}
ImGui.PopItemWidth();
DrawEnabledCheckbox(element.Id, ElementComponent.Y);
DrawSettingName("Y");
ImGui.PushItemWidth(-1);
var y = (int) Math.Truncate(element.Y * screen.Y / 100);
if (ImGui.InputInt($"##y-{kind}", ref y)) {
element.Y = y / screen.Y * 100;
update = true;
}
ImGui.PopItemWidth();
}
if (!drawVisibility) {
DrawDelete();
}
var y = element.Y;
if (ImGui.DragFloat($"Y##{kind}", ref y, this._dragSpeed)) {
element.Y = y;
update = true;
}
DrawEnabledCheckbox(element.Id, ElementComponent.Scale);
DrawSettingName("Scale");
ImGui.PushItemWidth(-1);
var currentScale = $"{element.Scale * 100}%";
if (ImGui.BeginCombo($"Scale##{kind}", currentScale)) {
if (ImGui.BeginCombo($"##scale-{kind}", currentScale)) {
foreach (var scale in ScaleOptions) {
if (!ImGui.Selectable($"{scale * 100}%")) {
continue;
@ -420,29 +511,46 @@ namespace HUD_Manager {
ImGui.EndCombo();
}
ImGui.PopItemWidth();
if (!kind.IsJobGauge()) {
DrawEnabledCheckbox(element.Id, ElementComponent.Opacity);
DrawSettingName("Opacity");
ImGui.PushItemWidth(-1);
var opacity = (int) element.Opacity;
if (ImGui.DragInt($"Opacity##{kind}", ref opacity, 1, 1, 255)) {
if (ImGui.DragInt($"##opacity-{kind}", ref opacity, 1, 1, 255)) {
element.Opacity = (byte) opacity;
update = true;
}
ImGui.PopItemWidth();
}
if (kind == ElementKind.TargetBar) {
var targetBarOpts = new TargetBarOptions(element.Options);
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Display target information independently");
ImGui.PushItemWidth(-1);
var independent = targetBarOpts.ShowIndependently;
if (ImGui.Checkbox("Display target information independently", ref independent)) {
if (ImGui.Checkbox($"##display-target-info-indep-{kind}", ref independent)) {
targetBarOpts.ShowIndependently = independent;
update = true;
}
ImGui.PopItemWidth();
}
if (kind == ElementKind.StatusEffects) {
var statusOpts = new StatusOptions(element.Options);
if (ImGui.BeginCombo($"Style##{kind}", statusOpts.Style.ToString())) {
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Style");
ImGui.PushItemWidth(-1);
if (ImGui.BeginCombo($"##style-{kind}", statusOpts.Style.ToString())) {
foreach (var style in (StatusStyle[]) Enum.GetValues(typeof(StatusStyle))) {
if (!ImGui.Selectable($"{style}##{kind}")) {
continue;
@ -454,12 +562,18 @@ namespace HUD_Manager {
ImGui.EndCombo();
}
ImGui.PopItemWidth();
}
if (kind == ElementKind.StatusInfoEnhancements || kind == ElementKind.StatusInfoEnfeeblements || kind == ElementKind.StatusInfoOther) {
var statusOpts = new StatusInfoOptions(kind, element.Options);
if (ImGui.BeginCombo($"Layout##{kind}", statusOpts.Layout.ToString())) {
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Layout");
ImGui.PushItemWidth(-1);
if (ImGui.BeginCombo($"##layout-{kind}", statusOpts.Layout.ToString())) {
foreach (var sLayout in (StatusLayout[]) Enum.GetValues(typeof(StatusLayout))) {
if (!ImGui.Selectable($"{sLayout}##{kind}")) {
continue;
@ -471,8 +585,14 @@ namespace HUD_Manager {
ImGui.EndCombo();
}
ImGui.PopItemWidth();
if (ImGui.BeginCombo($"Alignment##{kind}", statusOpts.Alignment.ToString())) {
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Alignment");
ImGui.PushItemWidth(-1);
if (ImGui.BeginCombo($"##alignment-{kind}", statusOpts.Alignment.ToString())) {
foreach (var alignment in (StatusAlignment[]) Enum.GetValues(typeof(StatusAlignment))) {
if (!ImGui.Selectable($"{alignment}##{kind}")) {
continue;
@ -484,26 +604,45 @@ namespace HUD_Manager {
ImGui.EndCombo();
}
ImGui.PopItemWidth();
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Focusable by gamepad");
ImGui.PushItemWidth(-1);
var focusable = statusOpts.Gamepad == StatusGamepad.Focusable;
if (ImGui.Checkbox($"Focusable by gamepad##{kind}", ref focusable)) {
if (ImGui.Checkbox($"##focusable-by-gamepad-{kind}", ref focusable)) {
statusOpts.Gamepad = focusable ? StatusGamepad.Focusable : StatusGamepad.NonFocusable;
update = true;
}
ImGui.PopItemWidth();
}
if (kind.IsHotbar()) {
var hotbarOpts = new HotbarOptions(element.Options);
if (kind != ElementKind.PetHotbar) {
var hotbarIndex = (int) hotbarOpts.Index;
if (ImGui.InputInt($"Hotbar number##{kind}", ref hotbarIndex)) {
hotbarOpts.Index = (byte) Math.Max(0, Math.Min(9, hotbarIndex));
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Hotbar number");
ImGui.PushItemWidth(-1);
var hotbarIndex = hotbarOpts.Index + 1;
if (ImGui.InputInt($"##hotbar-number-{kind}", ref hotbarIndex)) {
hotbarOpts.Index = (byte) Math.Max(0, Math.Min(9, hotbarIndex - 1));
update = true;
}
ImGui.PopItemWidth();
}
if (ImGui.BeginCombo($"Hotbar layout##{kind}", hotbarOpts.Layout.ToString())) {
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Hotbar layout");
ImGui.PushItemWidth(-1);
if (ImGui.BeginCombo($"##hotbar-layout-{kind}", hotbarOpts.Layout.ToString())) {
foreach (var hotbarLayout in (HotbarLayout[]) Enum.GetValues(typeof(HotbarLayout))) {
if (!ImGui.Selectable($"{hotbarLayout}##{kind}")) {
continue;
@ -515,17 +654,28 @@ namespace HUD_Manager {
ImGui.EndCombo();
}
ImGui.PopItemWidth();
}
if (kind.IsJobGauge()) {
var gaugeOpts = new GaugeOptions(element.Options);
ImGui.NextColumn();
ImGui.NextColumn();
DrawSettingName("Simple");
ImGui.PushItemWidth(-1);
var simple = gaugeOpts.Style == GaugeStyle.Simple;
if (ImGui.Checkbox($"Simple##{kind}", ref simple)) {
if (ImGui.Checkbox($"##simple-{kind}", ref simple)) {
gaugeOpts.Style = simple ? GaugeStyle.Simple : GaugeStyle.Normal;
update = true;
}
ImGui.PopItemWidth();
}
ImGui.SetColumnWidth(1, maxSettingWidth + ImGui.GetStyle().ItemSpacing.X * 2);
ImGui.Columns();
}
foreach (var remove in toRemove) {

139
HUD Manager/Structs/Element.cs Executable file
View File

@ -0,0 +1,139 @@
using System;
namespace HUD_Manager.Structs {
[Serializable]
public class Element {
public const ElementComponent AllEnabled = ElementComponent.X
| ElementComponent.Y
| ElementComponent.Scale
| ElementComponent.Visibility
| ElementComponent.Opacity
| ElementComponent.Options;
public ElementKind Id { get; set; }
public ElementComponent Enabled { get; set; } = AllEnabled;
public float X { get; set; }
public float Y { get; set; }
public float Scale { get; set; }
public byte[] Options { get; set; }
public ushort Width { get; set; }
public ushort Height { get; set; }
public MeasuredFrom MeasuredFrom { get; set; }
public VisibilityFlags Visibility { get; set; }
public byte Unknown6 { get; set; }
public byte Opacity { get; set; }
public byte[] Unknown8 { get; set; }
public bool this[VisibilityFlags flags] {
get => (this.Visibility & flags) > 0;
set {
if (value) {
this.Visibility |= flags;
} else {
this.Visibility &= ~flags;
}
}
}
public bool this[ElementComponent component] {
get => (this.Enabled & component) > 0;
set {
if (value) {
this.Enabled |= component;
} else {
this.Enabled &= ~component;
}
}
}
#pragma warning disable 8618
private Element() {
}
#pragma warning restore 8618
public Element(RawElement raw) {
this.Id = raw.id;
this.X = raw.x;
this.Y = raw.y;
this.Scale = raw.scale;
this.Options = raw.options;
this.Width = raw.width;
this.Height = raw.height;
this.MeasuredFrom = raw.measuredFrom;
this.Visibility = raw.visibility;
this.Unknown6 = raw.unknown6;
this.Opacity = raw.opacity;
this.Unknown8 = raw.unknown8;
}
public Element Clone() {
return new() {
Id = this.Id,
X = this.X,
Y = this.Y,
Scale = this.Scale,
Options = (byte[]) this.Options.Clone(),
Width = this.Width,
Height = this.Height,
MeasuredFrom = this.MeasuredFrom,
Visibility = this.Visibility,
Unknown6 = this.Unknown6,
Unknown8 = (byte[]) this.Unknown8.Clone(),
};
}
public void UpdateEnabled(Element other) {
if (other[ElementComponent.X]) {
this.X = other.X;
}
if (other[ElementComponent.Y]) {
this.Y = other.Y;
}
if (other[ElementComponent.Scale]) {
this.Scale = other.Scale;
}
if (other[ElementComponent.Visibility]) {
this.Visibility = other.Visibility;
}
if (other[ElementComponent.Opacity]) {
this.Opacity = other.Opacity;
}
if (other[ElementComponent.Options]) {
this.Options = other.Options;
}
this.Height = other.Height;
this.Width = other.Width;
this.MeasuredFrom = other.MeasuredFrom;
this.Unknown6 = other.Unknown6;
this.Unknown8 = other.Unknown8;
}
}
[Flags]
public enum ElementComponent : uint {
X = 1 << 0,
Y = 1 << 1,
Scale = 1 << 2,
Visibility = 1 << 3,
Opacity = 1 << 4,
Options = 1 << 5,
}
}

View File

@ -126,7 +126,7 @@ namespace HUD_Manager.Structs {
ElementKind.SongGauge => 44,
ElementKind.HealingGauge => 45,
ElementKind.ElementalGauge => 46,
ElementKind.AetherflowGaugeSch => 47, // order?
ElementKind.AetherflowGaugeSch => 47, // order? - same name, so not sure which key is for which
ElementKind.AetherflowGaugeSmn => 48, // order?
ElementKind.TranceGauge => 49,
ElementKind.FaerieGauge => 50,

View File

@ -0,0 +1,13 @@
namespace HUD_Manager.Structs {
public enum MeasuredFrom : byte {
TopLeft = 0,
TopCentre = 1,
TopRight = 2,
MiddleLeft = 3,
Middle = 4,
MiddleRight = 5,
BottomLeft = 6,
BottomMiddle = 7,
BottomRight = 8,
}
}

View File

@ -18,7 +18,7 @@ namespace HUD_Manager.Structs {
public ushort height;
public byte unknown4;
public MeasuredFrom measuredFrom;
public VisibilityFlags visibility;
@ -26,6 +26,7 @@ namespace HUD_Manager.Structs {
public byte opacity;
// last two bytes are padding
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] unknown8;
@ -37,63 +38,37 @@ namespace HUD_Manager.Structs {
this.options = element.Options;
this.width = element.Width;
this.height = element.Height;
this.unknown4 = element.Unknown4;
this.measuredFrom = element.MeasuredFrom;
this.visibility = element.Visibility;
this.unknown6 = element.Unknown6;
this.opacity = element.Opacity;
this.unknown8 = element.Unknown8;
}
}
public class Element {
public ElementKind Id { get; set; }
public float X { get; set; }
public float Y { get; set; }
public float Scale { get; set; }
public byte[] Options { get; set; }
public ushort Width { get; set; }
public ushort Height { get; set; }
public byte Unknown4 { get; set; }
public VisibilityFlags Visibility { get; set; }
public byte Unknown6 { get; set; }
public byte Opacity { get; set; }
public byte[] Unknown8 { get; set; }
public bool this[VisibilityFlags flags] {
get => (this.Visibility & flags) > 0;
set {
if (value) {
this.Visibility |= flags;
} else {
this.Visibility &= ~flags;
}
public void UpdateEnabled(Element element) {
if (element[ElementComponent.X]) {
this.x = element.X;
}
}
public Element(RawElement raw) {
this.Id = raw.id;
this.X = raw.x;
this.Y = raw.y;
this.Scale = raw.scale;
this.Options = raw.options;
this.Width = raw.width;
this.Height = raw.height;
this.Unknown4 = raw.unknown4;
this.Visibility = raw.visibility;
this.Unknown6 = raw.unknown6;
this.Opacity = raw.opacity;
this.Unknown8 = raw.unknown8;
if (element[ElementComponent.Y]) {
this.y = element.Y;
}
if (element[ElementComponent.Scale]) {
this.scale = element.Scale;
}
if (element[ElementComponent.Visibility]) {
this.visibility = element.Visibility;
}
if (element[ElementComponent.Opacity]) {
this.opacity = element.Opacity;
}
if (element[ElementComponent.Options]) {
this.options = element.Options;
}
}
}
}