diff --git a/SaberFactory.Unity/SaberFactory.Unity.csproj b/SaberFactory.Unity/SaberFactory.Unity.csproj
index e571aea..81fce93 100644
--- a/SaberFactory.Unity/SaberFactory.Unity.csproj
+++ b/SaberFactory.Unity/SaberFactory.Unity.csproj
@@ -18,14 +18,14 @@
false
bin\Debug\
- DEBUG;TRACE;UNITY
+ DEBUG;TRACE;UNITY;UNITY_EDITOR
true
bin\Release\
prompt
4
- TRACE;UNITY
+ TRACE;UNITY;UNITY_EDITOR
True
@@ -47,6 +47,9 @@
$(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.dll
False
+
+ $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.AudioModule.dll
+
$(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.CoreModule.dll
False
@@ -56,7 +59,7 @@
False
- ..\..\..\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll
+ $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll
@@ -77,12 +80,22 @@
SaberModifierCollection.cs
+
TransformModifier.cs
VisibilityModifier.cs
+
+ SFBurnMarks.cs
+
+
+ SFClashEffect.cs
+
+
+ HelpAttribute.cs
+
\ No newline at end of file
diff --git a/SaberFactory/Configuration/PluginConfig.cs b/SaberFactory/Configuration/PluginConfig.cs
index 3fb9e61..db6ac7f 100644
--- a/SaberFactory/Configuration/PluginConfig.cs
+++ b/SaberFactory/Configuration/PluginConfig.cs
@@ -1,14 +1,16 @@
using System.Collections.Generic;
+using System.ComponentModel;
using System.Runtime.CompilerServices;
using IPA.Config.Stores;
using IPA.Config.Stores.Attributes;
using IPA.Config.Stores.Converters;
+using JetBrains.Annotations;
[assembly: InternalsVisibleTo(GeneratedStore.AssemblyVisibilityTarget)]
namespace SaberFactory.Configuration
{
- internal class PluginConfig
+ internal class PluginConfig : INotifyPropertyChanged
{
public bool Enabled { get; set; } = true;
@@ -49,6 +51,10 @@ internal class PluginConfig
public bool ReloadOnSaberUpdate { get; set; } = false;
+ public float SwingSoundVolume { get; set; } = 1;
+
+ public bool EnableCustomBurnmarks { get; set; } = true;
+
// How many threads to spawn when loading all sabers
// ! Not used as of right now !
[Ignore] public int LoadingThreads { get; set; } = 2;
@@ -94,5 +100,13 @@ public bool IsFavorite(string path)
{
return Favorites.Contains(path);
}
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [NotifyPropertyChangedInvocator]
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
}
}
\ No newline at end of file
diff --git a/SaberFactory/DataStore/MainAssetStore.cs b/SaberFactory/DataStore/MainAssetStore.cs
index c168ad1..9583fd6 100644
--- a/SaberFactory/DataStore/MainAssetStore.cs
+++ b/SaberFactory/DataStore/MainAssetStore.cs
@@ -16,7 +16,7 @@ namespace SaberFactory.DataStore
///
/// Class for managing store assets ie. parts and custom sabers
///
- internal class MainAssetStore : IDisposable, ILoadingTask
+ public class MainAssetStore : IDisposable, ILoadingTask
{
public List AdditionalCustomSaberFolders { get; } = new List();
@@ -81,7 +81,7 @@ public async Task GetCompositionByMeta(PreloadMetaData meta)
return await this[PathTools.ToRelativePath(meta.AssetMetaPath.Path)];
}
- public async Task LoadAllMetaAsync(EAssetTypeConfiguration assetType)
+ internal async Task LoadAllMetaAsync(EAssetTypeConfiguration assetType)
{
await LoadAllCustomSaberMetaDataAsync();
}
@@ -210,7 +210,7 @@ private async Task LoadAllMetaDataForLoader(AssetBundleLoader loader, bool creat
sw.Print(_logger);
}
- public async Task CreateMetaData(AssetMetaPath assetMetaPath)
+ internal async Task CreateMetaData(AssetMetaPath assetMetaPath)
{
var relativePath = assetMetaPath.RelativePath+".meta";
if (_metaData.TryGetValue(relativePath, out _))
diff --git a/SaberFactory/DataStore/StoreAsset.cs b/SaberFactory/DataStore/StoreAsset.cs
index 2df8324..3b1e1b3 100644
--- a/SaberFactory/DataStore/StoreAsset.cs
+++ b/SaberFactory/DataStore/StoreAsset.cs
@@ -7,7 +7,7 @@ namespace SaberFactory.DataStore
///
/// Keeps information about the origin of the asset
///
- internal class StoreAsset
+ public class StoreAsset
{
public readonly AssetBundle AssetBundle;
public readonly string Extension;
diff --git a/SaberFactory/Directory.Build.targets b/SaberFactory/Directory.Build.targets
index 2418059..c1b2f9b 100644
--- a/SaberFactory/Directory.Build.targets
+++ b/SaberFactory/Directory.Build.targets
@@ -70,7 +70,8 @@
-
+
+
diff --git a/SaberFactory/Editor/Editor.cs b/SaberFactory/Editor/Editor.cs
index dbe1fc8..94de9a2 100644
--- a/SaberFactory/Editor/Editor.cs
+++ b/SaberFactory/Editor/Editor.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using IPA.Loader;
using SaberFactory.Configuration;
using SaberFactory.HarmonyPatches;
using SaberFactory.Helpers;
@@ -10,6 +11,7 @@
using SaberFactory.UI.Lib;
using SiraUtil.Logging;
using SiraUtil.Tools;
+using Tweening;
using UnityEngine;
using Zenject;
@@ -49,6 +51,8 @@ public bool IsSaberInHand
private bool _isFirstActivation = true;
private bool _isSaberInHand;
private SaberInstance _spawnedSaber;
+ private readonly PluginMetadata _metaData;
+ private readonly TimeTweeningManager _tweeningManager;
private Editor(
SiraLog logger,
@@ -60,9 +64,13 @@ private Editor(
PlayerDataModel playerDataModel,
SaberGrabController saberGrabController,
MenuSaberProvider menuSaberProvider,
- PluginDirectories pluginDirs)
+ PluginDirectories pluginDirs,
+ [Inject(Id = nameof(SaberFactory))]PluginMetadata metadata,
+ TimeTweeningManager tweeningManager)
{
_logger = logger;
+ _metaData = metadata;
+ _tweeningManager = tweeningManager;
_pluginConfig = pluginConfig;
_baseUiComposition = baseUiComposition;
_editorInstanceManager = editorInstanceManager;
@@ -71,7 +79,7 @@ private Editor(
_saberGrabController = saberGrabController;
_menuSaberProvider = menuSaberProvider;
- _pedestal = new Pedestal(embeddedAssetLoader, pluginDirs.SaberFactoryDir.GetFile("pedestal"));
+ _pedestal = new Pedestal(pluginDirs.SaberFactoryDir.GetFile("pedestal"));
_sfLogoAnim = new SFLogoAnim(embeddedAssetLoader);
Instance = this;
@@ -93,6 +101,10 @@ public async void Initialize()
// Create Pedestal
var pos = new Vector3(0.3f, 0, 0.9f);
await _pedestal.Instantiate(pos, Quaternion.Euler(0, 25, 0));
+ SetPedestalText(1, "SF v"+_metaData.HVersion+"");
+#if PAT
+ SetPedestalText(2, "Patreon ♥");
+#endif
SetupGlobalShaderVars();
}
@@ -155,6 +167,20 @@ public void Close(bool instant)
_menuSaberProvider.RequestSaberVisiblity(true);
}
+ public void SetPedestalText(int line, string text)
+ {
+ _pedestal.SetText(line, text);
+ }
+
+ public void FlashPedestal(Color color)
+ {
+ _tweeningManager.KillAllTweens(_pedestal.SaberContainerTransform);
+ _tweeningManager.AddTween(new FloatTween(1, 0, f =>
+ {
+ _pedestal.SetLedColor(color.ColorWithAlpha(f));
+ }, 1, EaseType.InCubic), _pedestal.SaberContainerTransform);
+ }
+
private async void OnModelCompositionSet(ModelComposition composition)
{
_spawnedSaber?.Destroy();
diff --git a/SaberFactory/Editor/Pedestal.cs b/SaberFactory/Editor/Pedestal.cs
index 27ea8a7..42c846f 100644
--- a/SaberFactory/Editor/Pedestal.cs
+++ b/SaberFactory/Editor/Pedestal.cs
@@ -1,7 +1,10 @@
using System;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using SaberFactory.Helpers;
+using SaberFactory.Loaders;
+using TMPro;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -9,6 +12,8 @@ namespace SaberFactory.Editor
{
internal class Pedestal
{
+ private static readonly string PedestalPath = String.Join(".", nameof(SaberFactory), "Resources", "pedestal");
+
public bool IsVisible
{
set
@@ -29,13 +34,15 @@ public Vector3 Position
public Transform SaberContainerTransform { get; private set; }
private readonly FileInfo _customPedestalFile;
- private readonly EmbeddedAssetLoader _embeddedAssetLoader;
-
private Transform _rootTransform;
+ private TextMeshPro _textMeshPro;
+ private Material _ledMat;
+
+ private readonly string[] _lines = new string[3];
+ private static readonly int LedColor = Shader.PropertyToID("_LedColor");
- public Pedestal(EmbeddedAssetLoader embeddedAssetLoader, FileInfo customPedestalFile)
+ public Pedestal(FileInfo customPedestalFile)
{
- _embeddedAssetLoader = embeddedAssetLoader;
_customPedestalFile = customPedestalFile;
}
@@ -54,7 +61,20 @@ public async Task Instantiate(Vector3 pos, Quaternion rot)
return;
}
- Object.Instantiate(prefab, _rootTransform, false);
+ var instantiated = Object.Instantiate(prefab, _rootTransform, false);
+ _textMeshPro = instantiated.GetComponentsInChildren()
+ .FirstOrDefault(x => x.name == "Pedestal_Display");
+ var leds = instantiated.GetComponentsInChildren().FirstOrDefault(x => x.name == "Leds");
+
+ if (_textMeshPro)
+ {
+ _textMeshPro.alignment = TextAlignmentOptions.Center;
+ }
+
+ if (leds)
+ {
+ _ledMat = leds.sharedMaterial;
+ }
SaberContainerTransform = _rootTransform.CreateGameObject("SaberContainer").transform;
SaberContainerTransform.localPosition += new Vector3(0, 1, 0);
@@ -66,6 +86,17 @@ public async Task Instantiate(Vector3 pos, Quaternion rot)
IsVisible = false;
}
+ public void SetText(int line, string text)
+ {
+ if (!_textMeshPro)
+ {
+ return;
+ }
+
+ _lines[line] = text;
+ _textMeshPro.text = string.Join("\n", _lines);
+ }
+
private async Task GetPedestalAsset()
{
if (_customPedestalFile.Exists)
@@ -82,7 +113,10 @@ private async Task GetPedestalAsset()
}
}
- return await _embeddedAssetLoader.LoadAsset("Pedestal");
+ var data = await Readers.ReadResourceAsync(PedestalPath);
+ var bundle = await Readers.LoadAssetFromAssetBundleAsync(data, "Pedestal");
+ bundle.Item2.Unload(false);
+ return bundle.Item1;
}
public void Destroy()
@@ -92,5 +126,15 @@ public void Destroy()
_rootTransform.gameObject.TryDestroy();
}
}
+
+ public void SetLedColor(Color color)
+ {
+ if (!_ledMat)
+ {
+ return;
+ }
+
+ _ledMat.SetColor(LedColor, color);
+ }
}
}
\ No newline at end of file
diff --git a/SaberFactory/Game/SFSaberModelController.cs b/SaberFactory/Game/SFSaberModelController.cs
index f9e883b..60de154 100644
--- a/SaberFactory/Game/SFSaberModelController.cs
+++ b/SaberFactory/Game/SFSaberModelController.cs
@@ -1,6 +1,10 @@
-using System.Threading.Tasks;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using HarmonyLib;
using SaberFactory.Helpers;
using SaberFactory.Instances;
+using SaberFactory.Misc;
using SaberFactory.Models;
using SiraUtil.Interfaces;
using SiraUtil.Logging;
@@ -12,12 +16,12 @@ namespace SaberFactory.Game
{
internal class SfSaberModelController : SaberModelController, IColorable
{
- [InjectOptional] private readonly AFHandler _afHandler = null;
[InjectOptional] private readonly EventPlayer _eventPlayer = null;
[Inject] private readonly GameSaberSetup _gameSaberSetup = null;
[Inject] private readonly SiraLog _logger = null;
[Inject] private readonly SaberInstance.Factory _saberInstanceFactory = null;
[Inject] private readonly SaberSet _saberSet = null;
+ [Inject] private readonly List _customizers = null;
private Color? _saberColor;
private SaberInstance _saberInstance;
@@ -43,19 +47,17 @@ public override async void Init(Transform parent, Saber saber)
var saberModel = saber.saberType == SaberType.SaberA ? _saberSet.LeftSaber : _saberSet.RightSaber;
_saberInstance = _saberInstanceFactory.Create(saberModel);
+
+ if (saber.saberType == SaberType.SaberA)
+ {
+ _customizers.Do(x=>x.SetSaber(_saberInstance));
+ }
+
_saberInstance.SetParent(transform);
_saberInstance.CreateTrail(false, _saberTrail);
SetColor(_saberColor ?? _colorManager.ColorForSaberType(_saberInstance.Model.SaberSlot.ToSaberType()));
- if (_afHandler != null && AFHandler.IsValid && AFHandler.ShouldFire)
- {
- await Task.Delay(4000);
- await _afHandler.Shoot(this, saber.saberType);
- }
- else
- {
- _eventPlayer?.SetPartEventList(_saberInstance.Events, saber.saberType);
- }
+ _eventPlayer?.SetPartEventList(_saberInstance.Events, saber.saberType);
_logger.Info("Instantiated Saber");
}
diff --git a/SaberFactory/Game/SaberMovementTester.cs b/SaberFactory/Game/SaberMovementTester.cs
index 527bafe..77bb705 100644
--- a/SaberFactory/Game/SaberMovementTester.cs
+++ b/SaberFactory/Game/SaberMovementTester.cs
@@ -1,8 +1,11 @@
-using System.Collections;
+using System;
+using System.Collections;
+using System.Linq;
using System.Threading.Tasks;
using SiraUtil.Sabers;
using UnityEngine;
using Zenject;
+using Object = UnityEngine.Object;
namespace SaberFactory.Game
{
@@ -11,8 +14,6 @@ internal class SaberMovementTester : IInitializable
private readonly AudioTimeSyncController _audioController;
private readonly InitData _initData;
private readonly SiraSaberFactory _saberFactory;
-
- private Transform _movementContainer;
private SiraSaber _saber;
private SaberMovementTester(InitData initData, SiraSaberFactory saberFactory, AudioTimeSyncController audioController)
@@ -33,30 +34,75 @@ public async void Initialize()
return;
}
- _movementContainer = new GameObject("SaberTester").transform;
- _movementContainer.localPosition = new Vector3(0, 1.5f, 0);
- _saber = _saberFactory.Spawn(SaberType.SaberA);
- _saber.transform.SetParent(_movementContainer, false);
+ var saberA = CreateSaber(SaberType.SaberA, new Vector3(0, 0.6f, 0), Quaternion.Euler(90, 0, 0));
+ var saberB = CreateSaber(SaberType.SaberB, new Vector3(0, 0.6f, 0), Quaternion.Euler(90, 0, 0));
+
+ SharedCoroutineStarter.instance.StartCoroutine(GroundRoundAnimationCoroutine(-0.2f, saberA));
+ SharedCoroutineStarter.instance.StartCoroutine(GroundRoundAnimationCoroutine(0.2f, saberB));
+
+ // Don't try this at home
+ var allLRs = Object.FindObjectsOfType()
+ .Where(x => x.name.Contains("SaberBurnMark"));
+
+ var normalLR = allLRs.First(x => !x.name.Contains("Sira"));
+ var siraLRs = allLRs.Where(x => x.name.Contains("Sira"));
+
+ foreach (var lineRenderer in siraLRs)
+ {
+ lineRenderer.sharedMaterial = new Material(normalLR.sharedMaterial);
+ lineRenderer.textureMode = LineTextureMode.Stretch;
+ //lineRenderer.widthMultiplier = 2;
+ }
+ }
+
+ public Transform CreateSaber(SaberType saberType, Vector3 pos, Quaternion rot)
+ {
+ var parent = new GameObject("SaberTester_" + saberType).transform;
+ parent.localPosition = new Vector3(0, 0.6f, 0);
+ parent.localRotation = Quaternion.Euler(90, 0, 0);
+ _saber = _saberFactory.Spawn(saberType);
+ _saber.transform.SetParent(parent, false);
- SharedCoroutineStarter.instance.StartCoroutine(AnimationCoroutine());
+ return parent;
}
- private IEnumerator AnimationCoroutine()
+ //private IEnumerator AnimationCoroutine()
+ //{
+ // var currentRot = _movementContainer.localEulerAngles.x;
+ // while (true)
+ // {
+ // while (currentRot < 90)
+ // {
+ // currentRot += 1;
+ // _movementContainer.localEulerAngles = new Vector3(currentRot, 0, 0);
+ // yield return new WaitForEndOfFrame();
+ // }
+
+ // while (currentRot > -90)
+ // {
+ // currentRot -= 1;
+ // _movementContainer.localEulerAngles = new Vector3(currentRot, 0, 0);
+ // yield return new WaitForEndOfFrame();
+ // }
+ // }
+ //}
+
+ private IEnumerator GroundRoundAnimationCoroutine(float xPos, Transform t)
{
- var currentRot = _movementContainer.localEulerAngles.x;
+ var currentPos = t.localPosition.z;
while (true)
{
- while (currentRot < 90)
+ while (currentPos < 1)
{
- currentRot += 1;
- _movementContainer.localEulerAngles = new Vector3(currentRot, 0, 0);
+ currentPos += 0.02f;
+ t.localPosition = new Vector3(xPos, 0.6f, currentPos);
yield return new WaitForEndOfFrame();
}
- while (currentRot > -90)
+ while (currentPos > 0)
{
- currentRot -= 1;
- _movementContainer.localEulerAngles = new Vector3(currentRot, 0, 0);
+ currentPos -= 0.02f;
+ t.localPosition = new Vector3(xPos, 0.6f, currentPos);
yield return new WaitForEndOfFrame();
}
}
diff --git a/SaberFactory/Helpers/CommonHelpers.cs b/SaberFactory/Helpers/CommonHelpers.cs
index 46464f6..d8629f7 100644
--- a/SaberFactory/Helpers/CommonHelpers.cs
+++ b/SaberFactory/Helpers/CommonHelpers.cs
@@ -1,4 +1,5 @@
using System;
+using System.Reflection;
using System.Threading.Tasks;
using IPA.Utilities;
using SaberFactory.DataStore;
@@ -83,5 +84,27 @@ public static async Task WaitForFinish(this ILoadingTask loadingTask)
await loadingTask.CurrentTask;
}
+
+ public static Component Upgrade(Component monoBehaviour, Type upgradingType)
+ {
+ var originalType = monoBehaviour.GetType();
+
+ var gameObject = monoBehaviour.gameObject;
+ var upgradedDummyComponent = Activator.CreateInstance(upgradingType);
+ foreach (FieldInfo info in originalType.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
+ {
+ info.SetValue(upgradedDummyComponent, info.GetValue(monoBehaviour));
+ }
+ UnityEngine.Object.DestroyImmediate(monoBehaviour);
+ bool goState = gameObject.activeSelf;
+ gameObject.SetActive(false);
+ var upgradedMonoBehaviour = gameObject.AddComponent(upgradingType);
+ foreach (FieldInfo info in upgradingType.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
+ {
+ info.SetValue(upgradedMonoBehaviour, info.GetValue(upgradedDummyComponent));
+ }
+ gameObject.SetActive(goState);
+ return upgradedMonoBehaviour;
+ }
}
}
\ No newline at end of file
diff --git a/SaberFactory/Helpers/DebugTools.cs b/SaberFactory/Helpers/DebugTools.cs
index f2f640e..343d99c 100644
--- a/SaberFactory/Helpers/DebugTools.cs
+++ b/SaberFactory/Helpers/DebugTools.cs
@@ -1,4 +1,9 @@
-using UnityEngine;
+using System.Reflection;
+using System.Text;
+using BeatSaberMarkupLanguage.FloatingScreen;
+using BeatSaberMarkupLanguage.Tags;
+using UnityEngine;
+using UnityEngine.UI;
namespace SaberFactory.Helpers
{
@@ -23,6 +28,37 @@ public static GameObject CreateBall(BallOptions options)
return go;
}
+ public static string DumpObject(Object obj)
+ {
+ var str = new StringBuilder();
+ foreach (var fieldInfo in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
+ {
+ str.AppendLine($"{fieldInfo.Name}: {fieldInfo.GetValue(obj)}");
+ }
+
+ foreach (var propertyInfo in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
+ {
+ if(!propertyInfo.CanRead) continue;
+ str.AppendLine($"{propertyInfo.Name}: {propertyInfo.GetValue(obj)}");
+ }
+
+ return str.ToString();
+ }
+
+ public static FloatingScreen CreateScreen(Vector2? size = null, Vector3? pos = null)
+ {
+ return FloatingScreen.CreateFloatingScreen(size??new Vector2(500, 500), false, pos??new Vector3(0, 1, 1), Quaternion.identity);
+ }
+
+ public static void TextureScreen(Texture tex, Vector2? size = null, Vector3? pos = null)
+ {
+ var screen = CreateScreen(size, pos);
+ screen.gameObject.name = "TextureScreen_" + tex.name;
+ var rawImage = new RawImageTag().CreateObject(screen.transform).GetComponentInChildren();
+ rawImage.texture = tex;
+ rawImage.transform.AsRectTransform().sizeDelta = screen.transform.AsRectTransform().sizeDelta;
+ }
+
public struct BallOptions
{
public Vector3 Pos;
diff --git a/SaberFactory/Helpers/SaberHelpers.cs b/SaberFactory/Helpers/SaberHelpers.cs
index 96c3f9e..87d1ed2 100644
--- a/SaberFactory/Helpers/SaberHelpers.cs
+++ b/SaberFactory/Helpers/SaberHelpers.cs
@@ -1,11 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using CustomSaber;
+using SaberFactory.Instances;
using UnityEngine;
namespace SaberFactory.Helpers
{
- public static class SaberHelpers
+ internal static class SaberHelpers
{
public static List GetTrails(GameObject saberObject)
{
@@ -20,5 +21,10 @@ public static List GetTrails(GameObject saberObject)
.OrderByDescending(x => x.PointEnd.position.z)
.ToList();
}
+
+ public static SaberInstance.SaberMonoBehaviour GetSaberMonoBehaviour(GameObject go)
+ {
+ return go.GetComponentInParent();
+ }
}
}
\ No newline at end of file
diff --git a/SaberFactory/Installers/PluginAppInstaller.cs b/SaberFactory/Installers/PluginAppInstaller.cs
index 608f3c3..896dce1 100644
--- a/SaberFactory/Installers/PluginAppInstaller.cs
+++ b/SaberFactory/Installers/PluginAppInstaller.cs
@@ -8,6 +8,7 @@
using SaberFactory.Instances;
using SaberFactory.Instances.PostProcessors;
using SaberFactory.Instances.Trail;
+using SaberFactory.Misc;
using SaberFactory.Models;
using SaberFactory.Models.CustomSaber;
using SaberFactory.Serialization;
@@ -78,6 +79,8 @@ public override void InstallBindings()
Container.Bind().AsSingle();
Container.Bind().AsSingle();
+ Container.BindInterfacesAndSelfTo().AsSingle();
+
InstallFactories();
InstallMiddlewares();
}
diff --git a/SaberFactory/Installers/PluginGameInstaller.cs b/SaberFactory/Installers/PluginGameInstaller.cs
index 49783f8..3bf0dcc 100644
--- a/SaberFactory/Installers/PluginGameInstaller.cs
+++ b/SaberFactory/Installers/PluginGameInstaller.cs
@@ -4,6 +4,7 @@
using SaberFactory.Configuration;
using SaberFactory.Game;
using SaberFactory.Helpers;
+using SaberFactory.Misc;
using SaberFactory.Models;
using SiraUtil.Interfaces;
using SiraUtil.Sabers;
@@ -33,9 +34,7 @@ public override void InstallBindings()
//Container.BindInterfacesAndSelfTo().AsSingle();
Container.BindInterfacesAndSelfTo().AsSingle();
- //Container.Bind().To().AsSingle();
- Container.BindInstance(SaberModelRegistration.Create());
-
+ Container.BindInstance(SaberModelRegistration.Create(300)).AsSingle();
#if DEBUG && TEST_TRAIL
if (Container.TryResolve()?.FPFC ?? false)
diff --git a/SaberFactory/Instances/CustomSaber/CustomSaberInstance.cs b/SaberFactory/Instances/CustomSaber/CustomSaberInstance.cs
index 1721ac8..b2e6239 100644
--- a/SaberFactory/Instances/CustomSaber/CustomSaberInstance.cs
+++ b/SaberFactory/Instances/CustomSaber/CustomSaberInstance.cs
@@ -8,7 +8,6 @@
using SaberFactory.Models;
using SaberFactory.Models.CustomSaber;
using SiraUtil.Logging;
-using SiraUtil.Tools;
using UnityEngine;
namespace SaberFactory.Instances.CustomSaber
diff --git a/SaberFactory/Instances/MaterialDescriptor.cs b/SaberFactory/Instances/MaterialDescriptor.cs
index 51a9fad..7eec1e6 100644
--- a/SaberFactory/Instances/MaterialDescriptor.cs
+++ b/SaberFactory/Instances/MaterialDescriptor.cs
@@ -7,7 +7,7 @@ namespace SaberFactory.Instances
/// Extension class for with more information
/// and possibly to revert a changed
///
- internal class MaterialDescriptor
+ public class MaterialDescriptor
{
public bool IsValid => Material != null;
public Material Material;
diff --git a/SaberFactory/Instances/PostProcessors/MainSaberPostProcessor.cs b/SaberFactory/Instances/PostProcessors/MainSaberPostProcessor.cs
index 094cbb9..7b8e0f0 100644
--- a/SaberFactory/Instances/PostProcessors/MainSaberPostProcessor.cs
+++ b/SaberFactory/Instances/PostProcessors/MainSaberPostProcessor.cs
@@ -1,6 +1,7 @@
using HarmonyLib;
using SaberFactory.Configuration;
using SaberFactory.Helpers;
+using SaberFactory.ProjectComponents;
using UnityEngine;
namespace SaberFactory.Instances.PostProcessors
@@ -18,8 +19,13 @@ public void ProcessSaber(GameObject saberObject)
{
saberObject.SetLayer(12);
saberObject.GetComponentsInChildren().Do(x => x.enabled = false);
- saberObject.GetComponentsInChildren(true).Do(x => x.volume = x.volume * _config.SaberAudioVolumeMultiplier);
+ saberObject.GetComponentsInChildren(true).Do(x => x.volume *= _config.SaberAudioVolumeMultiplier);
saberObject.GetComponentsInChildren(true).Do(x => { x.sortingOrder = 3; });
+
+ if (saberObject.GetComponentInChildren() is { } saberSound)
+ {
+ saberSound.ConfigVolume = _config.SwingSoundVolume;
+ }
}
}
}
\ No newline at end of file
diff --git a/SaberFactory/Instances/SaberInstance.cs b/SaberFactory/Instances/SaberInstance.cs
index 4e29152..32be529 100644
--- a/SaberFactory/Instances/SaberInstance.cs
+++ b/SaberFactory/Instances/SaberInstance.cs
@@ -38,6 +38,8 @@ public class SaberInstance
private InstanceTrailData _instanceTrailData;
private List _secondaryTrails;
+ private readonly Dictionary _saberComponents = new Dictionary();
+
private SaberInstance(
SaberModel model,
BasePieceInstance.Factory pieceFactory,
@@ -51,7 +53,7 @@ private SaberInstance(
Model = model;
GameObject = new GameObject(SaberName);
- GameObject.AddComponent().Init(this, OnSaberGameObjectDestroyed);
+ GameObject.AddComponent().Init(this, _saberComponents, OnSaberGameObjectDestroyed);
CachedTransform = GameObject.transform;
@@ -160,6 +162,14 @@ public void DestroyTrail(bool immediate = false)
}
}
+ public bool GetSaberComponent(out T saberComp) where T : Component
+ {
+ saberComp = null;
+ if (!_saberComponents.TryGetValue(typeof(T), out var comp)) return false;
+ saberComp = (T)comp;
+ return saberComp;
+ }
+
public void Destroy()
{
GameObject.TryDestroy();
@@ -221,17 +231,25 @@ internal class SaberMonoBehaviour : MonoBehaviour
{
public SaberInstance SaberInstance { get; private set; }
private Action _onDestroyed;
+ public Dictionary SaberComponentDict;
private void OnDestroy()
{
_onDestroyed?.Invoke();
}
- public void Init(SaberInstance saberInstance, Action onDestroyedCallback)
+ public void Init(SaberInstance saberInstance, Dictionary saberComponentDict, Action onDestroyedCallback)
{
SaberInstance = saberInstance;
+ SaberComponentDict = saberComponentDict;
_onDestroyed = onDestroyedCallback;
}
+
+ public void RegisterComponent(Component comp)
+ {
+ SaberComponentDict[comp.GetType()] = comp;
+ }
+
}
}
}
\ No newline at end of file
diff --git a/SaberFactory/Misc/CustomSaberBurnMarkArea.cs b/SaberFactory/Misc/CustomSaberBurnMarkArea.cs
new file mode 100644
index 0000000..dbd0b07
--- /dev/null
+++ b/SaberFactory/Misc/CustomSaberBurnMarkArea.cs
@@ -0,0 +1,122 @@
+using System;
+using SaberFactory.Configuration;
+using SaberFactory.Models;
+using SaberFactory.ProjectComponents;
+using UnityEngine;
+using Zenject;
+using Object = UnityEngine.Object;
+
+namespace SaberFactory.Misc
+{
+ internal class CustomSaberBurnMarkArea : SaberBurnMarkArea
+ {
+ public Material FadeoutMaterial
+ {
+ get => _fadeOutMaterial;
+ set
+ {
+ if (_fadeOutMaterial)
+ {
+ DestroyImmediate(_fadeOutMaterial);
+ _fadeOutMaterial = value;
+ }
+ }
+ }
+
+ public float RandomOffset
+ {
+ get => _blackMarkLineRandomOffset;
+ set => _blackMarkLineRandomOffset = value;
+ }
+
+ public float FadeoutStrength
+ {
+ get => _burnMarksFadeOutStrength;
+ set => _burnMarksFadeOutStrength = value;
+ }
+
+ public float BurnmarkSize
+ {
+ get => _burnmarkSize;
+ set
+ {
+ _burnmarkSize = value;
+ foreach (var lineRenderer in _lineRenderers)
+ {
+ lineRenderer.widthMultiplier = _burnmarkSize;
+ }
+ }
+ }
+
+ public Material BurnmarkMaterial
+ {
+ get => _lineRenderers[0].sharedMaterial;
+ set
+ {
+ foreach (var lineRenderer in _lineRenderers)
+ {
+ var oldMat = lineRenderer.sharedMaterial;
+ lineRenderer.material = new Material(value) {color = oldMat.color};
+ }
+ }
+ }
+
+ private float _burnmarkSize = 0.1f;
+
+ [Inject] private readonly SaberSet _saberSet = null;
+ [Inject] private readonly PluginConfig _pluginConfig = null;
+
+ private SFBurnmarks _info;
+
+ public override void Start()
+ {
+ base.Start();
+ Init();
+ }
+
+ public void Init()
+ {
+ if (!_pluginConfig.EnableCustomBurnmarks)
+ {
+ return;
+ }
+
+ if (!_saberSet.LeftSaber.GetCustomSaber(out var cs))
+ {
+ return;
+ }
+
+ _info = cs.ModelComposition.AdditionalInstanceHandler.GetComponent();
+
+ if (!_info)
+ {
+ return;
+ }
+
+ if (_info.BurnMarkMaterial)
+ {
+ BurnmarkMaterial = _info.BurnMarkMaterial;
+ }
+
+ //if (_info.SparkleMaterial)
+ //{
+ // _sparkle.Material = _info.SparkleMaterial;
+ //}
+
+ if (_info.FadeoutMaterial)
+ {
+ FadeoutMaterial = new Material(_info.FadeoutMaterial);
+ }
+
+ if (_info.FloorMaterial)
+ {
+ GetComponent().material = new Material(_info.FloorMaterial);
+ }
+
+ BurnmarkSize = _info.BurnmarkSize;
+
+ FadeoutStrength = _info.FadeStrength;
+ RandomOffset = _info.RandomBurnmarkJitter;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SaberFactory/Misc/SaberClashCustomizer.cs b/SaberFactory/Misc/SaberClashCustomizer.cs
new file mode 100644
index 0000000..de4122e
--- /dev/null
+++ b/SaberFactory/Misc/SaberClashCustomizer.cs
@@ -0,0 +1,163 @@
+using System.IO;
+using HarmonyLib;
+using IPA.Utilities;
+using SaberFactory.Helpers;
+using SaberFactory.Instances;
+using SaberFactory.Models;
+using SaberFactory.ProjectComponents;
+using SiraUtil.Affinity;
+using UnityEngine;
+using Zenject;
+using Object = UnityEngine.Object;
+
+namespace SaberFactory.Misc
+{
+ internal class PSManager
+ {
+ public readonly ParticleSystem ParticleSystem;
+ public readonly ParticleSystemRenderer Renderer;
+
+ private ParticleSystem.MainModule _main;
+
+ public Material Material
+ {
+ get => Renderer.sharedMaterial;
+ set => Renderer.sharedMaterial = value;
+ }
+
+ public Color Color
+ {
+ get => _main.startColor.color;
+ set => _main.startColor = value;
+ }
+
+ public ParticleSystem.MainModule Main => _main;
+
+ public PSManager(ParticleSystem particleSystem)
+ {
+ ParticleSystem = particleSystem;
+ _main = particleSystem.main;
+ Renderer = particleSystem.GetComponent();
+ }
+ }
+
+ internal class SaberClashCustomizer : IInitializable, IAffinity, ICustomizer
+ {
+ public bool ClashEnabled { get; set; }
+
+ private SaberClashEffect _currentClashEffect;
+ private PSManager _sparkle;
+ private PSManager _glow;
+
+ internal SaberClashCustomizer(EmbeddedAssetLoader assetLoader)
+ {
+ }
+
+ public void SetSaber(SaberInstance saber)
+ {
+ var info = saber.Model.PieceCollection[AssetTypeDefinition.CustomSaber].ModelComposition
+ .AdditionalInstanceHandler.GetComponent();
+ if (!info)
+ {
+ return;
+ }
+
+ if (info.Material)
+ {
+ _glow.Material = info.Material;
+ }
+ }
+
+ [AffinityPostfix]
+ [AffinityPatch(typeof(SaberClashEffect), nameof(SaberClashEffect.Start))]
+ protected void Setup(SaberClashEffect __instance, ParticleSystem ____sparkleParticleSystem, ParticleSystem ____glowParticleSystem)
+ {
+ _currentClashEffect = __instance;
+ _sparkle = new PSManager(____sparkleParticleSystem);
+ _glow = new PSManager(____glowParticleSystem);
+ }
+
+ public void Initialize()
+ {
+
+ }
+ }
+
+ //internal class SaberBurnMarkCustomizer : IInitializable, IAffinity, ICustomizer
+ //{
+ // private SaberBurnMarkSparkles _currentSpakles;
+ // private readonly CustomSaberBurnMarkArea _burnMarkArea;
+
+ // private PSManager _sparkle;
+ // private PSManager[] _burnMarks;
+
+ // private SFBurnmarks _currentInfo;
+
+ // public SaberBurnMarkCustomizer(CustomSaberBurnMarkArea burnMarkArea)
+ // {
+ // _burnMarkArea = burnMarkArea;
+ // }
+
+ // public void SetSaber(SaberInstance saber)
+ // {
+ // var info = saber.Model.PieceCollection[AssetTypeDefinition.CustomSaber].ModelComposition
+ // .AdditionalInstanceHandler.GetComponent();
+ // if (!info)
+ // {
+ // return;
+ // }
+
+ // if (info.BurnMarkMaterial)
+ // {
+ // _burnMarkArea.BurnmarkMaterial = info.BurnMarkMaterial;
+ // }
+
+ // if (info.SparkleMaterial)
+ // {
+ // _sparkle.Material = info.SparkleMaterial;
+ // }
+
+ // if (info.FadeoutMaterial)
+ // {
+ // _burnMarkArea.FadeoutMaterial = new Material(info.FadeoutMaterial);
+ // }
+
+ // if (info.FloorMaterial)
+ // {
+ // _burnMarkArea.GetComponent().material = new Material(info.FloorMaterial);
+ // }
+
+ // _burnMarkArea.BurnmarkSize = info.BurnmarkSize;
+
+ // _burnMarkArea.FadeoutStrength = info.FadeStrength;
+ // _burnMarkArea.RandomOffset = info.RandomBurnmarkJitter;
+ // }
+
+ // [AffinityPostfix]
+ // [AffinityPatch(typeof(SaberBurnMarkSparkles), nameof(SaberBurnMarkSparkles.Start))]
+ // protected void Setup(SaberBurnMarkSparkles __instance, ParticleSystem ____sparklesPS,
+ // ParticleSystem[] ____burnMarksPS)
+ // {
+ // _currentSpakles = __instance;
+
+ // _sparkle = new PSManager(____sparklesPS);
+ // Object.DestroyImmediate(_sparkle.Renderer);
+ // _burnMarks = new PSManager[2];
+ // _burnMarks[0] = new PSManager(____burnMarksPS[0]);
+ // _burnMarks[1] = new PSManager(____burnMarksPS[1]);
+
+ // Object.DestroyImmediate(_burnMarks[0].Renderer);
+ // Object.DestroyImmediate(_burnMarks[1].Renderer);
+ // }
+
+ // public void Initialize()
+ // {
+
+ // }
+ //}
+
+ internal interface ICustomizer
+ {
+ public void SetSaber(SaberInstance saber);
+ }
+}
diff --git a/SaberFactory/Models/AdditionalInstanceHandler.cs b/SaberFactory/Models/AdditionalInstanceHandler.cs
index edb6609..731cb5e 100644
--- a/SaberFactory/Models/AdditionalInstanceHandler.cs
+++ b/SaberFactory/Models/AdditionalInstanceHandler.cs
@@ -1,5 +1,7 @@
-using SaberFactory.Helpers;
+using System;
+using SaberFactory.Helpers;
using UnityEngine;
+using Object = UnityEngine.Object;
namespace SaberFactory.Models
{
@@ -7,19 +9,21 @@ namespace SaberFactory.Models
/// Class for handling gameobject outside of the left and right sabers or parts
/// Mostly used for custom sabers
///
- internal class AdditionalInstanceHandler
+ public class AdditionalInstanceHandler
{
public bool IsInstantiated => _instance != null;
private readonly GameObject _prefab;
+ private readonly GameObject _fallbackRightSaber;
private GameObject _customSaberLeftSaber;
private GameObject _customSaberRightSaber;
private GameObject _instance;
- public AdditionalInstanceHandler(GameObject prefab)
+ public AdditionalInstanceHandler(GameObject prefab, GameObject fallbackRightSaber)
{
_prefab = prefab;
+ _fallbackRightSaber = fallbackRightSaber;
}
public GameObject GetInstance()
@@ -55,6 +59,11 @@ public GameObject GetSaber(ESaberSlot saberSlot)
return saberSlot == ESaberSlot.Left ? _customSaberLeftSaber : _customSaberRightSaber;
}
+ public T GetComponent() where T : Component
+ {
+ return GetInstance().GetComponent();
+ }
+
public Transform FindInInstance(string name)
{
return GetInstance().transform.Find(name);
@@ -67,8 +76,20 @@ private void Instantiate()
_customSaberLeftSaber = GetSaber(ESaberSlot.Left);
_customSaberRightSaber = GetSaber(ESaberSlot.Right);
- _customSaberLeftSaber.SetActive(false);
- _customSaberRightSaber.SetActive(false);
+ if (_customSaberRightSaber == null)
+ {
+ _customSaberRightSaber = Object.Instantiate(_fallbackRightSaber);
+ }
+
+ if (_customSaberLeftSaber != null)
+ {
+ _customSaberLeftSaber.SetActive(false);
+ }
+
+ if (_customSaberRightSaber != null)
+ {
+ _customSaberRightSaber.SetActive(false);
+ }
}
}
}
\ No newline at end of file
diff --git a/SaberFactory/Models/AssetTypeDefinition.cs b/SaberFactory/Models/AssetTypeDefinition.cs
index de2dfec..ae0cc6f 100644
--- a/SaberFactory/Models/AssetTypeDefinition.cs
+++ b/SaberFactory/Models/AssetTypeDefinition.cs
@@ -3,7 +3,7 @@
namespace SaberFactory.Models
{
[Serializable]
- internal readonly struct AssetTypeDefinition
+ public readonly struct AssetTypeDefinition
{
public static readonly AssetTypeDefinition CustomSaber = new AssetTypeDefinition(EAssetType.Model, EAssetSubType.CustomSaber);
diff --git a/SaberFactory/Models/BasePieceModel.cs b/SaberFactory/Models/BasePieceModel.cs
index 4dac711..b6cbbc8 100644
--- a/SaberFactory/Models/BasePieceModel.cs
+++ b/SaberFactory/Models/BasePieceModel.cs
@@ -14,7 +14,7 @@ namespace SaberFactory.Models
/// Model related to everything that makes up a saber
/// like parts, halos, accessories, custom sabers
///
- internal class BasePieceModel : IDisposable, IFactorySerializable
+ public class BasePieceModel : IDisposable, IFactorySerializable
{
///
/// Type of the associated instance class
diff --git a/SaberFactory/Models/CustomSaber/CustomSaberModel.cs b/SaberFactory/Models/CustomSaber/CustomSaberModel.cs
index 53c5bfd..e8f5823 100644
--- a/SaberFactory/Models/CustomSaber/CustomSaberModel.cs
+++ b/SaberFactory/Models/CustomSaber/CustomSaberModel.cs
@@ -14,7 +14,7 @@
namespace SaberFactory.Models.CustomSaber
{
- internal class CustomSaberModel : BasePieceModel
+ public class CustomSaberModel : BasePieceModel
{
public override Type InstanceType { get; protected set; } = typeof(CustomSaberInstance);
diff --git a/SaberFactory/Models/CustomSaber/CustomSaberModelLoader.cs b/SaberFactory/Models/CustomSaber/CustomSaberModelLoader.cs
index bb022fb..976847f 100644
--- a/SaberFactory/Models/CustomSaber/CustomSaberModelLoader.cs
+++ b/SaberFactory/Models/CustomSaber/CustomSaberModelLoader.cs
@@ -1,6 +1,8 @@
-using SaberFactory.Configuration;
+using System;
+using SaberFactory.Configuration;
using SaberFactory.DataStore;
using UnityEngine;
+using Object = UnityEngine.Object;
namespace SaberFactory.Models.CustomSaber
{
@@ -19,6 +21,21 @@ public ModelComposition GetComposition(StoreAsset storeAsset)
{
var (leftSaber, rightSaber) = GetSabers(storeAsset.Prefab.transform);
+ if (rightSaber == null)
+ {
+ var newParent = new GameObject("RightSaber").transform;
+ newParent.parent = storeAsset.Prefab.transform;
+
+ rightSaber = Object.Instantiate(leftSaber, newParent, false);
+ rightSaber.transform.position = Vector3.zero;
+ rightSaber.transform.localScale = new Vector3(-1, 1, 1);
+
+ rightSaber.name = "RightSaberMirror";
+
+ rightSaber = newParent.gameObject;
+ rightSaber.SetActive(false);
+ }
+
var storeAssetLeft = new StoreAsset(storeAsset.RelativePath, leftSaber, storeAsset.AssetBundle);
var storeAssetRight = new StoreAsset(storeAsset.RelativePath, rightSaber, storeAsset.AssetBundle);
diff --git a/SaberFactory/Models/EAssetSubType.cs b/SaberFactory/Models/EAssetSubType.cs
index b1b17b5..950de23 100644
--- a/SaberFactory/Models/EAssetSubType.cs
+++ b/SaberFactory/Models/EAssetSubType.cs
@@ -1,6 +1,6 @@
namespace SaberFactory.Models
{
- internal enum EAssetSubType
+ public enum EAssetSubType
{
Blade,
Emitter,
diff --git a/SaberFactory/Models/EAssetType.cs b/SaberFactory/Models/EAssetType.cs
index 3c037be..d181629 100644
--- a/SaberFactory/Models/EAssetType.cs
+++ b/SaberFactory/Models/EAssetType.cs
@@ -1,6 +1,6 @@
namespace SaberFactory.Models
{
- internal enum EAssetType
+ public enum EAssetType
{
Model,
Halo
diff --git a/SaberFactory/Models/ESaberSlot.cs b/SaberFactory/Models/ESaberSlot.cs
index 1c3ce0a..6278d1d 100644
--- a/SaberFactory/Models/ESaberSlot.cs
+++ b/SaberFactory/Models/ESaberSlot.cs
@@ -1,6 +1,6 @@
namespace SaberFactory.Models
{
- internal enum ESaberSlot
+ public enum ESaberSlot
{
Left,
Right
diff --git a/SaberFactory/Models/ModelComposition.cs b/SaberFactory/Models/ModelComposition.cs
index 3e062ac..d70f611 100644
--- a/SaberFactory/Models/ModelComposition.cs
+++ b/SaberFactory/Models/ModelComposition.cs
@@ -8,7 +8,7 @@ namespace SaberFactory.Models
///
/// Stores left and right piece models + additional detached game objects in a composition
///
- internal class ModelComposition : IDisposable, ICustomListItem
+ public class ModelComposition : IDisposable, ICustomListItem
{
public readonly AdditionalInstanceHandler AdditionalInstanceHandler;
public readonly AssetTypeDefinition AssetTypeDefinition;
@@ -25,7 +25,7 @@ public ModelComposition(AssetTypeDefinition definition, BasePieceModel modelLeft
AssetTypeDefinition = definition;
_modelLeft = modelLeft;
_modelRight = modelRight;
- AdditionalInstanceHandler = new AdditionalInstanceHandler(additionalData);
+ AdditionalInstanceHandler = new AdditionalInstanceHandler(additionalData, modelRight.StoreAsset.Prefab);
if (_modelLeft == null && _modelRight == null)
{
diff --git a/SaberFactory/Models/ModelMetaData.cs b/SaberFactory/Models/ModelMetaData.cs
index e2b015e..343ea9e 100644
--- a/SaberFactory/Models/ModelMetaData.cs
+++ b/SaberFactory/Models/ModelMetaData.cs
@@ -2,7 +2,7 @@
namespace SaberFactory.Models
{
- internal struct ModelMetaData
+ public struct ModelMetaData
{
public string Name;
public string Author;
diff --git a/SaberFactory/Models/PartEvents.cs b/SaberFactory/Models/PartEvents.cs
index ea4f7ab..703b8eb 100644
--- a/SaberFactory/Models/PartEvents.cs
+++ b/SaberFactory/Models/PartEvents.cs
@@ -4,7 +4,7 @@
namespace SaberFactory.Models
{
- internal class PartEvents
+ public class PartEvents
{
public UnityEvent MultiplierUp;
diff --git a/SaberFactory/Models/PieceCollection.cs b/SaberFactory/Models/PieceCollection.cs
index c58c782..6360083 100644
--- a/SaberFactory/Models/PieceCollection.cs
+++ b/SaberFactory/Models/PieceCollection.cs
@@ -7,7 +7,7 @@ namespace SaberFactory.Models
/// Class for managing a collection of parts
///
///
- internal class PieceCollection : IEnumerable
+ public class PieceCollection : IEnumerable
{
public T this[AssetTypeDefinition definition]
{
diff --git a/SaberFactory/Models/PreloadMetaData.cs b/SaberFactory/Models/PreloadMetaData.cs
index 79d4c9b..d8a9000 100644
--- a/SaberFactory/Models/PreloadMetaData.cs
+++ b/SaberFactory/Models/PreloadMetaData.cs
@@ -10,7 +10,7 @@
namespace SaberFactory.Models
{
- internal class PreloadMetaData : ICustomListItem
+ public class PreloadMetaData : ICustomListItem
{
public AssetTypeDefinition AssetTypeDefinition { get; private set; }
@@ -40,18 +40,18 @@ public Sprite CoverSprite
}
}
- public readonly AssetMetaPath AssetMetaPath;
+ internal readonly AssetMetaPath AssetMetaPath;
private byte[] _coverData;
private Sprite _coverSprite;
private Texture2D _coverTex;
- public PreloadMetaData(AssetMetaPath assetMetaPath)
+ internal PreloadMetaData(AssetMetaPath assetMetaPath)
{
AssetMetaPath = assetMetaPath;
}
- public PreloadMetaData(AssetMetaPath assetMetaPath, ICustomListItem customListItem, AssetTypeDefinition assetTypeDefinition)
+ internal PreloadMetaData(AssetMetaPath assetMetaPath, ICustomListItem customListItem, AssetTypeDefinition assetTypeDefinition)
{
AssetMetaPath = assetMetaPath;
AssetTypeDefinition = assetTypeDefinition;
diff --git a/SaberFactory/Models/PropHandler/PiecePropertyBlock.cs b/SaberFactory/Models/PropHandler/PiecePropertyBlock.cs
index 64bf418..da287ad 100644
--- a/SaberFactory/Models/PropHandler/PiecePropertyBlock.cs
+++ b/SaberFactory/Models/PropHandler/PiecePropertyBlock.cs
@@ -8,7 +8,7 @@ namespace SaberFactory.Models.PropHandler
///
/// Base class for storing customizable / serializable properties
///
- internal abstract class PiecePropertyBlock : IFactorySerializable
+ public abstract class PiecePropertyBlock : IFactorySerializable
{
public TransformPropertyBlock TransformProperty;
diff --git a/SaberFactory/Models/PropHandler/TransformPropertyBlock.cs b/SaberFactory/Models/PropHandler/TransformPropertyBlock.cs
index 63fb8ae..e36e228 100644
--- a/SaberFactory/Models/PropHandler/TransformPropertyBlock.cs
+++ b/SaberFactory/Models/PropHandler/TransformPropertyBlock.cs
@@ -8,7 +8,7 @@ namespace SaberFactory.Models.PropHandler
///
/// Class to store transform data
///
- internal class TransformPropertyBlock : IFactorySerializable
+ public class TransformPropertyBlock : IFactorySerializable
{
public float Width { get; set; } = 1;
diff --git a/SaberFactory/Models/SaberModel.cs b/SaberFactory/Models/SaberModel.cs
index 8310c91..b9008f0 100644
--- a/SaberFactory/Models/SaberModel.cs
+++ b/SaberFactory/Models/SaberModel.cs
@@ -12,7 +12,7 @@ namespace SaberFactory.Models
/// Stores information on how to build a saber instance
///
[JsonObject(MemberSerialization.OptIn)]
- internal class SaberModel : IFactorySerializable
+ public class SaberModel : IFactorySerializable
{
public bool IsEmpty => PieceCollection.PieceCount == 0;
public readonly PieceCollection PieceCollection;
diff --git a/SaberFactory/Models/SaberSet.cs b/SaberFactory/Models/SaberSet.cs
index 59b2e92..018d27e 100644
--- a/SaberFactory/Models/SaberSet.cs
+++ b/SaberFactory/Models/SaberSet.cs
@@ -15,7 +15,7 @@ namespace SaberFactory.Models
///
/// Stores currently used left and right saber model implementation
///
- internal class SaberSet : IFactorySerializable, ILoadingTask
+ public class SaberSet : IFactorySerializable, ILoadingTask
{
public SaberModel LeftSaber { get; set; }
diff --git a/SaberFactory/Models/TrailModel.cs b/SaberFactory/Models/TrailModel.cs
index e4151ab..aebbb0f 100644
--- a/SaberFactory/Models/TrailModel.cs
+++ b/SaberFactory/Models/TrailModel.cs
@@ -14,7 +14,7 @@ namespace SaberFactory.Models
///
/// Stores information on how to build a trail
///
- internal class TrailModel : IFactorySerializable
+ public class TrailModel : IFactorySerializable
{
public int OriginalLength { get; private set; }
diff --git a/SaberFactory/Modifiers/BaseModifierImpl.cs b/SaberFactory/Modifiers/BaseModifierImpl.cs
index 70093cd..f4714d6 100644
--- a/SaberFactory/Modifiers/BaseModifierImpl.cs
+++ b/SaberFactory/Modifiers/BaseModifierImpl.cs
@@ -3,7 +3,7 @@
namespace SaberFactory.Modifiers
{
- internal abstract class BaseModifierImpl : UpdatableSerialializable, IStringUiProvider
+ public abstract class BaseModifierImpl : UpdatableSerialializable, IStringUiProvider
{
public abstract string Name { get; }
public abstract string TypeName { get; }
diff --git a/SaberFactory/Modifiers/ModifyableComponentManager.cs b/SaberFactory/Modifiers/ModifyableComponentManager.cs
index 800a63d..eba59bf 100644
--- a/SaberFactory/Modifiers/ModifyableComponentManager.cs
+++ b/SaberFactory/Modifiers/ModifyableComponentManager.cs
@@ -12,7 +12,7 @@
namespace SaberFactory.Modifiers
{
- internal class ModifyableComponentManager : IFactorySerializable
+ public class ModifyableComponentManager : IFactorySerializable
{
public readonly Dictionary Mods = new Dictionary();
@@ -22,7 +22,7 @@ internal class ModifyableComponentManager : IFactorySerializable
public ModifyableComponentManager(GameObject prefab)
{
- SaberModifierCollection = prefab.GetComponent();
+ SaberModifierCollection = prefab.GetComponentInChildren();
}
public async Task FromJson(JObject obj, Serializer serializer)
@@ -102,7 +102,7 @@ public void SetInstance(GameObject gameObject)
return;
}
- var saberModifierCollection = gameObject.GetComponent();
+ var saberModifierCollection = gameObject.GetComponentInChildren();
if (saberModifierCollection == null)
{
return;
diff --git a/SaberFactory/Modifiers/TransformModifierImpl.cs b/SaberFactory/Modifiers/TransformModifierImpl.cs
index 2278b88..cf2491a 100644
--- a/SaberFactory/Modifiers/TransformModifierImpl.cs
+++ b/SaberFactory/Modifiers/TransformModifierImpl.cs
@@ -276,6 +276,11 @@ private void SetPositionOffset(Vector3 offset)
foreach (var t in _transforms)
{
+ if (!t.transform)
+ {
+ continue;
+ }
+
t.transform.localPosition = t.ogPos + offset;
}
}
@@ -289,6 +294,11 @@ private void SetScaleOffset(Vector3 offset)
foreach (var t in _transforms)
{
+ if (!t.transform)
+ {
+ continue;
+ }
+
t.transform.localScale = t.ogScale + offset;
}
}
@@ -302,6 +312,11 @@ private void SetRotationOffset(float offset)
foreach (var t in _transforms)
{
+ if (!t.transform)
+ {
+ continue;
+ }
+
t.transform.localRotation = t.ogRotation * Quaternion.Euler(Vector3.forward * offset);
}
}
diff --git a/SaberFactory/Plugin.cs b/SaberFactory/Plugin.cs
index d948c6a..386ffe9 100644
--- a/SaberFactory/Plugin.cs
+++ b/SaberFactory/Plugin.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using HarmonyLib;
@@ -6,10 +7,14 @@
using IPA.Config;
using IPA.Config.Stores;
using IPA.Loader;
+using IPA.Utilities;
using SaberFactory.Configuration;
using SaberFactory.Helpers;
using SaberFactory.Installers;
+using SaberFactory.Misc;
using SiraUtil.Zenject;
+using UnityEngine;
+using Zenject;
using IPALogger = IPA.Logging.Logger;
namespace SaberFactory
@@ -42,6 +47,12 @@ public async void Init(IPALogger logger, Config conf, Zenjector zenjector, Plugi
zenjector.Install(Location.App, logger, pluginConfig, metadata);
zenjector.Install(Location.Menu);
zenjector.Install(Location.Player | Location.MultiPlayer);
+
+ zenjector.Mutate("Environment", (ctx, ogBurnMark) =>
+ {
+ var newBurner = CommonHelpers.Upgrade(ogBurnMark, typeof(CustomSaberBurnMarkArea));
+ ctx.Container.QueueForInject(newBurner);
+ });
}
[OnEnable]
diff --git a/SaberFactory/ProjectComponents/HelpAttribute.cs b/SaberFactory/ProjectComponents/HelpAttribute.cs
new file mode 100644
index 0000000..e4a08d0
--- /dev/null
+++ b/SaberFactory/ProjectComponents/HelpAttribute.cs
@@ -0,0 +1,230 @@
+// --------------------------------------------------------------------------------------------------------------------
+///
+///
+/// Copyright (c) 2017, John Earnshaw, reblGreen Software Limited
+///
+///
+///
+/// All rights reserved.
+/// Redistribution and use in source and binary forms, with or without modification, are
+/// permitted provided that the following conditions are met:
+/// 1. Redistributions of source code must retain the above copyright notice, this list of
+/// conditions and the following disclaimer.
+/// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+/// of conditions and the following disclaimer in the documentation and/or other materials
+/// provided with the distribution.
+/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+/// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+/// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE
+/// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+/// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+/// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+/// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+/// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+/// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+///
+// --------------------------------------------------------------------------------------------------------------------
+using System;
+using UnityEngine;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+[AttributeUsage(AttributeTargets.Field, Inherited = true)]
+public class HelpAttribute : PropertyAttribute
+{
+ public readonly string text;
+
+ // MessageType exists in UnityEditor namespace and can throw an exception when used outside the editor.
+ // We spoof MessageType at the bottom of this script to ensure that errors are not thrown when
+ // MessageType is unavailable.
+ public readonly MessageType type;
+
+
+ ///
+ /// Adds a HelpBox to the Unity property inspector above this field.
+ ///
+ /// The help text to be displayed in the HelpBox.
+ /// The icon to be displayed in the HelpBox.
+ public HelpAttribute(string text, MessageType type = MessageType.Info)
+ {
+ this.text = text;
+ this.type = type;
+ }
+}
+
+#if UNITY_EDITOR
+[CustomPropertyDrawer(typeof(HelpAttribute))]
+public class HelpDrawer : PropertyDrawer
+{
+ // Used for top and bottom padding between the text and the HelpBox border.
+ const int paddingHeight = 8;
+
+ // Used to add some margin between the the HelpBox and the property.
+ const int marginHeight = 2;
+
+ // Global field to store the original (base) property height.
+ float baseHeight = 0;
+
+ // Custom added height for drawing text area which has the MultilineAttribute.
+ float addedHeight = 0;
+
+ ///
+ /// A wrapper which returns the PropertyDrawer.attribute field as a HelpAttribute.
+ ///
+ HelpAttribute helpAttribute { get { return (HelpAttribute)attribute; } }
+
+ ///
+ /// A helper property to check for RangeAttribute.
+ ///
+ RangeAttribute rangeAttribute
+ {
+ get
+ {
+ var attributes = fieldInfo.GetCustomAttributes(typeof(RangeAttribute), true);
+ return attributes != null && attributes.Length > 0 ? (RangeAttribute)attributes[0] : null;
+ }
+ }
+
+ ///
+ /// A helper property to check for MultiLineAttribute.
+ ///
+ MultilineAttribute multilineAttribute
+ {
+ get
+ {
+ var attributes = fieldInfo.GetCustomAttributes(typeof(MultilineAttribute), true);
+ return attributes != null && attributes.Length > 0 ? (MultilineAttribute)attributes[0] : null;
+ }
+ }
+
+
+ public override float GetPropertyHeight(SerializedProperty prop, GUIContent label)
+ {
+ // We store the original property height for later use...
+ baseHeight = base.GetPropertyHeight(prop, label);
+
+ // This stops icon shrinking if text content doesn't fill out the container enough.
+ float minHeight = paddingHeight * 5;
+
+ // Calculate the height of the HelpBox using the GUIStyle on the current skin and the inspector
+ // window's currentViewWidth.
+ var content = new GUIContent(helpAttribute.text);
+ var style = GUI.skin.GetStyle("helpbox");
+
+ var height = style.CalcHeight(content, EditorGUIUtility.currentViewWidth);
+
+ // We add tiny padding here to make sure the text is not overflowing the HelpBox from the top
+ // and bottom.
+ height += marginHeight * 2;
+
+ // Since we draw a custom text area with the label above if our property contains the
+ // MultilineAttribute, we need to add some extra height to compensate. This is stored in a
+ // seperate global field so we can use it again later.
+ if (multilineAttribute != null && prop.propertyType == SerializedPropertyType.String)
+ {
+ addedHeight = 48f;
+ }
+
+ // If the calculated HelpBox is less than our minimum height we use this to calculate the returned
+ // height instead.
+ return height > minHeight ? height + baseHeight + addedHeight : minHeight + baseHeight + addedHeight;
+ }
+
+
+ public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
+ {
+ // We get a local reference to the MultilineAttribute as we use it twice in this method and it
+ // saves calling the logic twice for minimal optimization, etc...
+ var multiline = multilineAttribute;
+
+ EditorGUI.BeginProperty(position, label, prop);
+
+ // Copy the position out so we can calculate the position of our HelpBox without affecting the
+ // original position.
+ var helpPos = position;
+
+ helpPos.height -= baseHeight + marginHeight;
+
+
+ if (multiline != null)
+ {
+ helpPos.height -= addedHeight;
+ }
+
+ // Renders the HelpBox in the Unity inspector UI.
+ EditorGUI.HelpBox(helpPos, helpAttribute.text, helpAttribute.type);
+
+ position.y += helpPos.height + marginHeight;
+ position.height = baseHeight;
+
+
+ // If we have a RangeAttribute on our field, we need to handle the PropertyDrawer differently to
+ // keep the same style as Unity's default.
+ var range = rangeAttribute;
+
+ if (range != null)
+ {
+ if (prop.propertyType == SerializedPropertyType.Float)
+ {
+ EditorGUI.Slider(position, prop, range.min, range.max, label);
+ }
+ else if (prop.propertyType == SerializedPropertyType.Integer)
+ {
+ EditorGUI.IntSlider(position, prop, (int)range.min, (int)range.max, label);
+ }
+ else
+ {
+ // Not numeric so draw standard property field as punishment for adding RangeAttribute to
+ // a property which can not have a range :P
+ EditorGUI.PropertyField(position, prop, label);
+ }
+ }
+ else if (multiline != null)
+ {
+ // Here's where we handle the PropertyDrawer differently if we have a MultiLineAttribute, to try
+ // and keep some kind of multiline text area. This is not identical to Unity's default but is
+ // better than nothing...
+ if (prop.propertyType == SerializedPropertyType.String)
+ {
+ var style = GUI.skin.label;
+ var size = style.CalcHeight(label, EditorGUIUtility.currentViewWidth);
+
+ EditorGUI.LabelField(position, label);
+
+ position.y += size;
+ position.height += addedHeight - size;
+
+ // Fixed text dissappearing thanks to: http://answers.unity3d.com/questions/244043/textarea-does-not-work-text-dissapears-solution-is.html
+ prop.stringValue = EditorGUI.TextArea(position, prop.stringValue);
+ }
+ else
+ {
+ // Again with a MultilineAttribute on a non-text field deserves for the standard property field
+ // to be drawn as punishment :P
+ EditorGUI.PropertyField(position, prop, label);
+ }
+ }
+ else
+ {
+ // If we get to here it means we're drawing the default property field below the HelpBox. More custom
+ // and built in PropertyDrawers could be implemented to enable HelpBox but it could easily make for
+ // hefty else/if block which would need refactoring!
+ EditorGUI.PropertyField(position, prop, label);
+ }
+
+ EditorGUI.EndProperty();
+ }
+}
+#else
+ // Replicate MessageType Enum if we are not in editor as this enum exists in UnityEditor namespace.
+ // This should stop errors being logged the same as Shawn Featherly's commit in the Github repo but I
+ // feel is cleaner than having the conditional directive in the middle of the HelpAttribute constructor.
+ public enum MessageType
+ {
+ None,
+ Info,
+ Warning,
+ Error,
+ }
+#endif
diff --git a/SaberFactory/ProjectComponents/SFBurnmarks.cs b/SaberFactory/ProjectComponents/SFBurnmarks.cs
new file mode 100644
index 0000000..c698dc9
--- /dev/null
+++ b/SaberFactory/ProjectComponents/SFBurnmarks.cs
@@ -0,0 +1,29 @@
+using UnityEngine;
+
+namespace SaberFactory.ProjectComponents
+{
+ public class SFBurnmarks : MonoBehaviour
+ {
+ [Header("Parameters")]
+ public float RandomBurnmarkJitter = 0.001f;
+
+ public float FadeStrength = 0.3f;
+
+ public float BurnmarkSize = 0.1f;
+
+ [Help("Only Assign the materials you actually need")]
+ [Header("Basic Materials")]
+ [Tooltip("Material for the spark particle system")]
+ public Material SparkleMaterial;
+
+ [Tooltip("Material for the linerenderer of the burnmarks")]
+ public Material BurnMarkMaterial;
+
+ [Tooltip("The rendertexture of the burnmarks will be passed to this material relative to the floor")]
+ public Material FloorMaterial;
+
+ [Header("Advanced Materials")]
+ [Tooltip("Material to use for blitting the faded rendertexture")]
+ public Material FadeoutMaterial;
+ }
+}
\ No newline at end of file
diff --git a/SaberFactory/ProjectComponents/SFClashEffect.cs b/SaberFactory/ProjectComponents/SFClashEffect.cs
new file mode 100644
index 0000000..914d241
--- /dev/null
+++ b/SaberFactory/ProjectComponents/SFClashEffect.cs
@@ -0,0 +1,9 @@
+using UnityEngine;
+
+namespace SaberFactory.ProjectComponents
+{
+ public class SFClashEffect : MonoBehaviour
+ {
+ public Material Material;
+ }
+}
\ No newline at end of file
diff --git a/SaberFactory/ProjectComponents/SFSaberSound.cs b/SaberFactory/ProjectComponents/SFSaberSound.cs
new file mode 100644
index 0000000..262e8a4
--- /dev/null
+++ b/SaberFactory/ProjectComponents/SFSaberSound.cs
@@ -0,0 +1,78 @@
+#if !UNITY
+using SaberFactory.Helpers;
+#endif
+using UnityEngine;
+
+namespace SaberFactory.ProjectComponents
+{
+ public class SFSaberSound : MonoBehaviour
+ {
+ public Transform SaberTop;
+
+ public AudioSource AudioSource;
+
+ public AnimationCurve PitchBySpeedCurve;
+
+ public AnimationCurve GainBySpeedCurve;
+
+ public float SpeedMultiplier = 0.05f;
+
+ public float UpSmooth = 4f;
+
+ public float DownSmooth = 4f;
+
+ [Tooltip("No sound is produced if saber point moves more than this distance in one frame.")]
+ public float NoSoundTopThresholdSqr = 1f;
+
+ [Range(0, 1)]
+ public float Volume = 1;
+
+#if !UNITY
+ public float ConfigVolume = 1;
+
+ private Vector3 _prevPos;
+ private float _speed;
+
+ public virtual void Start()
+ {
+ _prevPos = SaberTop.position;
+
+ var saberMb = SaberHelpers.GetSaberMonoBehaviour(gameObject);
+ if (saberMb)
+ {
+ saberMb.RegisterComponent(this);
+ }
+ }
+
+ public virtual void Update()
+ {
+ var position = SaberTop.position;
+ if ((_prevPos - position).sqrMagnitude > NoSoundTopThresholdSqr) _prevPos = position;
+
+ float targetSpeed;
+ if (Time.deltaTime == 0f)
+ {
+ targetSpeed = 0f;
+ }
+ else
+ {
+ targetSpeed = SpeedMultiplier * Vector3.Distance(position, _prevPos) / Time.deltaTime;
+ }
+
+ if (targetSpeed < _speed)
+ {
+ _speed = Mathf.Clamp01(Mathf.Lerp(_speed, targetSpeed, Time.deltaTime * DownSmooth));
+ }
+ else
+ {
+ _speed = Mathf.Clamp01(Mathf.Lerp(_speed, targetSpeed, Time.deltaTime * UpSmooth));
+ }
+
+ AudioSource.pitch = PitchBySpeedCurve.Evaluate(_speed);
+ AudioSource.volume = GainBySpeedCurve.Evaluate(_speed) * Volume * ConfigVolume;
+
+ _prevPos = position;
+ }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/SaberFactory/ProjectComponents/SaberModifierCollection.cs b/SaberFactory/ProjectComponents/SaberModifierCollection.cs
index 1df1792..f1bb824 100644
--- a/SaberFactory/ProjectComponents/SaberModifierCollection.cs
+++ b/SaberFactory/ProjectComponents/SaberModifierCollection.cs
@@ -26,7 +26,7 @@ public bool Init()
{
return _inited;
}
-
+
Newtonsoft.Json.JsonConvert.PopulateObject(ObjectJson, this);
foreach (var mod in VisibilityModifiers)
diff --git a/SaberFactory/Resources/pedestal b/SaberFactory/Resources/pedestal
new file mode 100644
index 0000000..90d9de4
Binary files /dev/null and b/SaberFactory/Resources/pedestal differ
diff --git a/SaberFactory/SaberFactory.csproj b/SaberFactory/SaberFactory.csproj
index 20a03c4..9d182b1 100644
--- a/SaberFactory/SaberFactory.csproj
+++ b/SaberFactory/SaberFactory.csproj
@@ -148,10 +148,10 @@
False
- ..\..\..\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll
+ $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll
- ..\..\..\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.ParticleSystemModule.dll
+ $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.ParticleSystemModule.dll
$(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.PhysicsModule.dll
@@ -195,7 +195,8 @@
-
+
+
diff --git a/SaberFactory/Serialization/PresetSaveManager.cs b/SaberFactory/Serialization/PresetSaveManager.cs
index 893e963..7717cf9 100644
--- a/SaberFactory/Serialization/PresetSaveManager.cs
+++ b/SaberFactory/Serialization/PresetSaveManager.cs
@@ -7,7 +7,7 @@
namespace SaberFactory.Serialization
{
- internal class PresetSaveManager
+ public class PresetSaveManager
{
private readonly DirectoryInfo _presetDir;
private readonly Serializer _serializer;
diff --git a/SaberFactory/Serialization/Serializer.cs b/SaberFactory/Serialization/Serializer.cs
index 09774fd..2cbf2d3 100644
--- a/SaberFactory/Serialization/Serializer.cs
+++ b/SaberFactory/Serialization/Serializer.cs
@@ -10,7 +10,7 @@
namespace SaberFactory.Serialization
{
- internal class Serializer
+ public class Serializer
{
public static readonly JsonSerializer JsonSerializer = new JsonSerializer();
diff --git a/SaberFactory/Serialization/UpdatableSerialializable.cs b/SaberFactory/Serialization/UpdatableSerialializable.cs
index a3a6c9f..9e17b18 100644
--- a/SaberFactory/Serialization/UpdatableSerialializable.cs
+++ b/SaberFactory/Serialization/UpdatableSerialializable.cs
@@ -9,7 +9,7 @@
namespace SaberFactory.Serialization
{
- internal class UpdatableSerialializable : IFactorySerializable
+ public class UpdatableSerialializable : IFactorySerializable
{
private readonly List<(HandledValueAttribute, PropertyInfo)> _updateProps = new List<(HandledValueAttribute, PropertyInfo)>();
diff --git a/SaberFactory/UI/CustomSaber/Views/Modifier/MainModifierPanelView.cs b/SaberFactory/UI/CustomSaber/Views/Modifier/MainModifierPanelView.cs
index 63c8595..c1bdcf1 100644
--- a/SaberFactory/UI/CustomSaber/Views/Modifier/MainModifierPanelView.cs
+++ b/SaberFactory/UI/CustomSaber/Views/Modifier/MainModifierPanelView.cs
@@ -26,6 +26,7 @@ internal class MainModifierPanelView : SubView, INavigationCategoryView
protected override string _resourceName => PatViewPath;
[UIValue("pat-preview")] private string PatPreview => "https://www.youtube.com/watch?v=xI-YFoPilxU";
[UIValue("has-pat-preview")] private bool HasPatPreview => true;
+ [UIValue("additional-pat-info")] private string AdditionalPatInfo => "Feature needs to be implemented on saber";
#endif
[UIObject("container")] private readonly GameObject _container = null;
diff --git a/SaberFactory/UI/CustomSaber/Views/SaberSelectorView.cs b/SaberFactory/UI/CustomSaber/Views/SaberSelectorView.cs
index fe438d5..811e333 100644
--- a/SaberFactory/UI/CustomSaber/Views/SaberSelectorView.cs
+++ b/SaberFactory/UI/CustomSaber/Views/SaberSelectorView.cs
@@ -16,7 +16,6 @@
using SaberFactory.Helpers;
using SaberFactory.Loaders;
using SaberFactory.Models;
-using SaberFactory.Serialization;
using SaberFactory.UI.CustomSaber.CustomComponents;
using SaberFactory.UI.CustomSaber.Popups;
using SaberFactory.UI.Lib;
@@ -62,12 +61,10 @@ private float SaberWidth
[Inject] private readonly EditorInstanceManager _editorInstanceManager = null;
[Inject] private readonly MainAssetStore _mainAssetStore = null;
- [Inject(Id = nameof(SaberFactory))] private readonly PluginMetadata _metadata = null;
[Inject] private readonly PluginConfig _pluginConfig = null;
[Inject] private readonly List _remoteParts = null;
[Inject] private readonly SaberFileWatcher _saberFileWatcher = null;
[Inject] private readonly SaberSet _saberSet = null;
- [Inject] private readonly Serializer _serializer = null;
private ModelComposition _currentComposition;
private PreloadMetaData _currentPreloadMetaData;
private SaberListDirectoryManager _dirManager;
@@ -108,7 +105,7 @@ private async void Setup()
_dirManager = new SaberListDirectoryManager(_mainAssetStore.AdditionalCustomSaberFolders);
_saberList.OnItemSelected += SaberSelected;
_saberList.OnCategorySelected += DirectorySelected;
- _listTitle = "Saber Factory " + _metadata.HVersion + "";
+ _listTitle = "";
_saberList.SetText(_listTitle);
await LoadSabers();
@@ -123,15 +120,6 @@ private async void Setup()
}
}
- private async void Update()
- {
- if (Input.GetKeyDown(KeyCode.N))
- {
- File.WriteAllText("Serialized.txt", (await _saberSet.ToJson(_serializer)).ToString());
- Debug.LogWarning("Serialized");
- }
- }
-
private async void DirectorySelected(string dir)
{
_dirManager.Navigate(dir);
@@ -206,6 +194,7 @@ orderby meta.IsFavorite descending
if (_currentComposition != null)
{
_saberList.Select(_mainAssetStore.GetMetaDataForComposition(_currentComposition)?.ListName, !scrollToTop);
+ UpdatePedestalText(_currentComposition);
}
if (scrollToTop)
@@ -213,6 +202,7 @@ orderby meta.IsFavorite descending
_saberList.ScrollTo(0);
}
+
UpdateUi();
}
@@ -275,14 +265,27 @@ await _mainAssetStore.CreateMetaData(
{
await ShowSabers();
}
+
+ _editor.FlashPedestal(new Color(0.24f, 0.77f, 1f));
}
private void CompositionDidChange(ModelComposition comp)
{
_currentComposition = comp;
+ UpdatePedestalText(comp);
_saberList.Select(comp);
}
+ private void UpdatePedestalText(ICustomListItem item)
+ {
+ var saberName = item.ListName;
+ if (saberName.Length > 12)
+ {
+ saberName = saberName.Substring(0, 9) + "...";
+ }
+ _editor.SetPedestalText(0, saberName);
+ }
+
private void UpdateUi()
{
if (_currentComposition == null)
diff --git a/SaberFactory/UI/CustomSaber/Views/SettingsView.bsml b/SaberFactory/UI/CustomSaber/Views/SettingsView.bsml
index 08572c9..17f2c61 100644
--- a/SaberFactory/UI/CustomSaber/Views/SettingsView.bsml
+++ b/SaberFactory/UI/CustomSaber/Views/SettingsView.bsml
@@ -1,7 +1,7 @@
-
+
@@ -13,6 +13,8 @@
hover-hint='Choose a random saber on every song start'/>
+
+
diff --git a/SaberFactory/UI/CustomSaber/Views/SettingsView.cs b/SaberFactory/UI/CustomSaber/Views/SettingsView.cs
index c6938a4..63f6ad3 100644
--- a/SaberFactory/UI/CustomSaber/Views/SettingsView.cs
+++ b/SaberFactory/UI/CustomSaber/Views/SettingsView.cs
@@ -1,7 +1,10 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
using System.Threading;
using BeatSaberMarkupLanguage.Attributes;
using SaberFactory.Configuration;
+using SaberFactory.Editor;
+using SaberFactory.ProjectComponents;
using SaberFactory.UI.CustomSaber.CustomComponents;
using SaberFactory.UI.Lib;
using UnityEngine;
@@ -11,8 +14,8 @@ namespace SaberFactory.UI.CustomSaber.Views
{
internal class SettingsView : SubView, INavigationCategoryView
{
- private static readonly string PROFILE_URL = "https://ko-fi.com/tonimacaroni";
- private static readonly string DISCORD_URL = "https://discord.gg/PjD7WcChH3";
+ private const string ProfileUrl = "https://ko-fi.com/tonimacaroni";
+ private const string DiscordUrl = "https://discord.gg/PjD7WcChH3";
[UIComponent("changelog-popup")] private readonly ChangelogPopup _changelogPopup = null;
[UIObject("github-button")] private readonly GameObject _githubButton = null;
@@ -61,16 +64,48 @@ private bool OverrideSongSaber
}
}
+ private float SwingSoundVolume
+ {
+ get => _pluginConfig.SwingSoundVolume;
+ set
+ {
+ _pluginConfig.SwingSoundVolume = value;
+ if (_saberSound)
+ {
+ _saberSound.ConfigVolume = value;
+ }
+ OnPropertyChanged();
+ }
+ }
+
+ private bool EnableCustomBurnmarks
+ {
+ get => _pluginConfig.EnableCustomBurnmarks;
+ set
+ {
+ _pluginConfig.EnableCustomBurnmarks = value;
+ OnPropertyChanged();
+ }
+ }
+
[Inject] private readonly PluginConfig _pluginConfig = null;
[Inject] private readonly PluginManager _pluginManager = null;
+ [Inject] private readonly EditorInstanceManager _editorInstanceManager = null;
public ENavigationCategory Category => ENavigationCategory.Settings;
+ private SFSaberSound _saberSound;
+
public override void DidClose()
{
_changelogPopup.Hide();
}
+ public override void DidOpen()
+ {
+ _editorInstanceManager.CurrentSaber.GetSaberComponent(out _saberSound);
+ }
+
[UIAction("#post-parse")]
private async void Setup()
{
@@ -84,13 +119,13 @@ private async void Setup()
[UIAction("profile-clicked")]
private void ProfileClicked()
{
- Process.Start(PROFILE_URL);
+ Process.Start(ProfileUrl);
}
[UIAction("discord-clicked")]
private void DiscordClicked()
{
- Process.Start(DISCORD_URL);
+ Process.Start(DiscordUrl);
}
[UIAction("github-clicked")]
diff --git a/SaberFactory/UI/Lib/PropCell.cs b/SaberFactory/UI/Lib/PropCell.cs
index c6f7613..079541a 100644
--- a/SaberFactory/UI/Lib/PropCell.cs
+++ b/SaberFactory/UI/Lib/PropCell.cs
@@ -14,7 +14,6 @@ public class PropCell : TableCell
public void SetData(PropertyDescriptor data)
{
- Console.WriteLine($"Setup Data {data.Type}");
switch (data.Type)
{
case EPropertyType.Float:
diff --git a/SaberFactory/UI/PatreonView.bsml b/SaberFactory/UI/PatreonView.bsml
index eb49547..33ab3f2 100644
--- a/SaberFactory/UI/PatreonView.bsml
+++ b/SaberFactory/UI/PatreonView.bsml
@@ -2,11 +2,14 @@
xsi:noNamespaceSchemaLocation='file:///C:/CustomBSMLSchema.xsd' pref-height="{template;NavHeight}" bg="round-rect-panel"
custom-color="$default-panel" vertical-fit="PreferredSize" pref-width="70" pad="5">
-
+
+
+
+
\ No newline at end of file
diff --git a/SaberFactory/manifest.json b/SaberFactory/manifest.json
index ac3db7c..82706ec 100644
--- a/SaberFactory/manifest.json
+++ b/SaberFactory/manifest.json
@@ -3,7 +3,7 @@
"id": "SaberFactory",
"name": "Saber Factory",
"author": "Toni Macaroni",
- "version": "2.4.2",
+ "version": "2.5.0",
"description": "A highly customizable saber mod",
"gameVersion": "1.19.0",
"dependsOn": {
diff --git a/changelog.md b/changelog.md
index a6fe1ce..53651b6 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,9 @@
*(for Beat Saber 1.19)*
-- Fixed choosing trails on trailless sabers
-- Automatically apply and close "choose trail" popup on exit
+- Ability to export only one saber if both of your sabers are identical
+- Added custom saber swing sounds
+- Added custom saber burnmarks
+- New pedestal
+- Made majority of the sf internals public to make it easier for mods to interact with sf
*Needs `BeatSaberMarkupLanguage` and `SiraUtil` (available on ModAssistant)*
\ No newline at end of file