diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b46e503 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ + +bin/* +obj/* +*.user +*.xcf +HarmonyPatches/RemoveSplashscreen.cs +HarmonyPatchHelper.cs +Screenshots/SocialPreview.jpg diff --git a/Configuration/Config.cs b/Configuration/Config.cs new file mode 100644 index 0000000..09db3c5 --- /dev/null +++ b/Configuration/Config.cs @@ -0,0 +1,35 @@ + +using IPA.Config.Stores; +using IPA.Config.Stores.Attributes; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(GeneratedStore.AssemblyVisibilityTarget)] +namespace HitscoreCounter { + internal class Config { + public static Config Instance { get; set; } + + + public virtual bool verticalLayout { get; set; } = true; + + [NonNullable, UseConverter] + public virtual List splits { get; set; } = new List() { 115, 114, 110, 100, 0 }; + + public static IEnumerable FilterSplitsList(IEnumerable splits) { + var x = splits.Where(x => x <= ScoreModel.kMaxCutRawScore && x >= 0).Distinct().OrderByDescending(x => x); + + if(!x.Any()) + return new[] { 115 }; + + return x; + } + + public virtual void Changed() { + var x = FilterSplitsList(splits); + + if(!x.SequenceEqual(splits)) + splits = x.ToList(); + } + } +} diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..cf3ef17 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,101 @@ + + + + + 2.0 + + false + + $(OutputPath)$(AssemblyName) + + $(OutputPath)Final + True + + + + + + + + + + + + + + + + $(BasePluginVersion) + $(BasePluginVersion) + $(BasePluginVersion) + + + + + + + + + $(AssemblyName) + $(ArtifactName)-$(PluginVersion) + $(ArtifactName)-bs$(GameVersion) + $(ArtifactName)-$(CommitHash) + + + + + + + $(AssemblyName) + + + + + + + + + + + + + + $(AssemblyName) + $(OutDir)zip\ + + + + + + + + + + + + + $(BeatSaberDir)\Plugins + True + Unable to copy assembly to game folder, did you set 'BeatSaberDir' correctly in your 'csproj.user' file? Plugins folder doesn't exist: '$(PluginDir)'. + + Unable to copy to Plugins folder, '$(BeatSaberDir)' does not appear to be a Beat Saber game install. + + Unable to copy to Plugins folder, 'BeatSaberDir' has not been set in your 'csproj.user' file. + False + + + + + + + + $(BeatSaberDir)\IPA\Pending\Plugins + + + + + + + + \ No newline at end of file diff --git a/HitscoreCounter.cs b/HitscoreCounter.cs new file mode 100644 index 0000000..bd9fc56 --- /dev/null +++ b/HitscoreCounter.cs @@ -0,0 +1,123 @@ +using CountersPlus.Counters.Custom; +using CountersPlus.Counters.Interfaces; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using TMPro; +using UnityEngine; + +namespace HitscoreCounter { + public class HitscoreCounter : BasicCustomCounter, INoteEventHandler, ISaberSwingRatingCounterDidFinishReceiver { + TMP_Text[] hintLabels; + TMP_Text[] valueLabels; + int[] targets; + int[] values; + + public override void CounterInit() { + var label = CanvasUtility.CreateTextFromSettings(Settings); + label.text = "Hitscores"; + label.fontSize = 3; + + TMP_Text CreateLabel(TextAlignmentOptions align, Vector3 offset, float fontSize = 2.69f) { + var x = CanvasUtility.CreateTextFromSettings(Settings, offset); + x.text = "0"; + x.alignment = align; + x.fontSize = fontSize; + + return x; + } + + var countersCount = Config.Instance.splits.Count; + + hintLabels = new TMP_Text[countersCount]; + valueLabels = new TMP_Text[countersCount]; + values = new int[countersCount]; + targets = new int[countersCount]; + + var totalWidth = countersCount * 0.5f; + var halfWidth = totalWidth / 2f; + var labelStep = totalWidth / (countersCount - 1); + + if(Config.Instance.verticalLayout) { + for(var i = countersCount; i-- != 0;) { + hintLabels[i] = CreateLabel(TextAlignmentOptions.CaplineRight, new Vector3(-0.25f, -0.3f - (i * 0.25f))); + valueLabels[i] = CreateLabel(TextAlignmentOptions.CaplineLeft, new Vector3(0.25f, -0.3f - (i * 0.25f)), 3f); + } + } else { + if(countersCount == 1) { + labelStep = 0; + halfWidth = 0; + } + + for(var i = countersCount; i-- != 0;) { + hintLabels[i] = CreateLabel(TextAlignmentOptions.Center, new Vector3((i * labelStep) - halfWidth, -0.3f)); + valueLabels[i] = CreateLabel(TextAlignmentOptions.Center, new Vector3((i * labelStep) - halfWidth, -0.6f), 3f); + } + } + + var prevValue = ScoreModel.kMaxCutRawScore + 1; + for(var i = 0; i < countersCount; i++) { + if(!Config.Instance.verticalLayout) + hintLabels[i].fontStyle = FontStyles.Underline; + + if(i == countersCount - 1 && Config.Instance.splits[i] == 0) { + hintLabels[i].text = $"<{prevValue}"; + targets[i] = -1; + break; + } + + if(prevValue - Config.Instance.splits[i] > 1) { + if(i == 0) { + hintLabels[i].text = $">{Config.Instance.splits[i] - 1}"; + } else { + hintLabels[i].text = $"{prevValue - 1}-{Config.Instance.splits[i]}"; + + if(!Config.Instance.verticalLayout) + hintLabels[i].fontSize = 2.2f; + } + } else { + hintLabels[i].text = Config.Instance.splits[i].ToString(); + } + prevValue = Config.Instance.splits[i]; + targets[i] = Config.Instance.splits[i] - 1; + } + } + + public override void CounterDestroy() { + hintLabels = null; + valueLabels = null; + targets = null; + values = null; + } + + void IncrementValueLabelForHitscore(int hitscore) { + for(var i = 0; i < targets.Length; i++) { + if(hitscore > targets[i]) { + valueLabels[i].text = (++values[i]).ToString(); + return; + } + } + } + + private Dictionary noteCutAccs = new Dictionary(); + public void OnNoteCut(NoteData data, NoteCutInfo info) { + if(!info.allIsOK || data.colorType == ColorType.None) + return; + + noteCutAccs.Add(info.swingRatingCounter, info.cutDistanceToCenter); + info.swingRatingCounter.RegisterDidFinishReceiver(this); + } + + public void OnNoteMiss(NoteData data) { } + + public void HandleSaberSwingRatingCounterDidFinish(ISaberSwingRatingCounter saberSwingRatingCounter) { + if(!noteCutAccs.TryGetValue(saberSwingRatingCounter, out var nci)) + return; + + noteCutAccs.Remove(saberSwingRatingCounter); + + ScoreModel.RawScoreWithoutMultiplier(saberSwingRatingCounter, nci, out int beforeCut, out int afterCut, out int cutDistance); + + IncrementValueLabelForHitscore(beforeCut + afterCut + cutDistance); + } + } +} diff --git a/HitscoreCounter.csproj b/HitscoreCounter.csproj new file mode 100644 index 0000000..0786ab3 --- /dev/null +++ b/HitscoreCounter.csproj @@ -0,0 +1,126 @@ + + + net48 + Library + 8 + false + HitscoreCounter + ..\Refs + $(LocalRefsDir) + $(MSBuildProjectDirectory)\ + disable + HitscoreCounter + + Kinsi55 + Kinsi55 + + + + x64 + false + + + + + + DEBUG + true + portable + bin\Debug + + + + none + bin\ + + + + True + + + True + True + + + + + + + + + $(BeatSaberDir)\Libs\0Harmony.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\BeatmapCore.dll + + + $(BeatSaberDir)\Plugins\Counters+.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\GameplayCore.dll + + + + + + + + + $(BeatSaberDir)\Beat Saber_Data\Managed\Main.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\HMLib.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\HMUI.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\IPA.Loader.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\Unity.TextMeshPro.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.CoreModule.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.UI.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.UIElementsModule.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.UIModule.dll + + + $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.VRModule.dll + + + + + + + + + + 1.4.3 + build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Images/icon.png b/Images/icon.png new file mode 100644 index 0000000..4b36bec Binary files /dev/null and b/Images/icon.png differ diff --git a/Images/ss.jpg b/Images/ss.jpg new file mode 100644 index 0000000..7776b82 Binary files /dev/null and b/Images/ss.jpg differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cd106e6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Kinsi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Plugin.cs b/Plugin.cs new file mode 100644 index 0000000..a753c34 --- /dev/null +++ b/Plugin.cs @@ -0,0 +1,20 @@ +using IPA; +using IPA.Config.Stores; +using IPALogger = IPA.Logging.Logger; + +namespace HitscoreCounter { + [Plugin(RuntimeOptions.SingleStartInit)] + public class Plugin { + internal static Plugin Instance { get; private set; } + internal static IPALogger Log { get; private set; } + + internal static string Name => "HitscoreCounter"; + + [Init] + public void Init(IPALogger logger, IPA.Config.Config config) { + Config.Instance = config.Generated(); + Instance = this; + Log = logger; + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..59692e8 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# HitscoreCounter + +Counts the amoungts of cuts of a specific value. You can configure it to be vertical or Horizontal and can modify the ranges its split up into. + +By default the splits are `115,114,110,100,0` which thus counts 115s, 114s, 113-110, 109-100 and everything below 100 seperately + +--- + +The Game version(s) specific releases are compatible with are mentioned in the Release title (Its obviously possible latest is not supported assuming its been released recently). If you need the plugin for an older version - Grab an older release that fits 🤯 + +## Install + +#### You can always find the latest download in [The Releases](https://github.com/kinsi55/BeatSaber_HitscoreCounter/releases), simply drag the files into the respective folders + +### Requirements + +- [Counters+](https://github.com/Caeden117/CountersPlus) (Available in ModAssistant) + +![SS](Images/ss.jpg) \ No newline at end of file diff --git a/SettingsHandler.cs b/SettingsHandler.cs new file mode 100644 index 0000000..e17560f --- /dev/null +++ b/SettingsHandler.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +namespace HitscoreCounter { + class SettingsHandler : INotifyPropertyChanged { + Config config => Config.Instance; + + string splits { + get => string.Join(",", config.splits); + set { + config.splits = value + .Split(new[] { ",", ";", " " }, System.StringSplitOptions.RemoveEmptyEntries) + .Select(x => { + if(int.TryParse(x, out var l)) + return l; + + return -1; + }).ToList(); + + PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(splits))); + } + } + + private readonly string version = $"Version {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)} by Kinsi55\nCommissioned by zachakaquack"; + + public event PropertyChangedEventHandler PropertyChanged; + } +} \ No newline at end of file diff --git a/SuppressRefereces.targets b/SuppressRefereces.targets new file mode 100644 index 0000000..c45bc3a --- /dev/null +++ b/SuppressRefereces.targets @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..92ec1a3 --- /dev/null +++ b/manifest.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://raw.githubusercontent.com/bsmg/BSIPA-MetadataFileSchema/master/Schema.json", + "id": "HitscoreCounter", + "name": "HitscoreCounter", + "author": "Kinsi55", + "version": "0.1.0", + "description": "Counter for Counters+ that counts the scores of your cuts grouped into configurable ranges", + "gameVersion": "1.18.3", + "dependsOn": { + "BSIPA": "^4.0.5", + "Counters+": "^2.2.0" + }, + "features": { + "CountersPlus.CustomCounter": { + "Name": "Hitscore Counter", + "Description": "Counts the scores of your cuts grouped into configurable ranges", + "CounterLocation": "HitscoreCounter.HitscoreCounter", + "ConfigDefaults": { + "Enabled": true, + "Position": "BelowEnergy", + "Distance": 2 + }, + "BSML": { + "Resource": "HitscoreCounter.settings.bsml", + "Host": "HitscoreCounter.SettingsHandler", + "Icon": "HitscoreCounter.Images.icon.png" + } + } + } +} \ No newline at end of file diff --git a/settings.bsml b/settings.bsml new file mode 100644 index 0000000..53f0aac --- /dev/null +++ b/settings.bsml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file