Compare commits

...

16 commits

Author SHA1 Message Date
Nikolay Kuznetsov f905428238
Merge pull request #23 from DubyaDude/master
Move to api/v1 + additional QOL changes
2022-06-16 20:37:22 +02:00
Usman Shafiq b74c421bbb Added IsRetired (ApprovalStatus 3) 2022-06-15 18:15:32 -04:00
Usman Shafiq 71efc3990f Fixed download file name 2022-06-12 02:35:56 -04:00
Usman Shafiq d57e730baa Version bump 2022-06-12 00:57:50 -04:00
Usman Shafiq 2adb976b21 On Agree Removed Windows Notif + Move To Mods. Search bar enabled by default + made bigger 2022-06-12 00:22:23 -04:00
Usman Shafiq 59cd085130 Moved to api/v1 + Moved Broken to bottom 2022-06-12 00:04:03 -04:00
Nikolay Kuznetsov 992480facc Handle missing directories for deleting all mods 2021-07-16 01:59:08 +02:00
Nikolay Kuznetsov 8160521d10 Add a bit of exception handling to headpats/hugs buttons 2021-07-16 01:59:08 +02:00
Nikolay Kuznetsov a6321a9ecc Let SemVer handle four-digit version numbers 2021-07-16 01:59:08 +02:00
Nikolay Kuznetsov 88c987d714 Bump version again 2021-07-16 01:59:08 +02:00
Nikolay Kuznetsov 610098dcbf
Fix formatting 2021-07-15 22:45:05 +02:00
Nikolay Kuznetsov ec8cd210f7 Bump version 2021-07-15 19:43:24 +02:00
Nikolay Kuznetsov 66d2b41de8 Update default mods 2021-07-15 19:42:36 +02:00
Nikolay Kuznetsov ed27510ccc Update hardcoded categories for new mods 2021-07-15 19:42:15 +02:00
Nikolay Kuznetsov 0f60e68c02 Use latest ML installer instead of 0.3.0 2021-07-15 19:41:57 +02:00
Nikolay Kuznetsov f250bb893c Fix hyperlinks in mod info page 2021-05-29 22:02:39 +02:00
14 changed files with 143 additions and 64 deletions

View file

@ -1,4 +1,4 @@
#[Download here!](https://github.com/knah/VRCMelonAssistant/releases/latest) # [Download here!](https://github.com/knah/VRCMelonAssistant/releases/latest)
VRChat Melon Assistant is a PC mod installer for VRChat. It uses mods published in [VRChat Modding Group Discord](https://discord.gg/rCqKSvR). VRChat Melon Assistant is a PC mod installer for VRChat. It uses mods published in [VRChat Modding Group Discord](https://discord.gg/rCqKSvR).
It's a (very stripped down) fork of [Assistant's Mod Assistant](https://github.com/Assistant/ModAssistant), a mod manager for Beat Saber. It's a (very stripped down) fork of [Assistant's Mod Assistant](https://github.com/Assistant/ModAssistant), a mod manager for Beat Saber.

View file

@ -6,8 +6,8 @@ namespace VRCMelonAssistant
{ {
private static readonly Dictionary<string, List<string>> CategoryContents = new() private static readonly Dictionary<string, List<string>> CategoryContents = new()
{ {
{"Safety & Security", new() {"Advanced Safety", "Finitizer", "True Shader Anticrash", "Safety-Presets"}}, {"Safety & Security", new() {"Advanced Safety", "Finitizer", "True Shader Anticrash", "Safety-Presets", "Final IK Sanity"}},
{"Core mods and libraries", new() {"UI Expansion Kit", "ActionMenuApi", "VRCModUpdater.Loader"}}, {"Core mods and libraries", new() {"UI Expansion Kit", "ActionMenuApi", "VRCModUpdater.Loader", "VRChatUtilityKit"}},
{"All-in-one mods", new() {"emmVRCLoader"}}, {"All-in-one mods", new() {"emmVRCLoader"}},
{"Camera mods", new() { {"Camera mods", new() {
"CameraMinus", "DesktopCamera", "BetterSteadycam", "ITR's Melon Cameras", "CameraResChanger", "CameraMinus", "DesktopCamera", "BetterSteadycam", "ITR's Melon Cameras", "CameraResChanger",
@ -15,16 +15,17 @@ namespace VRCMelonAssistant
}}, }},
{"Performance & Fidelity", new() { {"Performance & Fidelity", new() {
"Core Limiter", "MirrorResolutionUnlimiter", "AvatarHider", "Runtime Graphics Settings", "Core Limiter", "MirrorResolutionUnlimiter", "AvatarHider", "Runtime Graphics Settings",
"GamePriority", "FrameFocus", "ClearVRAM", "NoPerformanceStats" "GamePriority", "FrameFocus", "ClearVRAM", "NoPerformanceStats", "Turbones"
}}, }},
{"Utilities & Tweaks", new() { {"Utilities & Tweaks", new() {
"ReloadAvatars", "KeyboardPaste", "No Outlines", "UnmuteSound", "SparkleBeGone", "ReloadAvatars", "KeyboardPaste", "No Outlines", "UnmuteSound", "SparkleBeGone",
"BTKSAImmersiveHud", "OGTrustRanks", "ToggleMicIcon", "Friends+ home", "BTKSAImmersiveHud", "OGTrustRanks", "ToggleMicIcon", "Friends+ home",
"MicSensitivity", "CloningBeGone", "ToggleFullScreen", "View Point Tweaker", "MicSensitivity", "CloningBeGone", "ToggleFullScreen", "View Point Tweaker",
"SettingsRestart", "SmallUserVolume", "TeleportCameraToYou", "SettingsRestart", "SmallUserVolume", "TeleportCameraToYou",
"BetterPortalPlacement" "BetterPortalPlacement", "BetterDirections", "ChairExitController",
"Panic Button Rework", "SelectYourself", "Trust Color Changer", "Voice Falloff Override"
}}, }},
{"Hardware support", new() {"LeapMotionExtension", "ThumbParams", "VRCFaceTracking", "VRCPimaxEyeTracker"}}, {"Hardware support", new() {"LeapMotionExtension", "ThumbParams", "VRCFaceTracking", "VRCPimaxEyeTracker", "VRCBhapticsIntegration"}},
{"Dynamic bones", new() { {"Dynamic bones", new() {
"ImmersiveTouch", "Dynamic Bones Safety", "MultiplayerDynamicBonesMod", "Multiplayer Dynamic Bones", "ImmersiveTouch", "Dynamic Bones Safety", "MultiplayerDynamicBonesMod", "Multiplayer Dynamic Bones",
}}, }},
@ -36,12 +37,14 @@ namespace VRCMelonAssistant
"IKTweaks", "JoinNotifier", "FBT Saver", "BTKSANameplateMod", "AdvancedInvites", "VRCVideoLibrary", "IKTweaks", "JoinNotifier", "FBT Saver", "BTKSANameplateMod", "AdvancedInvites", "VRCVideoLibrary",
"BTKSASelfPortrait", "OldMate", "BetterLoadingScreen", "Loading Screen Pictures", "FavCat", "BTKSASelfPortrait", "OldMate", "BetterLoadingScreen", "Loading Screen Pictures", "FavCat",
"ActionMenuUtils", "WorldPredownload", "AskToPortal", "Headlight", "ITR's Player Tracer", "ActionMenuUtils", "WorldPredownload", "AskToPortal", "Headlight", "ITR's Player Tracer",
"InstanceHistory", "PortableMirrorMod", "VRCBonesController" "InstanceHistory", "PortableMirrorMod", "VRCBonesController", "CalibrationLinesVisualizer",
"ITR's Collider Mod", "RememberMe", "TriggerESP"
}}, }},
{"UI mods", new() { {"UI mods", new() {
"Particle and DynBone limiter settings UI", "CalibrateConfirm", "Emoji Page Buttons", "Particle and DynBone limiter settings UI", "CalibrateConfirm", "Emoji Page Buttons",
"UserInfoExtensions", "MLConsoleViewer", "OwO Mod", "ActiveBackground", "PlayerList", "ComfyVRMenu", "UserInfoExtensions", "MLConsoleViewer", "OwO Mod", "ActiveBackground", "PlayerList", "ComfyVRMenu",
"DiscordMute", "MicToggle", "VRCPlusPet" "DiscordMute", "MicToggle", "VRCPlusPet", "AMMusic", "Friend Notes", "GestureIndicator",
"NameplateStats", "PreviewScroller", "ProPlates", "QuickMenuVolume", "ToggleUIStickers"
}}, }},
{"Movement", new() { {"Movement", new() {
"TeleporterVR", "ImmobilizePlayerMod", "TrackingRotator", "OculusPlayspaceMover", "TeleporterVR", "ImmobilizePlayerMod", "TrackingRotator", "OculusPlayspaceMover",

View file

@ -46,7 +46,7 @@ namespace VRCMelonAssistant
{ {
MainWindow.Instance.MainText = $"{(string) App.Current.FindResource("Mods:DownloadingMelonLoader")}..."; MainWindow.Instance.MainText = $"{(string) App.Current.FindResource("Mods:DownloadingMelonLoader")}...";
using var installerZip = await DownloadFileToMemory("https://github.com/LavaGang/MelonLoader/releases/download/v0.3.0/MelonLoader.x64.zip"); using var installerZip = await DownloadFileToMemory("https://github.com/LavaGang/MelonLoader/releases/latest/download/MelonLoader.x64.zip");
using var zipReader = new ZipArchive(installerZip, ZipArchiveMode.Read); using var zipReader = new ZipArchive(installerZip, ZipArchiveMode.Read);
MainWindow.Instance.MainText = $"{(string) App.Current.FindResource("Mods:UnpackingMelonLoader")}..."; MainWindow.Instance.MainText = $"{(string) App.Current.FindResource("Mods:UnpackingMelonLoader")}...";
@ -80,7 +80,7 @@ namespace VRCMelonAssistant
public static async Task InstallMod(Mod mod) public static async Task InstallMod(Mod mod)
{ {
string downloadLink = mod.versions[0].downloadlink; string downloadLink = mod.versions[0].downloadLink;
if (string.IsNullOrEmpty(downloadLink)) if (string.IsNullOrEmpty(downloadLink))
{ {
@ -90,22 +90,28 @@ namespace VRCMelonAssistant
if (mod.installedFilePath != null) if (mod.installedFilePath != null)
File.Delete(mod.installedFilePath); File.Delete(mod.installedFilePath);
var modUri = new Uri(downloadLink); string targetFilePath = "";
var targetFilePath = Path.Combine(App.VRChatInstallDirectory, mod.versions[0].IsPlugin ? "Plugins" : "Mods",
mod.versions[0].IsBroken ? "Broken" : "", modUri.Segments.Last());
Directory.CreateDirectory(Path.GetDirectoryName(targetFilePath)); using (var resp = await Http.HttpClient.GetAsync(downloadLink))
using (Stream stream = await DownloadFileToMemory(downloadLink))
{ {
var stream = new MemoryStream();
await resp.Content.CopyToAsync(stream);
stream.Position = 0;
targetFilePath = Path.Combine(App.VRChatInstallDirectory, mod.versions[0].IsPlugin ? "Plugins" : "Mods",
mod.versions[0].IsBroken ? "Broken" : (mod.versions[0].IsRetired ? "Retired" : ""), resp.RequestMessage.RequestUri.Segments.Last());
Directory.CreateDirectory(Path.GetDirectoryName(targetFilePath));
using var targetFile = File.OpenWrite(targetFilePath); using var targetFile = File.OpenWrite(targetFilePath);
await stream.CopyToAsync(targetFile); await stream.CopyToAsync(targetFile);
} }
mod.ListItem.IsInstalled = true; mod.ListItem.IsInstalled = true;
mod.installedFilePath = targetFilePath; mod.installedFilePath = targetFilePath;
mod.ListItem.InstalledVersion = mod.versions[0].modversion; mod.ListItem.InstalledVersion = mod.versions[0].modVersion;
mod.ListItem.InstalledModInfo = mod; mod.ListItem.InstalledModInfo = mod;
} }
} }

View file

@ -7,7 +7,7 @@ namespace VRCMelonAssistant
public class Mod public class Mod
{ {
public int _id; public int _id;
public string uploaddate; public string uploadDate;
public string category; public string category;
public string[] aliases; public string[] aliases;
public ModVersion[] versions; public ModVersion[] versions;
@ -15,25 +15,27 @@ namespace VRCMelonAssistant
public string installedFilePath; public string installedFilePath;
public string installedVersion; public string installedVersion;
public bool installedInBrokenDir; public bool installedInBrokenDir;
public bool installedInRetiredDir;
public class ModVersion public class ModVersion
{ {
public int _version; public int _version;
public string name; public string name;
public string modversion; public string modVersion;
public string modtype; public string modType;
public string author; public string author;
public string description; public string description;
public string downloadlink; public string downloadLink;
public string sourcelink; public string sourceLink;
public string hash; public string hash;
public string updatedate; public string updateDate;
public string vrchatversion; public string vrchatVersion;
public string loaderversion; public string loaderVersion;
public int approvalStatus; public int approvalStatus;
public bool IsBroken => approvalStatus == 2; public bool IsBroken => approvalStatus == 2;
public bool IsPlugin => modtype.Equals("plugin", StringComparison.InvariantCultureIgnoreCase); public bool IsRetired => approvalStatus == 3;
public bool IsPlugin => modType.Equals("plugin", StringComparison.InvariantCultureIgnoreCase);
} }
} }
} }

View file

@ -25,7 +25,7 @@ namespace VRCMelonAssistant
public class Constants public class Constants
{ {
public const string VRChatAppId = "438100"; public const string VRChatAppId = "438100";
public const string VRCMGModsJson = "https://api.vrcmg.com/v0/mods.json"; public const string VRCMGModsJson = "https://api.vrcmg.com/v1/mods";
public const string WeebCDNAPIURL = "https://pat.assistant.moe/api/v1.0/"; public const string WeebCDNAPIURL = "https://pat.assistant.moe/api/v1.0/";
public const string MD5Spacer = " "; public const string MD5Spacer = " ";
public static readonly char[] IllegalCharacters = new char[] public static readonly char[] IllegalCharacters = new char[]

View file

@ -46,6 +46,7 @@ namespace VRCMelonAssistant.Libs
new Regex(@"^(?<major>\d+)" + new Regex(@"^(?<major>\d+)" +
@"(?>\.(?<minor>\d+))?" + @"(?>\.(?<minor>\d+))?" +
@"(?>\.(?<patch>\d+))?" + @"(?>\.(?<patch>\d+))?" +
@"(?>\.(?<extra>\d+))?" +
@"(?>\-(?<pre>[0-9A-Za-z\-\.]+))?" + @"(?>\-(?<pre>[0-9A-Za-z\-\.]+))?" +
@"(?>\+(?<build>[0-9A-Za-z\-\.]+))?$", @"(?>\+(?<build>[0-9A-Za-z\-\.]+))?$",
#if NETSTANDARD #if NETSTANDARD
@ -82,11 +83,12 @@ namespace VRCMelonAssistant.Libs
/// <param name="patch">The patch version.</param> /// <param name="patch">The patch version.</param>
/// <param name="prerelease">The prerelease version (e.g. "alpha").</param> /// <param name="prerelease">The prerelease version (e.g. "alpha").</param>
/// <param name="build">The build metadata (e.g. "nightly.232").</param> /// <param name="build">The build metadata (e.g. "nightly.232").</param>
public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = "", string build = "") public SemVersion(int major, int minor = 0, int patch = 0, int extra = 0, string prerelease = "", string build = "")
{ {
Major = major; Major = major;
Minor = minor; Minor = minor;
Patch = patch; Patch = patch;
Extra = extra;
Prerelease = prerelease ?? ""; Prerelease = prerelease ?? "";
Build = build ?? ""; Build = build ?? "";
@ -151,10 +153,17 @@ namespace VRCMelonAssistant.Libs
else if (strict) else if (strict)
throw new InvalidOperationException("Invalid version (no patch version given in strict mode)"); throw new InvalidOperationException("Invalid version (no patch version given in strict mode)");
var extraMatch = match.Groups["extra"];
int extra = 0;
if (extraMatch.Success)
extra = int.Parse(extraMatch.Value, CultureInfo.InvariantCulture);
var prerelease = match.Groups["pre"].Value; var prerelease = match.Groups["pre"].Value;
var build = match.Groups["build"].Value; var build = match.Groups["build"].Value;
return new SemVersion(major, minor, patch, prerelease, build);
return new SemVersion(major, minor, patch, extra, prerelease, build);
} }
/// <summary> /// <summary>
@ -197,10 +206,18 @@ namespace VRCMelonAssistant.Libs
} }
else if (strict) return false; else if (strict) return false;
var extraMatch = match.Groups["extra"];
int extra = 0;
if (extraMatch.Success)
{
if (!int.TryParse(extraMatch.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out extra))
return false;
}
var prerelease = match.Groups["pre"].Value; var prerelease = match.Groups["pre"].Value;
var build = match.Groups["build"].Value; var build = match.Groups["build"].Value;
semver = new SemVersion(major, minor, patch, prerelease, build); semver = new SemVersion(major, minor, patch, extra, prerelease, build);
return true; return true;
} }
@ -248,13 +265,14 @@ namespace VRCMelonAssistant.Libs
/// To change only the patch version: /// To change only the patch version:
/// <code>version.Change(patch: 4)</code> /// <code>version.Change(patch: 4)</code>
/// </example> /// </example>
public SemVersion Change(int? major = null, int? minor = null, int? patch = null, public SemVersion Change(int? major = null, int? minor = null, int? patch = null, int? extra = null,
string prerelease = null, string build = null) string prerelease = null, string build = null)
{ {
return new SemVersion( return new SemVersion(
major ?? Major, major ?? Major,
minor ?? Minor, minor ?? Minor,
patch ?? Patch, patch ?? Patch,
extra ?? Extra,
prerelease ?? Prerelease, prerelease ?? Prerelease,
build ?? Build); build ?? Build);
} }
@ -283,6 +301,11 @@ namespace VRCMelonAssistant.Libs
/// </value> /// </value>
public int Patch { get; } public int Patch { get; }
/// <summary>
/// Handles the fourth number present in assembly versions
/// </summary>
public int Extra { get; }
/// <summary> /// <summary>
/// Gets the prerelease version. /// Gets the prerelease version.
/// </summary> /// </summary>
@ -316,6 +339,12 @@ namespace VRCMelonAssistant.Libs
version.Append(Minor); version.Append(Minor);
version.Append('.'); version.Append('.');
version.Append(Patch); version.Append(Patch);
if (Extra != 0)
{
version.Append('.');
version.Append(Extra);
}
if (Prerelease.Length > 0) if (Prerelease.Length > 0)
{ {
version.Append('-'); version.Append('-');
@ -409,6 +438,9 @@ namespace VRCMelonAssistant.Libs
r = Patch.CompareTo(other.Patch); r = Patch.CompareTo(other.Patch);
if (r != 0) return r; if (r != 0) return r;
r = Extra.CompareTo(other.Extra);
if (r != 0) return r;
return CompareComponent(Prerelease, other.Prerelease, true); return CompareComponent(Prerelease, other.Prerelease, true);
} }

View file

@ -103,7 +103,7 @@ namespace VRCMelonAssistant
InstallButton.IsEnabled = false; InstallButton.IsEnabled = false;
} }
private async Task ShowModsPage() public async Task ShowModsPage()
{ {
void OpenModsPage() void OpenModsPage()
{ {

View file

@ -1,4 +1,4 @@
using System.Linq; using System;
using System.Windows; using System.Windows;
using System.Windows.Documents; using System.Windows.Documents;
@ -18,29 +18,30 @@ namespace VRCMelonAssistant
ModDescription.Text = mod.versions[0].description ?? (string) FindResource("ModInfoWindow:NoDescription"); ModDescription.Text = mod.versions[0].description ?? (string) FindResource("ModInfoWindow:NoDescription");
ModName.Text = mod.versions[0].name; ModName.Text = mod.versions[0].name;
ModAuthor.Text = string.Format((string) FindResource("ModInfoWindow:Author"), mod.versions[0].author ?? FindResource("ModInfoWindow:NoAuthor")); ModAuthor.Text = string.Format((string) FindResource("ModInfoWindow:Author"), mod.versions[0].author ?? FindResource("ModInfoWindow:NoAuthor"));
ModVersion.Text = mod.versions[0].modversion; ModVersion.Text = mod.versions[0].modVersion;
var dlLink = mod.versions[0].downloadlink; var dlLink = mod.versions[0].downloadLink;
DownloadLink.Text = (string) FindResource("ModInfoWindow:DownloadLink"); DownloadLink.Text = (string) FindResource("ModInfoWindow:DownloadLink");
DownloadLink.Inlines.Add(new Run(" ")); DownloadLink.Inlines.Add(new Run(" "));
if (dlLink?.StartsWith("http") == true) if (dlLink?.StartsWith("http") == true)
DownloadLink.Inlines.Add(WrapNavigator(new Hyperlink(new Run(dlLink)))); DownloadLink.Inlines.Add(CreateHyperlink(dlLink));
else else
DownloadLink.Inlines.Add(new Run(dlLink)); DownloadLink.Inlines.Add(new Run(dlLink));
var srcLink = mod.versions[0].sourcelink; var srcLink = mod.versions[0].sourceLink;
SourceCodeLink.Text = (string) FindResource("ModInfoWindow:SourceCodeLink"); SourceCodeLink.Text = (string) FindResource("ModInfoWindow:SourceCodeLink");
SourceCodeLink.Inlines.Add(new Run(" ")); SourceCodeLink.Inlines.Add(new Run(" "));
if (srcLink?.StartsWith("http") == true) if (srcLink?.StartsWith("http") == true)
SourceCodeLink.Inlines.Add(WrapNavigator(new Hyperlink(new Run(srcLink)))); SourceCodeLink.Inlines.Add(CreateHyperlink(srcLink));
else else
SourceCodeLink.Inlines.Add(new Run(srcLink)); SourceCodeLink.Inlines.Add(new Run(srcLink));
InternalIds.Text = string.Format((string) FindResource("ModInfoWindow:InternalIds"), mod._id, mod.versions[0]._version); InternalIds.Text = string.Format((string) FindResource("ModInfoWindow:InternalIds"), mod._id, mod.versions[0]._version);
} }
private static Hyperlink WrapNavigator(Hyperlink link) private static Hyperlink CreateHyperlink(string uri)
{ {
var link = new Hyperlink(new Run(uri)) {NavigateUri = new Uri(uri)};
link.RequestNavigate += HyperlinkExtensions.Hyperlink_RequestNavigate; link.RequestNavigate += HyperlinkExtensions.Hyperlink_RequestNavigate;
return link; return link;
} }

View file

@ -1,3 +1,4 @@
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -50,12 +51,32 @@ namespace VRCMelonAssistant.Pages
private async Task HeadPat() private async Task HeadPat()
{ {
PatImage.Load(await WeebCDN("pats")); try
{
PatImage.Load(await WeebCDN("pats"));
}
catch (Exception ex)
{
Application.Current.Dispatcher.Invoke(() =>
{
Utils.ShowErrorMessageBox("Oops! Can't get headpats right now!", ex);
});
}
} }
private async Task Hug() private async Task Hug()
{ {
HugImage.Load(await WeebCDN("hugs")); try
{
HugImage.Load(await WeebCDN("hugs"));
}
catch (Exception ex)
{
Application.Current.Dispatcher.Invoke(() =>
{
Utils.ShowErrorMessageBox("Oops! Can't get hugs right now!", ex);
});
}
} }
} }
} }

View file

@ -37,10 +37,11 @@ namespace VRCMelonAssistant.Pages
MainWindow.Instance.ModsButton.IsEnabled = true; MainWindow.Instance.ModsButton.IsEnabled = true;
string text = (string) FindResource("Intro:ModsTabEnabled"); string text = (string) FindResource("Intro:ModsTabEnabled");
Utils.SendNotify(text);
MainWindow.Instance.MainText = text; MainWindow.Instance.MainText = text;
Properties.Settings.Default.Agreed = true; Properties.Settings.Default.Agreed = true;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
MainWindow.Instance.ShowModsPage().NoAwait();
} }
} }
} }

View file

@ -28,7 +28,7 @@
<TextBlock <TextBlock
Name="SearchText" Name="SearchText"
Grid.Row="0" Grid.Row="0"
Height="0" Height="20"
Padding="5,0,0,0" Padding="5,0,0,0"
Panel.ZIndex="1" Panel.ZIndex="1"
Background="{DynamicResource BottomStatusBarBackground}" Background="{DynamicResource BottomStatusBarBackground}"
@ -37,7 +37,7 @@
<TextBox <TextBox
Name="SearchBar" Name="SearchBar"
Grid.Row="0" Grid.Row="0"
Height="0" Height="20"
Margin="0,-1,0,0" Margin="0,-1,0,0"
Padding="3,1,0,0" Padding="3,1,0,0"
Panel.ZIndex="2" Panel.ZIndex="2"

View file

@ -31,10 +31,11 @@ namespace VRCMelonAssistant.Pages
public static Mods Instance = new Mods(); public static Mods Instance = new Mods();
private static readonly ModListItem.CategoryInfo BrokenCategory = new("Broken", "These mods were broken by a game update. They will be temporarily removed and restored once they are updated for the current game version"); private static readonly ModListItem.CategoryInfo BrokenCategory = new("Broken", "These mods were broken by a game update. They will be temporarily removed and restored once they are updated for the current game version");
private static readonly ModListItem.CategoryInfo RetiredCategory = new("Retired", "These mods are either no longer needed due to VRChat updates or are no longer being maintained");
private static readonly ModListItem.CategoryInfo UncategorizedCategory = new("Uncategorized", "Mods without a category assigned"); private static readonly ModListItem.CategoryInfo UncategorizedCategory = new("Uncategorized", "Mods without a category assigned");
private static readonly ModListItem.CategoryInfo UnknownCategory = new("Unknown/Unverified", "Mods not coming from VRCMG. Potentially dangerous."); private static readonly ModListItem.CategoryInfo UnknownCategory = new("Unknown/Unverified", "Mods not coming from VRCMG. Potentially dangerous.");
public List<string> DefaultMods = new List<string>() { "UI Expansion Kit", "Finitizer", "VRCModUpdater.Loader" }; public List<string> DefaultMods = new List<string>() { "UI Expansion Kit", "Finitizer", "VRCModUpdater.Loader", "VRChatUtilityKit", "Final IK Sanity", "ActionMenuApi" };
public Mod[] AllModsList; public Mod[] AllModsList;
public List<Mod> UnknownMods = new List<Mod>(); public List<Mod> UnknownMods = new List<Mod>();
public CollectionView view; public CollectionView view;
@ -138,10 +139,12 @@ namespace VRCMelonAssistant.Pages
await Task.Run(() => await Task.Run(() =>
{ {
CheckInstallDir("Plugins", false); CheckInstallDir("Plugins");
CheckInstallDir("Mods", false); CheckInstallDir("Mods");
CheckInstallDir("Plugins/Broken", true); CheckInstallDir("Plugins/Broken", isBrokenDir: true);
CheckInstallDir("Mods/Broken", true); CheckInstallDir("Mods/Broken", isBrokenDir: true);
CheckInstallDir("Plugins/Retired", isRetiredDir: true);
CheckInstallDir("Mods/Retired", isRetiredDir: true);
}); });
} }
@ -168,7 +171,7 @@ namespace VRCMelonAssistant.Pages
} }
} }
private void CheckInstallDir(string directory, bool isBrokenDir) private void CheckInstallDir(string directory, bool isBrokenDir = false, bool isRetiredDir = false)
{ {
if (!Directory.Exists(Path.Combine(App.VRChatInstallDirectory, directory))) if (!Directory.Exists(Path.Combine(App.VRChatInstallDirectory, directory)))
{ {
@ -193,6 +196,7 @@ namespace VRCMelonAssistant.Pages
mod.installedFilePath = file; mod.installedFilePath = file;
mod.installedVersion = modInfo.ModVersion; mod.installedVersion = modInfo.ModVersion;
mod.installedInBrokenDir = isBrokenDir; mod.installedInBrokenDir = isBrokenDir;
mod.installedInRetiredDir = isRetiredDir;
break; break;
} }
@ -203,12 +207,13 @@ namespace VRCMelonAssistant.Pages
installedFilePath = file, installedFilePath = file,
installedVersion = modInfo.ModVersion, installedVersion = modInfo.ModVersion,
installedInBrokenDir = isBrokenDir, installedInBrokenDir = isBrokenDir,
installedInRetiredDir = isRetiredDir,
versions = new [] versions = new []
{ {
new Mod.ModVersion() new Mod.ModVersion()
{ {
name = modInfo.ModName, name = modInfo.ModName,
modversion = modInfo.ModVersion, modVersion = modInfo.ModVersion,
author = modInfo.ModAuthor, author = modInfo.ModAuthor,
description = "" description = ""
} }
@ -255,11 +260,17 @@ namespace VRCMelonAssistant.Pages
public async Task PopulateModsList() public async Task PopulateModsList()
{ {
foreach (Mod mod in AllModsList) foreach (Mod mod in AllModsList.Where(x => !x.versions[0].IsBroken && !x.versions[0].IsRetired))
AddModToList(mod); AddModToList(mod);
foreach (var mod in UnknownMods) foreach (var mod in UnknownMods)
AddModToList(mod, UnknownCategory); AddModToList(mod, UnknownCategory);
foreach (Mod mod in AllModsList.Where(x => x.versions[0].IsBroken))
AddModToList(mod);
foreach (Mod mod in AllModsList.Where(x => x.versions[0].IsRetired))
AddModToList(mod);
} }
private void AddModToList(Mod mod, ModListItem.CategoryInfo categoryOverride = null) private void AddModToList(Mod mod, ModListItem.CategoryInfo categoryOverride = null)
@ -285,14 +296,14 @@ namespace VRCMelonAssistant.Pages
IsSelected = preSelected, IsSelected = preSelected,
IsEnabled = true, IsEnabled = true,
ModName = latestVersion.name, ModName = latestVersion.name,
ModVersion = latestVersion.modversion, ModVersion = latestVersion.modVersion,
ModAuthor = HardcodedCategories.FixupAuthor(latestVersion.author), ModAuthor = HardcodedCategories.FixupAuthor(latestVersion.author),
ModDescription = latestVersion.description.Replace("\r\n", " ").Replace("\n", " "), ModDescription = latestVersion.description.Replace("\r\n", " ").Replace("\n", " "),
ModInfo = mod, ModInfo = mod,
IsInstalled = mod.installedFilePath != null, IsInstalled = mod.installedFilePath != null,
InstalledVersion = mod.installedVersion, InstalledVersion = mod.installedVersion,
InstalledModInfo = mod, InstalledModInfo = mod,
Category = categoryOverride ?? (latestVersion.IsBroken ? BrokenCategory : GetCategory(mod)) Category = categoryOverride ?? (latestVersion.IsBroken ? BrokenCategory : (latestVersion.IsRetired ? RetiredCategory : GetCategory(mod)))
}; };
foreach (Promotion promo in Promotions.ActivePromotions) foreach (Promotion promo in Promotions.ActivePromotions)
@ -319,7 +330,7 @@ namespace VRCMelonAssistant.Pages
foreach (Mod mod in AllModsList) foreach (Mod mod in AllModsList)
{ {
// Ignore mods that are newer than installed version or up-to-date // Ignore mods that are newer than installed version or up-to-date
if (mod.ListItem.GetVersionComparison >= 0 && mod.installedInBrokenDir == mod.versions[0].IsBroken) continue; if (mod.ListItem.GetVersionComparison >= 0 && mod.installedInBrokenDir == mod.versions[0].IsBroken && mod.installedInRetiredDir == mod.versions[0].IsRetired) continue;
if (mod.ListItem.IsSelected) if (mod.ListItem.IsSelected)
{ {
@ -506,14 +517,14 @@ namespace VRCMelonAssistant.Pages
if (SearchBar.Height == 0) if (SearchBar.Height == 0)
{ {
SearchBar.Focus(); SearchBar.Focus();
Animate(SearchBar, 0, 16, new TimeSpan(0, 0, 0, 0, 300)); Animate(SearchBar, 0, 20, new TimeSpan(0, 0, 0, 0, 300));
Animate(SearchText, 0, 16, new TimeSpan(0, 0, 0, 0, 300)); Animate(SearchText, 0, 20, new TimeSpan(0, 0, 0, 0, 300));
ModsListView.Items.Filter = new Predicate<object>(SearchFilter); ModsListView.Items.Filter = new Predicate<object>(SearchFilter);
} }
else else
{ {
Animate(SearchBar, 16, 0, new TimeSpan(0, 0, 0, 0, 300)); Animate(SearchBar, 20, 0, new TimeSpan(0, 0, 0, 0, 300));
Animate(SearchText, 16, 0, new TimeSpan(0, 0, 0, 0, 300)); Animate(SearchText, 20, 0, new TimeSpan(0, 0, 0, 0, 300));
ModsListView.Items.Filter = null; ModsListView.Items.Filter = null;
} }
} }

View file

@ -88,9 +88,11 @@ namespace VRCMelonAssistant.Pages
if (resp == System.Windows.Forms.DialogResult.Yes) if (resp == System.Windows.Forms.DialogResult.Yes)
{ {
var modsDir = Path.Combine(App.VRChatInstallDirectory, "Mods"); var modsDir = Path.Combine(App.VRChatInstallDirectory, "Mods");
Directory.Delete(modsDir, true); if (Directory.Exists(modsDir))
Directory.Delete(modsDir, true);
var pluginsDir = Path.Combine(App.VRChatInstallDirectory, "Plugins"); var pluginsDir = Path.Combine(App.VRChatInstallDirectory, "Plugins");
Directory.Delete(pluginsDir, true); if (Directory.Exists(pluginsDir))
Directory.Delete(pluginsDir, true);
Directory.CreateDirectory(modsDir); Directory.CreateDirectory(modsDir);
Directory.CreateDirectory(pluginsDir); Directory.CreateDirectory(pluginsDir);

View file

@ -51,5 +51,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.20.1029")] [assembly: AssemblyVersion("1.1.26.1029")]
[assembly: AssemblyFileVersion("1.1.20.1029+vrc")] [assembly: AssemblyFileVersion("1.1.26.1029+vrc")]