├── .gitignore
├── Assets
├── Arrow.png
├── RRect.png
├── White.png
├── Circle.png
├── RRectMask.png
├── svg2png.bat
├── Arrow.svg
├── Circle.svg
├── rrect.svg
└── RRectMask.svg
├── Models
├── ScoreScalingMode.cs
└── ScoreScalingModeExt.cs
├── SliceVisualizer.csproj.user.example
├── Views
└── Main.bsml
├── manifest.json
├── Configuration
├── FloatConverter.cs
├── ColorConverter.cs
└── PluginConfig.cs
├── Installers
├── NsvGameInstaller.cs
└── NsvAppInstaller.cs
├── Factories
└── NsvBlockFactory.cs
├── Directory.Build.props
├── ViewControllers
└── MainViewController.cs
├── UI
├── SettingsUI.cs
└── SliceVisualizerFlowCoordinator.cs
├── LICENSE
├── SliceVisualizer.sln
├── Plugin.cs
├── NsvAssetLoader.cs
├── Core
├── NsvController.cs
└── NsvSlicedBlock.cs
├── README.md
├── SliceVisualizer.csproj
├── .editorconfig
└── Directory.Build.targets
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs
2 | bin
3 | obj
4 | *.user
5 |
6 | # JetBrains Rider
7 | .idea/
8 | *.sln.iml
--------------------------------------------------------------------------------
/Assets/Arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m1el/BeatSaber-SliceVisualizer/HEAD/Assets/Arrow.png
--------------------------------------------------------------------------------
/Assets/RRect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m1el/BeatSaber-SliceVisualizer/HEAD/Assets/RRect.png
--------------------------------------------------------------------------------
/Assets/White.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m1el/BeatSaber-SliceVisualizer/HEAD/Assets/White.png
--------------------------------------------------------------------------------
/Assets/Circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m1el/BeatSaber-SliceVisualizer/HEAD/Assets/Circle.png
--------------------------------------------------------------------------------
/Assets/RRectMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m1el/BeatSaber-SliceVisualizer/HEAD/Assets/RRectMask.png
--------------------------------------------------------------------------------
/Assets/svg2png.bat:
--------------------------------------------------------------------------------
1 | imagick -background none RRect.svg RRect.png
2 | imagick -background none Arrow.svg Arrow.png
3 | imagick -background none Circle.svg Circle.png
4 |
--------------------------------------------------------------------------------
/Models/ScoreScalingMode.cs:
--------------------------------------------------------------------------------
1 | namespace SliceVisualizer.Models
2 | {
3 | public enum ScoreScalingMode
4 | {
5 | Linear,
6 | Sqrt,
7 | Log
8 | }
9 | }
--------------------------------------------------------------------------------
/Assets/Arrow.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Assets/Circle.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Assets/rrect.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/SliceVisualizer.csproj.user.example:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | C:\Program Files (x86)\Steam\steamapps\common\Beat Saber
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Assets/RRectMask.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Views/Main.bsml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/beat-saber-modding-group/BSIPA-MetadataFileSchema/master/Schema.json",
3 | "id": "SliceVisualizer",
4 | "name": "SliceVisualizer",
5 | "author": "Igor null ",
6 | "version": "0.1.3",
7 | "description": "Shows your cut data to train your accuracy",
8 | "gameVersion": "1.13.4",
9 | "dependsOn": {
10 | "BeatSaberMarkupLanguage": "^1.5.2",
11 | "BSIPA": "^4.1.6",
12 | "SiraUtil": "^2.5.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Configuration/FloatConverter.cs:
--------------------------------------------------------------------------------
1 | using IPA.Config.Data;
2 |
3 | namespace SliceVisualizer.Configuration
4 | {
5 | internal static class FloatConverter
6 | {
7 | public static float ValueToFloat(Value val)
8 | {
9 | return val switch
10 | {
11 | FloatingPoint point => (float) point.Value,
12 | Integer integer => integer.Value,
13 | _ => throw new System.ArgumentException("List element was not a number"),
14 | };
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/Installers/NsvGameInstaller.cs:
--------------------------------------------------------------------------------
1 | using SliceVisualizer.Configuration;
2 | using SliceVisualizer.Core;
3 | using SliceVisualizer.Factories;
4 | using Zenject;
5 |
6 | namespace SliceVisualizer.Installers
7 | {
8 | internal class NsvGameInstaller : Installer
9 | {
10 | public NsvGameInstaller()
11 | {
12 | }
13 |
14 | public override void InstallBindings()
15 | {
16 | Container.BindFactory().AsSingle();
17 | Container.BindInterfacesAndSelfTo().AsSingle();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Factories/NsvBlockFactory.cs:
--------------------------------------------------------------------------------
1 | using SliceVisualizer.Core;
2 | using Zenject;
3 |
4 | namespace SliceVisualizer.Factories
5 | {
6 | internal class NsvBlockFactory : PlaceholderFactory
7 | {
8 | private readonly DiContainer _container;
9 |
10 | public NsvBlockFactory(DiContainer container)
11 | {
12 | _container = container;
13 | }
14 |
15 | public override NsvSlicedBlock Create()
16 | {
17 | var slicedBlock = _container.InstantiateComponentOnNewGameObject();
18 | slicedBlock.gameObject.name = $"{nameof(NsvSlicedBlock)} (Factorized)";
19 |
20 | return slicedBlock;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | true
9 | true
10 | true
11 |
12 |
13 | false
14 | true
15 | true
16 |
17 |
--------------------------------------------------------------------------------
/ViewControllers/MainViewController.cs:
--------------------------------------------------------------------------------
1 | using BeatSaberMarkupLanguage.Attributes;
2 | using BeatSaberMarkupLanguage.ViewControllers;
3 | using SliceVisualizer.Configuration;
4 |
5 | namespace SliceVisualizer.ViewControllers
6 | {
7 | internal class MainViewController : BSMLResourceViewController
8 | {
9 | public void Activated()
10 | {
11 | NotifyPropertyChanged("EnabledValue");
12 | }
13 | [UIValue("Enabled-value")]
14 | public bool EnabledValue
15 | {
16 | get => PluginConfig.Instance.Enabled;
17 | set
18 | {
19 | PluginConfig.Instance.Enabled = value;
20 | }
21 | }
22 |
23 | public override string ResourceName => "SliceVisualizer.Views.Main.bsml";
24 | }
25 | }
--------------------------------------------------------------------------------
/Installers/NsvAppInstaller.cs:
--------------------------------------------------------------------------------
1 | using IPA.Logging;
2 | using SiraUtil;
3 | using SliceVisualizer.Configuration;
4 | using SliceVisualizer.UI;
5 | using Zenject;
6 |
7 | namespace SliceVisualizer.Installers
8 | {
9 | internal class NsvAppInstaller : Installer
10 | {
11 | private readonly Logger _logger;
12 | private readonly PluginConfig _config;
13 |
14 | public NsvAppInstaller(Logger logger, PluginConfig config)
15 | {
16 | _logger = logger;
17 | _config = config;
18 | PluginConfig.Instance = config;
19 | SettingsUI.CreateMenu();
20 | }
21 |
22 | public override void InstallBindings()
23 | {
24 | Container.BindLoggerAsSiraLogger(_logger);
25 |
26 | Container.BindInstance(_config).AsSingle();
27 |
28 | Container.BindInterfacesAndSelfTo().AsSingle().Lazy();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/Models/ScoreScalingModeExt.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 |
4 | namespace SliceVisualizer.Models
5 | {
6 | public static class ScoreScalingModeExt
7 | {
8 | public static float ApplyScaling(this ScoreScalingMode mode, float offset, float min, float max)
9 | {
10 | Func transform = mode switch
11 | {
12 | ScoreScalingMode.Linear => (x => x),
13 | ScoreScalingMode.Log => Mathf.Log,
14 | ScoreScalingMode.Sqrt => Mathf.Sqrt,
15 | _ => (x => x),
16 | };
17 |
18 | var sign = Mathf.Sign(offset);
19 | offset = Mathf.Abs(offset);
20 |
21 | if (offset < min)
22 | {
23 | return 0.0f;
24 | }
25 |
26 | var tMin = transform(min);
27 | var tMax = transform(max);
28 | offset = (transform(offset) - tMin) / (tMax - tMin);
29 |
30 | return Mathf.Clamp(sign * offset, -0.5f, 0.5f);
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/UI/SettingsUI.cs:
--------------------------------------------------------------------------------
1 | using BeatSaberMarkupLanguage;
2 | using BeatSaberMarkupLanguage.MenuButtons;
3 |
4 | namespace SliceVisualizer.UI
5 | {
6 | internal class SettingsUI
7 | {
8 | public static SliceVisualizerFlowCoordinator? SliceVisualizerFlowCoordinator;
9 | public static bool Created;
10 |
11 | public static void CreateMenu()
12 | {
13 | if (!Created)
14 | {
15 | var menuButton = new MenuButton("SliceVisualizer", "Chase the perfect slice", ShowFlow);
16 | MenuButtons.instance.RegisterButton(menuButton);
17 | Created = true;
18 | }
19 | }
20 |
21 | public static void ShowFlow()
22 | {
23 | if (SliceVisualizerFlowCoordinator == null)
24 | {
25 | SliceVisualizerFlowCoordinator = BeatSaberUI.CreateFlowCoordinator();
26 | }
27 | BeatSaberUI.MainFlowCoordinator.PresentFlowCoordinator(SliceVisualizerFlowCoordinator);
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2020 Igor null
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SliceVisualizer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30804.86
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SliceVisualizer", "SliceVisualizer.csproj", "{16235F7D-5042-4185-8EC7-E555DA68A2F8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {16235F7D-5042-4185-8EC7-E555DA68A2F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {16235F7D-5042-4185-8EC7-E555DA68A2F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {16235F7D-5042-4185-8EC7-E555DA68A2F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {16235F7D-5042-4185-8EC7-E555DA68A2F8}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {E889DCF9-0744-4AB0-9C59-2A866F1E774B}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Plugin.cs:
--------------------------------------------------------------------------------
1 | using IPA;
2 | using IPA.Config;
3 | using IPA.Config.Stores;
4 | using IPA.Logging;
5 | using SiraUtil.Zenject;
6 | using SliceVisualizer.Configuration;
7 | using SliceVisualizer.Installers;
8 |
9 |
10 | namespace SliceVisualizer
11 | {
12 | [Plugin(RuntimeOptions.DynamicInit)]
13 | public class Plugin
14 | {
15 | internal static Logger Log = null!;
16 | ///
17 | /// Called when the plugin is first loaded by IPA (either when the game starts or when the plugin is enabled if it starts disabled).
18 | /// [Init] methods that use a Constructor or called before regular methods like InitWithConfig.
19 | /// Only use [Init] with one Constructor.
20 | ///
21 | [Init]
22 | public void Init(Logger logger, Config conf, Zenjector zenject)
23 | {
24 | Log = logger;
25 | zenject.OnApp().WithParameters(logger, conf.Generated());
26 | zenject.OnGame(false).ShortCircuitForTutorial();
27 | }
28 |
29 | [OnEnable, OnDisable]
30 | public void OnStateChanged()
31 | {
32 | // Zenject is poggers
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Configuration/ColorConverter.cs:
--------------------------------------------------------------------------------
1 | using IPA.Config.Data;
2 | using IPA.Config.Stores;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | namespace SliceVisualizer.Configuration
7 | {
8 | internal class ColorConverter : ValueConverter
9 | {
10 | public override Color FromValue(Value value, object parent)
11 | {
12 | switch (value)
13 | {
14 | case List list:
15 | {
16 | var array = list.Select(FloatConverter.ValueToFloat).ToArray();
17 | return new Color(array[0], array[1], array[2], array[3]);
18 | }
19 |
20 | case Text text:
21 | {
22 | return ColorUtility.TryParseHtmlString(text.Value, out var color) ? color : Color.white;
23 | }
24 |
25 | default:
26 | throw new System.ArgumentException("Color deserializer expects either string or array");
27 | }
28 | }
29 |
30 | public override Value ToValue(Color obj, object parent)
31 | {
32 | var array = new[] { obj.r, obj.g, obj.b, obj.a };
33 | return Value.From(array.Select(x => Value.Float((decimal)x)));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/UI/SliceVisualizerFlowCoordinator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BeatSaberMarkupLanguage;
3 | using HMUI;
4 | using SliceVisualizer.ViewControllers;
5 |
6 | namespace SliceVisualizer.UI
7 | {
8 | internal class SliceVisualizerFlowCoordinator : FlowCoordinator
9 | {
10 | private MainViewController? _mainViewController;
11 | // private BindingsViewController _bindingsViewController;
12 | // private MiscViewController _miscViewController;
13 | // private ThresholdViewController _thresholdViewController;
14 |
15 | public void Awake()
16 | {
17 | if (!_mainViewController)
18 | {
19 | _mainViewController = BeatSaberUI.CreateViewController();
20 | }
21 | }
22 |
23 | protected override void DidActivate(bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling)
24 | {
25 | try
26 | {
27 | if (firstActivation)
28 | {
29 | SetTitle("SliceVisualizer settings");
30 | showBackButton = true;
31 | ProvideInitialViewControllers(_mainViewController);
32 | }
33 | _mainViewController?.Activated();
34 | }
35 | catch (Exception e)
36 | {
37 | Plugin.Log.Error(e);
38 | }
39 | }
40 |
41 | protected override void BackButtonWasPressed(ViewController topViewController)
42 | {
43 | BeatSaberUI.MainFlowCoordinator.DismissFlowCoordinator(this);
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/Configuration/PluginConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using IPA.Config.Stores;
3 | using IPA.Config.Stores.Attributes;
4 | using IPA.Config.Stores.Converters;
5 | using SiraUtil.Converters;
6 | using UnityEngine;
7 | using SliceVisualizer.Models;
8 |
9 | [assembly: InternalsVisibleTo(GeneratedStore.AssemblyVisibilityTarget)]
10 | namespace SliceVisualizer.Configuration
11 | {
12 | internal class PluginConfig
13 | {
14 | internal static PluginConfig Instance = null!;
15 | public virtual bool Enabled { get; set; } = true;
16 | public virtual float SliceWidth { get; set; } = 0.05f;
17 |
18 | [UseConverter(typeof(EnumConverter))]
19 | public virtual ScoreScalingMode ScoreScaling { get; set; } = ScoreScalingMode.Linear;
20 | public virtual float ScoreScaleMin { get; set; } = 0.05f;
21 | public virtual float ScoreScaleMax { get; set; } = 0.5f;
22 | public virtual float ScoreScale { get; set; } = 1.0f;
23 | [UseConverter(typeof(ColorConverter))]
24 | public virtual Color MissedAreaColor { get; set; } = new Color(0f, 0f, 0f, 0.5f);
25 | [UseConverter(typeof(ColorConverter))]
26 | public virtual Color SliceColor { get; set; } = new Color(1f, 1f, 1f, 1f);
27 | [UseConverter(typeof(ColorConverter))]
28 | public virtual Color ArrowColor { get; set; } = new Color(1f, 1f, 1f, 1f);
29 | [UseConverter(typeof(ColorConverter))]
30 | public virtual Color BadDirectionColor { get; set; } = new Color(0f, 0f, 0f, 1f);
31 | [UseConverter(typeof(ColorConverter))]
32 | public virtual Color CenterColor { get; set; } = new Color(1f, 1f, 1f, 1f);
33 | public virtual bool UseCustomColors { get; set; } = false;
34 | [UseConverter(typeof(ColorConverter))]
35 | public virtual Color LeftColor { get; set; } = new Color(0.659f, 0.125f, 0.125f, 1f);
36 | [UseConverter(typeof(ColorConverter))]
37 | public virtual Color RightColor { get; set; } = new Color(0.125f, 0.392f, 0.659f, 1f);
38 | public virtual float CubeLifetime { get; set; } = 1f;
39 | public virtual float PopEnd { get; set; } = 0.1f;
40 | public virtual float FadeStart { get; set; } = 0.5f;
41 | public virtual float PopDistance { get; set; } = 0.5f;
42 | public virtual bool PositionFromCubeTransform { get; set; } = true;
43 | public virtual bool RotationFromCubeTransform { get; set; } = true;
44 | public virtual float CubeScale { get; set; } = 0.9f;
45 | public virtual float CenterScale { get; set; } = 0.2f;
46 | public virtual float ArrowScale { get; set; } = 0.6f;
47 | public virtual float UIOpacity { get; set; } = 1.0f;
48 | [UseConverter(typeof(Vector3Converter))]
49 | public virtual Vector3 CanvasOffset { get; set; } = new Vector3(0f, 0f, 16f);
50 | public virtual float CanvasScale { get; set; } = 1f;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/NsvAssetLoader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using SiraUtil.Tools;
5 | using UnityEngine;
6 | using Zenject;
7 |
8 | namespace SliceVisualizer
9 | {
10 | internal class NsvAssetLoader : IInitializable, IDisposable
11 | {
12 | private readonly SiraLog _siraLog;
13 |
14 | private Material? _uiNoGlowMaterial;
15 | private bool _loggedNoGlowMaterial = false;
16 |
17 | public Material? UINoGlowMaterial {
18 | get {
19 | if (!(_uiNoGlowMaterial is null))
20 | {
21 | return _uiNoGlowMaterial;
22 | }
23 | var sprite = Resources.FindObjectsOfTypeAll().FirstOrDefault(m => m.name == "GameUISprite");
24 | if (sprite is null)
25 | {
26 | if (!_loggedNoGlowMaterial)
27 | {
28 | _loggedNoGlowMaterial = true;
29 | _siraLog.Error("Trying to get GameUISprite before it was loaded. This should not happen.");
30 | }
31 | return null;
32 | }
33 |
34 | _uiNoGlowMaterial = new Material(sprite);
35 | return _uiNoGlowMaterial;
36 | }
37 | }
38 |
39 | public Sprite? RRect { get; private set; }
40 | public Sprite? Circle { get; private set; }
41 | public Sprite? Arrow { get; private set; }
42 | public Sprite? White { get; private set; }
43 |
44 | public NsvAssetLoader(SiraLog siraLog)
45 | {
46 | _siraLog = siraLog;
47 | }
48 |
49 | public void Initialize()
50 | {
51 | var assembly = Assembly.GetExecutingAssembly();
52 | RRect = LoadSpriteFromResources(assembly, "SliceVisualizer.Assets.RRect.png");
53 | Circle = LoadSpriteFromResources(assembly, "SliceVisualizer.Assets.Circle.png");
54 | Arrow = LoadSpriteFromResources(assembly, "SliceVisualizer.Assets.Arrow.png");
55 | White = LoadSpriteFromResources(assembly, "SliceVisualizer.Assets.White.png", 1f);
56 | }
57 |
58 | public void Dispose()
59 | {
60 | _uiNoGlowMaterial = null;
61 |
62 | RRect = null;
63 | Circle = null;
64 | Arrow = null;
65 | White = null;
66 | }
67 |
68 | private Sprite? LoadSpriteFromResources(Assembly assembly, string resourcePath, float pixelsPerUnit = 256.0f)
69 | {
70 | using var stream = assembly.GetManifestResourceStream(resourcePath);
71 | if (stream == null)
72 | {
73 | _siraLog.Warning($"Couldn't find embedded resource {resourcePath}");
74 | return null;
75 | }
76 |
77 | byte[] imageData = new byte[stream.Length];
78 | stream.Read(imageData, 0, (int) stream.Length);
79 | if (imageData.Length == 0)
80 | {
81 | return null;
82 | }
83 |
84 | var texture = new Texture2D(2, 2, TextureFormat.RGBA32, false, false);
85 | texture.LoadImage(imageData);
86 |
87 | var rect = new Rect(0, 0, texture.width, texture.height);
88 | var sprite = Sprite.Create(texture, rect, Vector2.zero, pixelsPerUnit);
89 |
90 | _siraLog.Info($"Successfully loaded sprite {resourcePath}, w={texture.width}, h={texture.height}");
91 |
92 | return sprite;
93 | }
94 | }
95 | }
--------------------------------------------------------------------------------
/Core/NsvController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SliceVisualizer.Configuration;
3 | using UnityEngine;
4 | using UnityEngine.SceneManagement;
5 | using UnityEngine.UI;
6 | using Zenject;
7 | using HMUI;
8 | using BeatSaberMarkupLanguage.Tags;
9 | using BeatSaberMarkupLanguage.Components.Settings;
10 | using SiraUtil.Tools;
11 |
12 | namespace SliceVisualizer.Core
13 | {
14 | internal class NsvController : IInitializable, ITickable, IDisposable
15 | {
16 | private readonly PluginConfig _config;
17 | private readonly SiraLog _logger;
18 | private readonly BeatmapObjectManager _beatmapObjectManager;
19 | private readonly NsvSlicedBlock[] _slicedBlockPool;
20 | private readonly Factories.NsvBlockFactory _blockFactory;
21 |
22 | private GameObject _canvasGO = null!;
23 |
24 | private static readonly int MaxItems = 12;
25 |
26 | public NsvController(BeatmapObjectManager beatmapObjectManager, Factories.NsvBlockFactory blockFactory, SiraLog logger)
27 | {
28 | _config = PluginConfig.Instance;
29 | _logger = logger;
30 | _beatmapObjectManager = beatmapObjectManager;
31 | _slicedBlockPool = new NsvSlicedBlock[MaxItems];
32 | _blockFactory = blockFactory;
33 | }
34 |
35 | public void Initialize()
36 | {
37 | _canvasGO = new GameObject("SliceVisualizerCanvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
38 | var canvas = _canvasGO.GetComponent