mirror of
https://github.com/muskit/H3VR-TNH-Quality-of-Life-Improvements.git
synced 2026-06-02 12:14:27 -07:00
233 lines
9.0 KiB
C#
233 lines
9.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using Object = UnityEngine.Object;
|
|
#if H3VR_IMPORTED
|
|
using Valve.Newtonsoft.Json;
|
|
using Valve.Newtonsoft.Json.Linq;
|
|
#endif
|
|
|
|
|
|
namespace MeatKit
|
|
{
|
|
[CreateAssetMenu(menuName = "MeatKit/Build Profile")]
|
|
public class BuildProfile : ScriptableObject, IValidatable
|
|
{
|
|
private const string BaseOutputPath = "AssetBundles/";
|
|
|
|
[Header("Thunderstore Metadata")]
|
|
public string PackageName = "";
|
|
public string Author = "";
|
|
public string Version = "";
|
|
public Texture2D Icon;
|
|
public Object ReadMe;
|
|
public string WebsiteURL = "";
|
|
public string Description = "";
|
|
public string[] AdditionalDependencies = new string[0];
|
|
|
|
[Header("Script Options")]
|
|
public bool StripNamespaces = true;
|
|
public string[] AdditionalNamespaces = new string[0];
|
|
public bool ApplyHarmonyPatches = true;
|
|
|
|
[Header("Export Options")]
|
|
public BuildItem[] BuildItems = new BuildItem[0];
|
|
public BuildAction BuildAction = BuildAction.JustBuildFiles;
|
|
|
|
[HideInInspector]
|
|
public string OutputProfile = "";
|
|
|
|
public Dictionary<string, BuildMessage> Validate()
|
|
{
|
|
var messages = new Dictionary<string, BuildMessage>();
|
|
|
|
// Package name needs to match regex
|
|
if (!Regex.IsMatch(PackageName, @"^[a-zA-Z_0-9]+$"))
|
|
messages["PackageName"] =
|
|
BuildMessage.Error("Package name can only contain letters, numbers, and underscores.");
|
|
|
|
// Author needs to match regex
|
|
if (!Regex.IsMatch(Author, @"^[a-zA-Z_0-9]+$"))
|
|
messages["Author"] =
|
|
BuildMessage.Error("Author can only contain letters, numbers, and underscores.");
|
|
|
|
// Make sure the version number is a valid x.x.x
|
|
if (!Regex.IsMatch(Version, @"^\d+\.\d+\.\d+$"))
|
|
messages["Version"] = BuildMessage.Error("Version number must be in format 'x.x.x'.");
|
|
|
|
// Description must be no longer than 250 chars
|
|
if (Description.Length > 250)
|
|
messages["Description"] = BuildMessage.Error("Description cannot be longer than 250 characters.");
|
|
|
|
// Icon must exist and be 256 x 256
|
|
if (!Icon)
|
|
messages["Icon"] = BuildMessage.Error("Missing icon.");
|
|
else if (Icon.width != 256 || Icon.height != 256)
|
|
messages["Icon"] = BuildMessage.Info("Icon will be resized to 256x256.");
|
|
|
|
if (!ReadMe)
|
|
messages["ReadMe"] = BuildMessage.Error("Missing readme.");
|
|
else if (!AssetDatabase.GetAssetPath(ReadMe).EndsWith(".md", StringComparison.InvariantCultureIgnoreCase))
|
|
messages["ReadMe"] = BuildMessage.Warning("Are you sure this is a Markdown file? It doesn't have the .md file extension.");
|
|
|
|
switch (BuildAction)
|
|
{
|
|
case BuildAction.JustBuildFiles:
|
|
messages["BuildAction"] =
|
|
BuildMessage.Info(
|
|
"This will just create the files for a Thunderstore package in your AssetBundles folder.");
|
|
break;
|
|
case BuildAction.CopyToProfile:
|
|
messages["BuildAction"] =
|
|
BuildMessage.Info(
|
|
"This will copy the built files into the plugins folder of the selected profile.");
|
|
if (string.IsNullOrEmpty(OutputProfile))
|
|
messages["OutputProfile"] = BuildMessage.Error("Please set the output profile.");
|
|
else if (!Directory.Exists(OutputProfile))
|
|
messages["OutputProfile"] = BuildMessage.Error("Selected profile no longer exists.");
|
|
else if (!File.Exists(Path.Combine(OutputProfile, "mods.yml")))
|
|
messages["OutputProfile"] = BuildMessage.Error(
|
|
"Selected folder is not a r2mm profile. Please select the folder which contains the plugins folder.");
|
|
break;
|
|
case BuildAction.CreateThunderstorePackage:
|
|
messages["BuildAction"] =
|
|
BuildMessage.Info(
|
|
"This will zip up the built files as a final build for importing into r2mm / uploading to Thunderstore.");
|
|
break;
|
|
}
|
|
|
|
return messages;
|
|
}
|
|
|
|
public bool EnsureValidForEditor()
|
|
{
|
|
BuildLog.WriteLine("Starting build profile check...");
|
|
|
|
// Check ourselves
|
|
bool hasErrors = false, hasWarnings = false;
|
|
foreach (var message in Validate().Values)
|
|
{
|
|
// Log them
|
|
switch (message.Type)
|
|
{
|
|
case MessageType.Error:
|
|
Debug.LogError(AssetDatabase.GetAssetPath(this) + ": " + message.Message);
|
|
hasErrors = true;
|
|
break;
|
|
case MessageType.Warning:
|
|
Debug.LogWarning(AssetDatabase.GetAssetPath(this) + ": " + message.Message);
|
|
hasWarnings = true;
|
|
break;
|
|
}
|
|
|
|
BuildLog.WriteLine(" " + message.Type + ": " + this + ": " + message.Message);
|
|
}
|
|
|
|
// Go over each build item and check for any validation messages
|
|
foreach (var item in BuildItems.Where(x => x != null))
|
|
foreach (var message in item.Validate().Values)
|
|
{
|
|
// Log them
|
|
switch (message.Type)
|
|
{
|
|
case MessageType.Error:
|
|
Debug.LogError(AssetDatabase.GetAssetPath(item) + ": " + message.Message);
|
|
hasErrors = true;
|
|
break;
|
|
case MessageType.Warning:
|
|
Debug.LogWarning(AssetDatabase.GetAssetPath(item) + ": " + message.Message);
|
|
hasWarnings = true;
|
|
break;
|
|
}
|
|
|
|
BuildLog.WriteLine(" " + message.Type + ": " + item + ": " + message.Message);
|
|
}
|
|
|
|
|
|
// If there's errors don't let anything continue
|
|
if (hasErrors)
|
|
{
|
|
EditorUtility.DisplayDialog("Build errors",
|
|
"There were errors validating your build items. Please check the console for more info.", "Ok.");
|
|
BuildLog.SetCompletionStatus(true, "Build profile failed one or more checks", null);
|
|
return false;
|
|
}
|
|
|
|
// If there's only warnings, let the user decide if they want to continue
|
|
if (hasWarnings)
|
|
{
|
|
var continueAnyway = EditorUtility.DisplayDialog("Build warnings",
|
|
"Some build items validated with warnings. Continue with build anyway?", "Yes", "No");
|
|
|
|
BuildLog.WriteLine("Build profile has one or more warnings.");
|
|
BuildLog.WriteLine(" Continue anyway? " + continueAnyway);
|
|
BuildLog.SetCompletionStatus(true, "User canceled build", null);
|
|
|
|
return continueAnyway;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise continue
|
|
BuildLog.WriteLine(" Build profile passed all checks!");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public string[] GetRequiredDependencies()
|
|
{
|
|
return BuildItems
|
|
.Where(x => x != null)
|
|
.SelectMany(x => x.RequiredDependencies)
|
|
.Distinct().ToArray();
|
|
}
|
|
|
|
public string MainNamespace
|
|
{
|
|
get { return Author + "." + PackageName; }
|
|
}
|
|
|
|
public string[] GetRequiredNamespaces()
|
|
{
|
|
return new[] {MainNamespace};
|
|
}
|
|
|
|
public string[] GetAllAllowedNamespaces()
|
|
{
|
|
return GetRequiredNamespaces().Concat(AdditionalNamespaces).ToArray();
|
|
}
|
|
|
|
public string ExportPath
|
|
{
|
|
get { return Path.Combine(BaseOutputPath, Path.Combine(PackageName, Version)) + Path.DirectorySeparatorChar; }
|
|
}
|
|
|
|
public void WriteThunderstoreManifest(string location)
|
|
{
|
|
#if H3VR_IMPORTED
|
|
var obj = new JObject();
|
|
obj["name"] = PackageName;
|
|
obj["author"] = Author;
|
|
obj["version_number"] = Version;
|
|
obj["description"] = Description;
|
|
obj["website_url"] = string.IsNullOrEmpty(WebsiteURL) ? "" : WebsiteURL;
|
|
|
|
// ReSharper disable once CoVariantArrayConversion
|
|
obj["dependencies"] = new JArray(GetRequiredDependencies().Concat(AdditionalDependencies).ToArray());
|
|
|
|
File.WriteAllText(location, JsonConvert.SerializeObject(obj,Formatting.Indented));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public enum BuildAction
|
|
{
|
|
JustBuildFiles,
|
|
CopyToProfile,
|
|
CreateThunderstorePackage
|
|
}
|
|
}
|