Newer
Older
Qwilight / Qwilight / System / UI / DrawingComponent.cs
@Taehui Taehui on 26 Mar 33 KB 2024-03-26 오후 8:24
using MoonSharp.Interpreter;
using Qwilight.Compute;
using Qwilight.Utilities;
using System.Text;

namespace Qwilight
{
    public sealed class DrawingComponent
    {
        public int judgmentPaintComposition;
        public int hitNotePaintComposition;
        public int hitInputPaintComposition;

        public float audioVisualizerPosition0;
        public float audioVisualizerPosition1;
        public float audioVisualizerLength;
        public float audioVisualizerHeight;

        public float mediaPosition0;
        public float mediaPosition1;
        public float mediaLength;
        public float mediaHeight;

        public float mainPosition1;
        public float mainHeight;

        public float mainPosition;
        public float p2Position;

        public float judgmentMainPosition;

        public float mainWall0Position1;
        public float mainWall0Length;
        public float mainWall0Height;

        public float mainWall1Position1;
        public float mainWall1Length;
        public float mainWall1Height;

        public float hitPointsPosition0;
        public float hitPointsPosition1;
        public float hitPointsLength;
        public float hitPointsHeight;
        public int hitPointsSystem;

        public float levelPosition0;
        public float levelPosition1;
        public float levelLength;
        public float levelHeight;

        public float bandPosition0;
        public float bandPosition1;
        public float binBandLength;
        public float binBandHeight;
        public int bandSystem;
        public float enlargeBand;

        public float judgmentMeterPosition0;
        public float judgmentMeterPosition1;
        public float binJudgmentMeterLength;
        public float binJudgmentMeterHeight;
        public float judgmentMeterFrontDrawingLength;
        public float judgmentMeterUnitDrawingLength;
        public int judgmentMeterSystem;

        public float hunterPosition0;
        public float hunterPosition1;
        public float binHunterLength;
        public float binHunterHeight;
        public float hunterFrontDrawingLength;
        public int hunterSystem;

        public float standCommaDrawingLength;
        public float standPosition0;
        public float standPosition1;
        public float binStandLength;
        public float binStandHeight;
        public float standSystem;

        public float pointStopPointDrawingLength;
        public float pointPosition0;
        public float pointPosition1;
        public float binPointLength;
        public float binPointHeight;
        public float pointUnitDrawingLength;
        public int pointSystem;

        public float bpmPosition0;
        public float bpmPosition1;
        public float binBPMLength;
        public float binBPMHeight;
        public float bpmUnitDrawingLength;
        public int bpmSystem;

        public float multiplierPosition0;
        public float multiplierPosition1;
        public float binMultiplierLength;
        public float binMultiplierHeight;
        public float multiplierStopPointDrawingLength;
        public float multiplierUnitDrawingLength;
        public int multiplierSystem;

        public float netPosition0;
        public float netPosition1;
        public int netSystem;

        public float pausePosition0;
        public float pausePosition1;
        public float pauseLength;
        public float pauseHeight;
        public int pauseSystem;

        public float statusPosition0;
        public float statusPosition1;
        public float statusLength;
        public float statusHeight;
        public int statusSystem;

        public float statusSliderPosition0;
        public float statusSliderPosition1;
        public float statusSliderLength;
        public float statusSliderHeight;
        public float statusSliderContentsLength;
        public float statusSliderContentsHeight;
        public int statusSliderSystem;

        public float hmsPosition0;
        public float hmsPosition1;
        public float binHmsLength;
        public float binHmsHeight;
        public int hmsSystem;
        public float hmsColonDrawingLength;
        public float hmsSlashDrawingLength;

        public float judgmentPointsPosition0;
        public float judgmentPointsPosition1;
        public float judgmentPointsLength;
        public float judgmentPointsHeight;
        public int judgmentPointsSystem;

        public float yell1Position0;
        public float yell1Position1;
        public float yell1Length;
        public float yell1Height;
        public int yell1System;

        public float band1Position0;
        public float band1Position1;
        public float band1Length;
        public float band1Height;
        public int band1System;

        public float lastPosition0;
        public float lastPosition1;
        public float lastLength;
        public float lastHeight;
        public int lastSystem;

        public float autoMainPosition0;
        public float autoMainPosition1;
        public float autoMainLength;
        public float autoMainHeight;
        public int autoMainSystem;

        public float audioMultiplierPosition0;
        public float audioMultiplierPosition1;
        public float binAudioMultiplierLength;
        public float binAudioMultiplierHeight;
        public float audioMultiplierStopPointDrawingLength;
        public float audioMultiplierUnitDrawingLength;
        public int audioMultiplierSystem;

        public float hitPointsVisualizerPosition0;
        public float hitPointsVisualizerPosition1;
        public float binHitPointsVisualizerLength;
        public float binHitPointsVisualizerHeight;
        public float hitPointsVisualizerUnitDrawingLength;
        public int hitPointsVisualizerSystem;

        public float limiterPosition1;
        public float limiterLength;
        public float limiterHeight;

        public float judgmentVisualizerPosition0;
        public float judgmentVisualizerPosition1;
        public float judgmentVisualizerLength;
        public float judgmentVisualizerHeight;
        public float judgmentVisualizerContentsLength;
        public float judgmentVisualizerContentsHeight;
        public int judgmentVisualizerSystem;

        public float judgmentInputVisualizerPosition0;
        public float judgmentInputVisualizerPosition1;
        public float judgmentInputVisualizerLength;
        public float judgmentInputVisualizerHeight;

        public int highestJudgmentValueSystem;
        public float highestJudgmentValuePosition0;
        public float highestJudgmentValuePosition1;
        public float binHighestJudgmentValueLength;
        public float binHighestJudgmentValueHeight;

        public int higherJudgmentValueSystem;
        public float higherJudgmentValuePosition0;
        public float higherJudgmentValuePosition1;
        public float binHigherJudgmentValueLength;
        public float binHigherJudgmentValueHeight;

        public int highJudgmentValueSystem;
        public float highJudgmentValuePosition0;
        public float highJudgmentValuePosition1;
        public float binHighJudgmentValueLength;
        public float binHighJudgmentValueHeight;

        public int lowJudgmentValueSystem;
        public float lowJudgmentValuePosition0;
        public float lowJudgmentValuePosition1;
        public float binLowJudgmentValueLength;
        public float binLowJudgmentValueHeight;

        public int lowerJudgmentValueSystem;
        public float lowerJudgmentValuePosition0;
        public float lowerJudgmentValuePosition1;
        public float binLowerJudgmentValueLength;
        public float binLowerJudgmentValueHeight;

        public int lowestJudgmentValueSystem;
        public float lowestJudgmentValuePosition0;
        public float lowestJudgmentValuePosition1;
        public float binLowestJudgmentValueLength;
        public float binLowestJudgmentValueHeight;

        public int highestBandSystem;
        public float highestBandPosition0;
        public float highestBandPosition1;
        public float binHighestBandLength;
        public float binHighestBandHeight;

        public int inputVisualizerSystem;
        public float inputVisualizerPosition0;
        public float inputVisualizerPosition1;
        public float binInputVisualizerLength;
        public float binInputVisualizerHeight;

        public float titlePosition0;
        public float titlePosition1;
        public float titleLength;
        public float titleHeight;
        public int titleSystem0;
        public int titleSystem1;

        public float artistPosition0;
        public float artistPosition1;
        public float artistLength;
        public float artistHeight;
        public int artistSystem0;
        public int artistSystem1;

        public float genrePosition0;
        public float genrePosition1;
        public float genreLength;
        public float genreHeight;
        public int genreSystem0;
        public int genreSystem1;

        public float levelTextPosition0;
        public float levelTextPosition1;
        public float levelTextLength;
        public float levelTextHeight;
        public int levelTextSystem0;
        public int levelTextSystem1;

        public float wantLevelPosition0;
        public float wantLevelPosition1;
        public float wantLevelLength;
        public float wantLevelHeight;
        public int wantLevelSystem0;
        public int wantLevelSystem1;

        public float judgmentPaintPosition0;
        public float judgmentPaintPosition1;
        public float judgmentPaintLength;
        public float judgmentPaintHeight;
        public int judgmentPaintSystem;

        public int earlyValueSystem;
        public float earlyValuePosition0;
        public float earlyValuePosition1;
        public float binEarlyValueLength;
        public float binEarlyValueHeight;

        public int lateValueSystem;
        public float lateValuePosition0;
        public float lateValuePosition1;
        public float binLateValueLength;
        public float binLateValueHeight;

        public int judgmentVSVisualizerSystem;
        public float judgmentVSVisualizerPosition0;
        public float judgmentVSVisualizerPosition1;
        public float binJudgmentVSVisualizerLength;
        public float binJudgmentVSVisualizerHeight;
        public float judgmentVSVisualizerStopPointDrawingLength;

        public float pausedUnpausePosition0;
        public float pausedUnpausePosition1;
        public float pausedUnpauseLength;
        public float pausedUnpauseHeight;

        public float pausedStopPosition0;
        public float pausedStopPosition1;
        public float pausedStopLength;
        public float pausedStopHeight;

        public float pausedUndoPosition0;
        public float pausedUndoPosition1;
        public float pausedUndoLength;
        public float pausedUndoHeight;

        public float pausedConfigurePosition0;
        public float pausedConfigurePosition1;
        public float pausedConfigureLength;
        public float pausedConfigureHeight;

        public float assistTextPosition1;
        public float inputAssistTextPosition1;

        public int autoMainFrame;
        public double autoMainFramerate;
        public int judgmentMainFrame;
        public int noteFrame;
        public double noteFramerate;
        public int pauseFrame;
        public int mainFrame;
        public double mainFramerate;
        public double judgmentMainFramerate;
        public int mainJudgmentMeterFrame;
        public double mainJudgmentMeterFramerate;
        public int noteHitFrame;
        public double noteHitFramerate;
        public int longNoteHitFrame;
        public double longNoteHitFramerate;
        public int inputFrame;
        public double inputFramerate;
        public int levelFrame;
        public double levelFramerate;
        public int hitInputPaintFrame;
        public double hitInputPaintFramerate;
        public int bandFrame;
        public double bandFramerate;
        public int judgmentFrame;
        public double judgmentFramerate;
        public int yell1Frame;
        public double yell1Framerate;
        public int band1Frame;
        public double band1Framerate;
        public int lastFrame;
        public double lastFramerate;
        public int longNoteHitLoopFrame;
        public int lastEnlargedBandLoopFrame;

        public int altWall0;
        public int altWall1;
        public int altHitPoints;
        public int altBand;
        public int altJudgmentMeter;
        public int altStand;
        public int altPoint;
        public int altBPM;
        public int altMultiplier;
        public int altNet;
        public int altPause;
        public int altStatus;
        public int altStatusSlider;
        public int altHms;
        public int altJudgmentPoints;
        public int altLevel;
        public int altAudioMultiplier;
        public int altHitPointsVisualizer;
        public int altJudgmentVisualizer;
        public int altHighestJudgmentValue;
        public int altHigherJudgmentValue;
        public int altHighJudgmentValue;
        public int altLowJudgmentValue;
        public int altLowerJudgmentValue;
        public int altLowestJudgmentValue;
        public int altHighestBand;
        public int altInputVisualizer;
        public int altYell1;
        public int altBand1;
        public int altLast;
        public int altHunter;
        public int altAutoMain;
        public int altEarlyValue;
        public int altLateValue;
        public int altJudgmentVSVisualizer;
        public int altJudgmentInputVisualizer;
        public int altMedia;
        public int altTitle;
        public int altArtist;
        public int altGenre;
        public int altLevelText;
        public int altWantLevel;

        public float[] noteHeights = new float[53];
        public float[] noteHeightJudgments = new float[53];
        public float[] inputPosition0s = new float[53];
        public float[] inputPosition1s = new float[53];
        public float[] inputLengths = new float[53];
        public float[] inputHeights = new float[53];
        public float[] longNoteTailEdgeHeights = new float[53];
        public float[] longNoteTailEdgePositions = new float[53];
        public float[] longNoteTailContentsHeights = new float[53];
        public float[] longNoteFrontEdgeHeights = new float[53];
        public float[] longNoteFrontEdgePositions = new float[53];
        public float[] longNoteFrontContentsHeights = new float[53];
        public float[] autoInputPosition1s = new float[53];
        public float[] autoInputHeights = new float[53];
        public float[] judgmentMainPosition1s = new float[53];
        public float[] judgmentMainHeights = new float[53];
        public float[] hitNotePaintPosition0s = new float[53];
        public float[] hitNotePaintPosition1s = new float[53];
        public float[] hitNotePaintLengths = new float[53];
        public float[] hitNotePaintHeights = new float[53];
        public float[] hitLongNotePaintPosition0s = new float[53];
        public float[] hitLongNotePaintPosition1s = new float[53];
        public float[] hitLongNotePaintLengths = new float[53];
        public float[] hitLongNotePaintHeights = new float[53];
        public float[] mainJudgmentMeterPosition1s = new float[53];
        public float[] mainJudgmentMeterHeights = new float[53];

        public readonly object PaintPropertyCSX = new();
        public readonly List<int> PaintPropertyIDs = new();
        public readonly Dictionary<PaintProperty.ID, int>[] PaintPropertyIntMap = new Dictionary<PaintProperty.ID, int>[UI.MaxPaintPropertyID];
        public readonly Dictionary<PaintProperty.ID, double>[] PaintPropertyMap = new Dictionary<PaintProperty.ID, double>[UI.MaxPaintPropertyID];
        /// <summary>
        /// 라인 길이
        /// 플로팅 노트는 라인 길이가 0 이다.
        /// </summary>
        public readonly float[] MainNoteLengthMap = new float[53];
        /// <summary>
        /// 노트 길이
        /// </summary>
        public readonly float[] DrawingNoteLengthMap = new float[53];
        /// <summary>
        /// 노트는 여기서부터 그린다.
        /// </summary>
        public readonly float[] MainNoteLengthLevyingMap = new float[53];
        /// <summary>
        /// 노트는 여기까지 그린다.
        /// </summary>
        public readonly float[] MainNoteLengthBuiltMap = new float[53];

        public float p1BuiltLength;
        public float p2BuiltLength;

        public DrawingComponent()
        {
            for (var i = PaintPropertyMap.Length - 1; i >= 0; --i)
            {
                PaintPropertyMap[i] = new();
            }
            for (var i = PaintPropertyIntMap.Length - 1; i >= 0; --i)
            {
                PaintPropertyIntMap[i] = new();
            }
        }

        public void SetValue(DefaultCompute defaultComputer)
        {
            var valueMap = new Dictionary<string, double>();
            var intMap = new Dictionary<string, int>();
            var has2P = defaultComputer.Has2P;
            var inputMode = defaultComputer.InputMode;
            var inputCount = Component.InputCounts[(int)inputMode];
            var autoableInputCount = Component.AutoableInputCounts[(int)inputMode];
            var noteLengths = new float[inputCount + 1];
            var floatingNotePosition0s = new float[inputCount + 1];
            var floatingNoteLengths = new float[inputCount + 1];
            var slashNotePosition0s = new float[inputCount + 1];
            var p1BuiltLengthFunc = new Func<double, float>(e => (float)(MainNoteLengthBuiltMap.Skip(1).Take(defaultComputer.InputCount1P).DefaultIfEmpty(0).Max() * e));
            var p2BuiltLengthFunc = new Func<double, float>(e => (float)(MainNoteLengthBuiltMap.Skip(1).Max() * e));
            var p1Length = new Func<double, float>(e => (float)(MainNoteLengthBuiltMap.Skip(1).Take(Component.InputCounts1P[(int)inputMode]).DefaultIfEmpty(0).Max() * e));
            var lsCaller = new Script();
            lsCaller.Globals["judgmentStage"] = defaultComputer.JudgmentStage;
            lsCaller.Globals["autoableInputCount"] = autoableInputCount;
            lsCaller.Globals["defaultInputCount"] = inputCount - autoableInputCount;
            lsCaller.Globals["inputCount"] = inputCount;
            lsCaller.Globals["has2P"] = has2P;
            var judgmentMainPosition1 = Configure.Instance.UIConfigureValue.JudgmentMainPosition1V2;
            lsCaller.Globals["judgmentMainPosition"] = judgmentMainPosition1 + 600.0;
            lsCaller.Globals["judgmentMainPositionV2"] = 1.0 + judgmentMainPosition1 / 600.0;
            lsCaller.Globals["judgmentMainPositionV3"] = judgmentMainPosition1;
            lsCaller.Globals["mainPosition"] = Configure.Instance.UIConfigureValue.MainPositions.GetValueOrDefault((int)inputMode);
            lsCaller.Globals["noteLength"] = Configure.Instance.UIConfigureValue.NoteLengths.GetValueOrDefault((int)inputMode);
            lsCaller.Globals["noteHeight"] = Configure.Instance.UIConfigureValue.NoteHeights.GetValueOrDefault((int)inputMode);
            lsCaller.Globals["bandPosition"] = Configure.Instance.UIConfigureValue.BandPositionV2;
            lsCaller.Globals["judgmentPaintPosition"] = Configure.Instance.UIConfigureValue.JudgmentPaintPosition;
            lsCaller.Globals["judgmentVisualizerPosition"] = Configure.Instance.UIConfigureValue.JudgmentVisualizerPosition;
            lsCaller.Globals["hitNotePaintArea"] = Configure.Instance.UIConfigureValue.HitNotePaintArea;
            lsCaller.Globals["inputMapping"] = (int)Configure.Instance.InputMappingValue;
            lsCaller.Globals["P1Length"] = p1Length;
            lsCaller.Globals["P1BuiltLength"] = p1BuiltLengthFunc;
            lsCaller.Globals["P2BuiltLength"] = p2BuiltLengthFunc;
            lsCaller.Globals["Wall"] = new Func<double, float>(e => (float)(e + valueMap["mainPosition"] + p1BuiltLength));
            lsCaller.Globals["Contents"] = new Func<double, float>(e => (float)(valueMap["mainPosition"] + p1BuiltLengthFunc(e)));
            UI.Instance.SetConfigures(lsCaller);

            if (!string.IsNullOrEmpty(UI.Instance.UILS))
            {
                lsCaller.DoString(UI.Instance.UILS);
            }

            foreach (var (valueID, value) in UI.Instance.ValueMap)
            {
                valueMap[valueID] = value;
            }
            foreach (var (valueID, value) in UI.Instance.IntMap)
            {
                intMap[valueID] = value;
            }
            foreach (var (valueID, value) in UI.Instance.AltMap)
            {
                intMap[valueID] = has2P ? value : 0;
            }

            // 이 항목들은 Wall, Contents 함수등 기반이 되므로 먼저 처리
            SaveValueMap("mainPosition");
            for (var i = UI.MaxNoteID; i > 0; --i)
            {
                SaveValueMap($"noteLength{i}");
                SaveValueMap($"floatingNotePosition0{i}");
                SaveValueMap($"floatingNoteLength{i}");
                SaveValueMap($"slashNotePosition0{i}");
            }
            SaveSplitMap("noteLength", ref noteLengths);
            SaveSplitMap("floatingNotePosition0", ref floatingNotePosition0s);
            SaveSplitMap("floatingNoteLength", ref floatingNoteLengths);
            SaveSplitMap("slashNotePosition0", ref slashNotePosition0s);

            Array.Clear(DrawingNoteLengthMap, 0, DrawingNoteLengthMap.Length);
            Array.Clear(MainNoteLengthMap, 0, MainNoteLengthMap.Length);
            for (var i = inputCount; i > 0; --i)
            {
                if (floatingNoteLengths[i] > 0.0)
                {
                    DrawingNoteLengthMap[i] = floatingNoteLengths[i];
                    MainNoteLengthMap[i] = 0F;
                }
                else
                {
                    DrawingNoteLengthMap[i] = noteLengths[i];
                    MainNoteLengthMap[i] = noteLengths[i];
                }
            }

            Array.Clear(MainNoteLengthLevyingMap, 0, MainNoteLengthLevyingMap.Length);
            Array.Clear(MainNoteLengthBuiltMap, 0, MainNoteLengthBuiltMap.Length);
            for (var i = 1; i <= inputCount; ++i)
            {
                if (floatingNoteLengths[i] > 0.0)
                {
                    MainNoteLengthLevyingMap[i] = floatingNotePosition0s[i];
                    MainNoteLengthBuiltMap[i] = MainNoteLengthLevyingMap[i] + floatingNoteLengths[i];
                }
                else
                {
                    var inputMappingValue = (int)defaultComputer.InputMappingValue;
                    var j = Component.InputMappingValues[inputMappingValue, (int)inputMode][i];
                    MainNoteLengthLevyingMap[i] += slashNotePosition0s[i];
                    for (var m = 1; m < j; ++m)
                    {
                        var o = Component.BasePaintMap[inputMappingValue, (int)inputMode][m];
                        MainNoteLengthLevyingMap[i] += MainNoteLengthMap[o] + slashNotePosition0s[o];
                    }
                    MainNoteLengthBuiltMap[i] = MainNoteLengthLevyingMap[i] + MainNoteLengthMap[Component.BasePaintMap[inputMappingValue, (int)inputMode][j]];
                }
            }
            p1BuiltLength = p1BuiltLengthFunc(1.0);
            p2BuiltLength = p2BuiltLengthFunc(1.0);

            // 위에서 여러 항목이 계산되므로 모든 항목을 다시 설정한다.
            foreach (var valueID in UI.Instance.ValueCallMap.Keys)
            {
                SaveValueMap(valueID, true);
            }
            foreach (var (valueID, values) in UI.Instance.IntCallMap)
            {
                if (!intMap.ContainsKey(valueID))
                {
                    try
                    {
                        intMap[valueID] = (int)lsCaller.Call(lsCaller.Globals[values[0]], values.Skip(1).Select(value => Utility.ToFloat64(value) as object).ToArray()).Number;
                    }
                    catch
                    {
                        throw new ArgumentException($"{values[0]}({string.Join(", ", values.Skip(1))})");
                    }
                }
            }
            foreach (var (valueID, values) in UI.Instance.AltCallMap)
            {
                if (!intMap.ContainsKey(valueID))
                {
                    try
                    {
                        intMap[valueID] = has2P ? (int)lsCaller.Call(lsCaller.Globals[values[0]], values.Skip(1).Select(value => Utility.ToFloat64(value) as object).ToArray()).Number switch
                        {
                            0 => 0,
                            1 => 3,
                            2 => 2,
                            _ => 0
                        } : 0;
                    }
                    catch
                    {
                        throw new ArgumentException($"{values[0]}({string.Join(", ", values.Skip(1))})");
                    }
                }
            }

            void SaveValueMap(string target, bool doForce = false)
            {
                if ((doForce || !valueMap.ContainsKey(target)) && UI.Instance.ValueCallMap.TryGetValue(target, out var values))
                {
                    try
                    {
                        valueMap[target] = lsCaller.Call(lsCaller.Globals[values[0]], values.Skip(1).Select(value => Utility.ToFloat64(value) as object).ToArray()).Number;
                    }
                    catch
                    {
                        throw new ArgumentException($"{values[0]}({string.Join(", ", values.Skip(1))})");
                    }
                }
            }

            SaveSplitMap("noteHeight", ref noteHeights);
            SaveSplitMap("noteHeightJudgment", ref noteHeightJudgments);
            SaveSplitMap("inputPosition0", ref inputPosition0s);
            SaveSplitMap("inputPosition1", ref inputPosition1s);
            SaveSplitMap("inputLength", ref inputLengths);
            SaveSplitMap("inputHeight", ref inputHeights);
            SaveSplitMap("longNoteTailEdgeHeight", ref longNoteTailEdgeHeights);
            SaveSplitMap("longNoteTailEdgePosition", ref longNoteTailEdgePositions);
            SaveSplitMap("longNoteTailContentsHeight", ref longNoteTailContentsHeights);
            SaveSplitMap("longNoteFrontEdgeHeight", ref longNoteFrontEdgeHeights);
            SaveSplitMap("longNoteFrontEdgePosition", ref longNoteFrontEdgePositions);
            SaveSplitMap("longNoteFrontContentsHeight", ref longNoteFrontContentsHeights);
            SaveSplitMap("autoInputPosition1", ref autoInputPosition1s);
            SaveSplitMap("autoInputHeight", ref autoInputHeights);
            SaveSplitMap("judgmentMainPosition1", ref judgmentMainPosition1s);
            SaveSplitMap("judgmentMainHeight", ref judgmentMainHeights);
            SaveSplitMap("hitNotePaintPosition0", ref hitNotePaintPosition0s);
            SaveSplitMap("hitNotePaintPosition1", ref hitNotePaintPosition1s);
            SaveSplitMap("hitNotePaintLength", ref hitNotePaintLengths);
            SaveSplitMap("hitNotePaintHeight", ref hitNotePaintHeights);
            SaveSplitMap("hitLongNotePaintPosition0", ref hitLongNotePaintPosition0s);
            SaveSplitMap("hitLongNotePaintPosition1", ref hitLongNotePaintPosition1s);
            SaveSplitMap("hitLongNotePaintLength", ref hitLongNotePaintLengths);
            SaveSplitMap("hitLongNotePaintHeight", ref hitLongNotePaintHeights);
            SaveSplitMap("mainJudgmentMeterPosition1", ref mainJudgmentMeterPosition1s);
            SaveSplitMap("mainJudgmentMeterHeight", ref mainJudgmentMeterHeights);

            void SaveSplitMap(string target, ref float[] data)
            {
                var drawingInputMode = UI.Instance.DrawingInputModeMap[(int)inputMode];
                for (var i = inputCount; i > 0; --i)
                {
                    data[i] = (float)valueMap[$"{target}{drawingInputMode[i]}"];
                }
            }

            lock (PaintPropertyCSX)
            {
                PaintPropertyIDs.Clear();
                for (var i = UI.Instance.PaintProperties.Length - 1; i >= 0; --i)
                {
                    PaintPropertyMap[i].Clear();
                    PaintPropertyIntMap[i].Clear();

                    var paintProperty = UI.Instance.PaintProperties[i];
                    if (paintProperty != null)
                    {
                        PaintPropertyIDs.Add(i);

                        foreach (var (valueID, value) in paintProperty.ValueMap)
                        {
                            PaintPropertyMap[i][valueID] = value;
                        }
                        foreach (var (valueID, value) in paintProperty.AltMap)
                        {
                            PaintPropertyIntMap[i][valueID] = value;
                        }
                        foreach (var (valueID, value) in paintProperty.IntMap)
                        {
                            PaintPropertyIntMap[i][valueID] = value;
                        }
                        foreach (var (valueID, values) in paintProperty.ValueCallMap)
                        {
                            if (!PaintPropertyMap[i].ContainsKey(valueID))
                            {
                                try
                                {
                                    PaintPropertyMap[i][valueID] = lsCaller.Call(lsCaller.Globals[values[0]], values.Skip(1).Select(value => Utility.ToFloat64(value) as object).ToArray()).Number;
                                }
                                catch
                                {
                                    throw new ArgumentException($"{values[0]}({string.Join(", ", values.Skip(1))})");
                                }
                            }
                        }
                        foreach (var (valueID, values) in paintProperty.IntCallMap)
                        {
                            if (!PaintPropertyIntMap[i].ContainsKey(valueID))
                            {
                                try
                                {
                                    PaintPropertyIntMap[i][valueID] = (int)lsCaller.Call(lsCaller.Globals[values[0]], values.Skip(1).Select(value => Utility.ToFloat64(value) as object).ToArray()).Number;
                                }
                                catch
                                {
                                    throw new ArgumentException($"{values[0]}({string.Join(", ", values.Skip(1))})");
                                }
                            }
                        }
                        foreach (var (valueID, values) in paintProperty.AltCallMap)
                        {
                            if (!PaintPropertyIntMap[i].ContainsKey(valueID))
                            {
                                try
                                {
                                    PaintPropertyIntMap[i][valueID] = has2P ? (int)lsCaller.Call(lsCaller.Globals[values[0]], values.Skip(1).Select(value => Utility.ToFloat64(value) as object).ToArray()).Number switch
                                    {
                                        0 => 0,
                                        1 => 3,
                                        2 => 2,
                                        _ => 0
                                    } : 0;
                                }
                                catch
                                {
                                    throw new ArgumentException($"{values[0]}({string.Join(", ", values.Skip(1))})");
                                }
                            }
                        }
                    }
                }
            }

            var drawingComponent = typeof(DrawingComponent);
            foreach (var value in drawingComponent.GetFields().Where(value => !value.FieldType.IsArray && !value.IsInitOnly && value.Name != nameof(p1BuiltLength) && value.Name != nameof(p2BuiltLength)))
            {
                value.SetValue(this, default);
            }
            foreach (var (valueID, value) in valueMap)
            {
                drawingComponent.GetField(GetProperty(valueID))?.SetValue(this, (float)value);
            }
            foreach (var (valueID, value) in intMap)
            {
                drawingComponent.GetField(GetProperty(valueID))?.SetValue(this, value);
            }

            static string GetProperty(string property)
            {
                switch (property)
                {
                    case "alt-judgment-vs-visualizer":
                        return nameof(altJudgmentVSVisualizer);
                    case "alt-bpm":
                        return nameof(altBPM);
                    default:
                        property = property.Replace('!', '1');
                        var propertyLength = property.Length;
                        var builder = new StringBuilder();
                        for (var i = 0; i < propertyLength; ++i)
                        {
                            if (property[i] == '-')
                            {
                                builder.Append(property.Substring(i++ + 1, 1).ToUpperInvariant());
                            }
                            else
                            {
                                builder.Append(property[i]);
                            }
                        }
                        return builder.ToString();
                }
            }
        }
    }
}