From 668c1cb1cd084a61a4c42cc9e853de79a0e30c59 Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sun, 1 Dec 2024 15:10:16 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20FPSCameraAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FPSCamera.API/Detector.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/FPSCamera.API/Detector.cs b/FPSCamera.API/Detector.cs index 6390499..11e8c06 100644 --- a/FPSCamera.API/Detector.cs +++ b/FPSCamera.API/Detector.cs @@ -7,12 +7,20 @@ namespace FPSCameraAPI { public class Detector { - public static void CheckFPSCamera() + public static bool CheckFPSCamera() { - if (AccessTools.TypeByName("FPSCamera.Utils.ModSupport, FPSCamera") == null) + if (AssemblyUtils.GetEnabledAssembly("FPSCamera") == null || + AccessTools.TypeByName("FPSCamera.Utils.ModSupport, FPSCamera") == null) + { + Logging.Error("FPSCamera not detected"); + return false; + } + return true; + } + public static void ShowNotificationWhenFPSCameraIsNotDetected() + { + if (!CheckFPSCamera()) { - Logging.Error("FPScamera not detected"); - var notification = NotificationBase.ShowNotification(); notification.AddParas(Translations.Translate("FPSCAMERA_NOT_DETECTED")); } From 5bb17c09e5a3b137127f59d1b2638ffcc700d31e Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sat, 7 Dec 2024 10:44:31 +0800 Subject: [PATCH 2/7] v3.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加设置导入功能 - 令信息面板在保存偏移设置时显示提示 - 优化异常显示 - 修复了偏移保存时误将设置中偏移一同保存的问题 - 更新翻译 --- .../Code/Cam/Controller/FPSCamController.cs | 41 ++- .../Code/Settings/Tabs/GeneralOptions.cs | 36 +++ FPSCamera/Code/Settings/v2/v2ModSettings.cs | 291 ++++++++++++++++++ .../Code/Settings/v2/v2OffsetsSettings.cs | 101 ++++++ FPSCamera/Code/UI/CamInfoPanel.cs | 54 +++- FPSCamera/Code/UI/FollowButtons.cs | 12 +- FPSCamera/Code/UI/MainPanel.cs | 4 +- FPSCamera/FPSCamera.csproj | 4 +- FPSCamera/Properties/AssemblyInfo.cs | 2 +- FPSCamera/Translations/en-EN.csv | 5 + FPSCamera/Translations/zh-CN.csv | 9 +- 11 files changed, 516 insertions(+), 43 deletions(-) create mode 100644 FPSCamera/Code/Settings/v2/v2ModSettings.cs create mode 100644 FPSCamera/Code/Settings/v2/v2OffsetsSettings.cs diff --git a/FPSCamera/Code/Cam/Controller/FPSCamController.cs b/FPSCamera/Code/Cam/Controller/FPSCamController.cs index 374734c..f4480ac 100644 --- a/FPSCamera/Code/Cam/Controller/FPSCamController.cs +++ b/FPSCamera/Code/Cam/Controller/FPSCamController.cs @@ -1,4 +1,6 @@ using AlgernonCommons; +using AlgernonCommons.Notifications; +using AlgernonCommons.Translation; using ColossalFramework; using FPSCamera.Game; using FPSCamera.Settings; @@ -177,8 +179,13 @@ private void Update() } catch (Exception e) { - Logging.Error("FPS Camera is about to exit due to some issues (Update)"); - Logging.LogException(e); + var notification = NotificationBase.ShowNotification(); + notification.AddParas(Translations.Translate("ERROR")); + notification.AddSpacer(); + notification.AddParas(e.ToString()); + + Logging.Error(); + Logging.LogException(e, "FPS Camera is about to exit due to some issues (Update)"); DisableCam(); } } @@ -210,6 +217,10 @@ private void LateUpdate() Logging.Error("FPS Camera is about to exit due to some issues (LateUpdate)"); DisableCam(); } + var notification = NotificationBase.ShowNotification(); + notification.AddParas(Translations.Translate("ERROR")); + notification.AddSpacer(); + notification.AddParas(e.ToString()); Logging.LogException(e); } } @@ -351,7 +362,8 @@ internal void SaveCamOffset(IFollowCam followCam) { OffsetsSettings.Offsets[name] = _offset; OffsetsSettings.Save(); - Logging.Message($"Offset saved for \"{name}\""); + CamInfoPanel.Instance.SetFooterMessage(string.Format(Translations.Translate("INFO_OFFSETSAVED"), name)); + Logging.Message($"Saved offset and rotation for \"{name}\""); } } /// @@ -363,24 +375,24 @@ internal void SyncCamOffset(IFollowCam followCam) OffsetsSettings.Load(); var name = followCam?.GetPrefabName(); - var newOffset = new Positioning(Vector3.zero); + _offset = default; + _offsetFromSetting = default; if (name != null && OffsetsSettings.Offsets.TryGetValue(name, out var offset)) { - newOffset = offset; + _offset = offset; } - newOffset.pos += ModSettings.FollowCamOffset; + _offsetFromSetting += ModSettings.FollowCamOffset; if (followCam is CitizenCam) - newOffset.pos += ModSettings.PedestrianFixedOffset; + _offsetFromSetting += ModSettings.PedestrianFixedOffset; else if (followCam is VehicleCam cam) { if (cam.GetVehicle().m_leadingVehicle != default && cam.GetPrefabName() != VehicleCam.GetVehicle(cam.GetFrontVehicleID()).Info.name) - newOffset.pos += ModSettings.MidVehFixedOffset; + _offsetFromSetting += ModSettings.MidVehFixedOffset; else - newOffset.pos += ModSettings.VehicleFixedOffset; + _offsetFromSetting += ModSettings.VehicleFixedOffset; } - _offset = newOffset; } /// @@ -389,7 +401,7 @@ internal void SyncCamOffset(IFollowCam followCam) private void UpdateFollowCamPos() { // Calculate the desired position and rotation of the camera by applying the offset to the FPSCam's current position and rotation. - var instancePos = FPSCam.GetPositioning().pos + (FPSCam.GetPositioning().rotation * _offset.pos); + var instancePos = FPSCam.GetPositioning().pos + (FPSCam.GetPositioning().rotation * (_offset.pos + _offsetFromSetting)); var instanceRotation = FPSCam.GetPositioning().rotation * _offset.rotation; // Limit the camera's position to the allowed area. @@ -489,7 +501,7 @@ private void UpdateTransitionPos() { _transitionTimer = 0f; AfterTransition(_endPos); - _endPos = new Positioning(Vector3.zero); + _endPos = default; return; } // Apply the transition position and rotation to the camera. @@ -507,8 +519,9 @@ public enum CamStatus } private static Transform CameraTransform => GameCamController.Instance.MainCamera.transform; private bool _isScrollTransitioning = false; - private Positioning _endPos = new Positioning(Vector3.zero); - private Positioning _offset = new Positioning(Vector3.zero); + private Positioning _endPos = default; + private Positioning _offset = default; + private Vector3 _offsetFromSetting = default; private float _targetFoV = ModSettings.CamFieldOfView; private float _transitionTimer = 0f; diff --git a/FPSCamera/Code/Settings/Tabs/GeneralOptions.cs b/FPSCamera/Code/Settings/Tabs/GeneralOptions.cs index 61a5dd2..753c16c 100644 --- a/FPSCamera/Code/Settings/Tabs/GeneralOptions.cs +++ b/FPSCamera/Code/Settings/Tabs/GeneralOptions.cs @@ -1,8 +1,11 @@ using AlgernonCommons; +using AlgernonCommons.Notifications; using AlgernonCommons.Translation; using AlgernonCommons.UI; using ColossalFramework.UI; +using FPSCamera.Settings.v2; using FPSCamera.UI; +using System; using UnityEngine; namespace FPSCamera.Settings.Tabs @@ -111,6 +114,38 @@ internal GeneralOptions(UITabstrip tabStrip, int tabIndex) // Reset to defaults. defaults_Button = UIButtons.AddButton(panel, LeftMargin, currentY, Translations.Translate("SETTINGS_RESETBTN"), 200f, 40f); defaults_Button.eventClicked += (c, _) => Reset(); + + var importButton = UIButtons.AddButton(panel, LeftMargin + 200f + LeftMargin, currentY, Translations.Translate("SETTINGS_IMPORT"), 200f, 40f); + importButton.eventClicked += (c, _) => + { + var notification = NotificationBase.ShowNotification(); + notification.AddParas(Translations.Translate("SETTINGS_IMPORTCONFIRM")); + notification.YesButton.eventClicked += (y, m) => + { + try + { + v2ModSettings.Load(); + ModSettings.Save(); + OptionsPanelManager.LocaleChanged(); + MainPanel.Instance?.LocaleChanged(); + + OffsetsSettings.Load(); + v2OffsetsSettings.Load(); + OffsetsSettings.Save(); + + var successedNotification = NotificationBase.ShowNotification(); + successedNotification.AddParas(Translations.Translate("SETTINGS_IMPORTSUCCESSED")); + } + catch (Exception e) + { + var failedNotification = NotificationBase.ShowNotification(); + failedNotification.AddParas(Translations.Translate("ERROR")); + failedNotification.AddSpacer(); + failedNotification.AddParas(e.ToString()); + Logging.LogException(e, "Failed to import FPSCamera v2 settings"); + } + }; + }; } /// /// for default button in . @@ -121,6 +156,7 @@ internal void Reset() ModSettings.ResetToDefaults(); ModSettings.Save(); OptionsPanelManager.LocaleChanged(); + MainPanel.Instance?.LocaleChanged(); } } } diff --git a/FPSCamera/Code/Settings/v2/v2ModSettings.cs b/FPSCamera/Code/Settings/v2/v2ModSettings.cs new file mode 100644 index 0000000..ab4c27e --- /dev/null +++ b/FPSCamera/Code/Settings/v2/v2ModSettings.cs @@ -0,0 +1,291 @@ +using AlgernonCommons.XML; +using ColossalFramework.IO; +using System; +using System.IO; +using System.Xml.Serialization; +using UnityEngine; + +namespace FPSCamera.Settings.v2 +{ + [XmlRoot("Config")] + public class v2ModSettings : SettingsXMLBase + { + [XmlIgnore] + internal static readonly string SettingsFileName = Path.Combine(DataLocation.executableDirectory, "FPSCameraConfig.xml"); + + internal static void Load() + { + using (var reader = new StreamReader(SettingsFileName)) + { + var xmlSerializer = new XmlSerializer(typeof(v2ModSettings)); + if (!(xmlSerializer.Deserialize(reader) is v2ModSettings xmlFile)) + { + throw new FileLoadException("couldn't deserialize XML file ", SettingsFileName); + } + } + } + // old config file use "True" and "False" which the xml Serializater could not read it, we need to convert it by ourselves + [XmlElement("HideGameUI")] + public string HideGameUI { get => ModSettings.HideGameUI.ToString(); set => ModSettings.HideGameUI = bool.Parse(value); } + + [XmlElement("SetBackCamera")] + public string SetBackCamera { get => ModSettings.SetBackCamera.ToString(); set => ModSettings.SetBackCamera = bool.Parse(value); } + + [XmlElement("UseMetricUnit")] + public string UseMetricUnit { get => ModSettings.UseMetricUnit.ToString(); set => ModSettings.UseMetricUnit = bool.Parse(value); } + + [XmlElement("ShowInfoPanel")] + public string ShowInfoPanel { get => ModSettings.ShowInfoPanel.ToString(); set => ModSettings.ShowInfoPanel = bool.Parse(value); } + + + [XmlElement("MaxPitchDeg")] + public float MaxPitchDeg { get => ModSettings.MaxPitchDeg; set => ModSettings.MaxPitchDeg = value; } + + [XmlElement("MovementSpeed")] + public float MovementSpeed { get => ModSettings.MovementSpeed; set => ModSettings.MovementSpeed = value; } + + [XmlElement("SpeedUpFactor")] + public float SpeedUpFactor { get => ModSettings.SpeedUpFactor; set => ModSettings.SpeedUpFactor = value; } + + [XmlElement("InvertRotateHorizontal")] + public string InvertRotateHorizontal + { get => ModSettings.InvertRotateHorizontal.ToString(); set => ModSettings.InvertRotateHorizontal = bool.Parse(value); } + + [XmlElement("InvertRotateVertical")] + public string InvertRotateVertical { get => ModSettings.InvertRotateVertical.ToString(); set => ModSettings.InvertRotateVertical = bool.Parse(value); } + + [XmlElement("RotateSensitivity")] + public float RotateSensitivity { get => ModSettings.RotateSensitivity; set => ModSettings.RotateSensitivity = value; } + + [XmlElement("RotateKeyFactor")] + public float RotateKeyFactor { get => ModSettings.RotateKeyFactor; set => ModSettings.RotateKeyFactor = value; } + + [XmlElement("EnableDof")] + public string EnableDof { get => ModSettings.Dof.ToString(); set => ModSettings.Dof = bool.Parse(value); } + + [XmlElement("CamFieldOfView")] + public float CamFieldOfView { get => ModSettings.CamFieldOfView; set => ModSettings.CamFieldOfView = value; } + + [XmlElement("ShowCursor4Free")] + public string ShowCursor4Free { get => ModSettings.ShowCursorFree.ToString(); set => ModSettings.ShowCursorFree = bool.Parse(value); } + + + [XmlElement("GroundClippingOption")] + public string GroundClippingOption + { + get => ModSettings.GroundClipping.ToString(); + set + { + int setValue; + switch (value) + {//v2.2.0 + case "None": setValue = 0; break; + case "AboveGround": setValue = 1; break; + case "SnapToGround": setValue = 2; break; + case "AboveRoad": setValue = 3; break; + case "SnapToRoad": setValue = 4; break; + default: // v2.4.1 + setValue = int.Parse(value); + break; + } + ModSettings.GroundClipping = setValue; + } + } + + [XmlElement("GroundLevelOffset")] + public float GroundLevelOffset { get => ModSettings.GroundLevelOffset; set => ModSettings.GroundLevelOffset = value; } + + [XmlElement("RoadLevelOffset")] + public float RoadLevelOffset { get => ModSettings.RoadLevelOffset; set => ModSettings.RoadLevelOffset = value; } + + [XmlElement("ShowCursor4Follow")] + public string ShowCursor4Follow { get => ModSettings.ShowCursorFollow.ToString(); set => ModSettings.ShowCursorFollow = bool.Parse(value); } + + [XmlElement("StickToFrontVehicle")] + public string StickToFrontVehicle { get => ModSettings.StickToFrontVehicle.ToString(); set => ModSettings.StickToFrontVehicle = bool.Parse(value); } + + [XmlElement("InstantMoveMax")] + public float InstantMoveMax { get => ModSettings.MinTransDistance; set => ModSettings.MinTransDistance = value; } + + [XmlElement("FollowCamOffset")] + public string FollowCamOffset + { + get => $"{ModSettings.FollowCamOffset.z},{ModSettings.FollowCamOffset.y},{ModSettings.FollowCamOffset.x}"; + set + { + var split = value.Split(','); + ModSettings.FollowCamOffset = new Vector3( + float.Parse(split[2]), + float.Parse(split[1]), + float.Parse(split[0])); + } + } + + [XmlElement("Period4Walk")] + public float Period4Walk { get => ModSettings.PeriodWalk; set => ModSettings.PeriodWalk = value; } + + [XmlElement("ManualSwitch4Walk")] + public string ManualSwitch4Walk { get => ModSettings.ManualSwitchWalk.ToString(); set => ModSettings.ManualSwitchWalk = bool.Parse(value); } + + [XmlElement("SelectPedestrian")] + public string SelectPedestrian { get => ModSettings.SelectPedestrian.ToString(); set => ModSettings.SelectPedestrian = bool.Parse(value); } + + [XmlElement("SelectPassenger")] + public string SelectPassenger { get => ModSettings.SelectPassenger.ToString(); set => ModSettings.SelectPassenger = bool.Parse(value); } + + [XmlElement("SelectWaiting")] + public string SelectWaiting { get => ModSettings.SelectWaiting.ToString(); set => ModSettings.SelectWaiting = bool.Parse(value); } + + [XmlElement("SelectDriving")] + public string SelectDriving { get => ModSettings.SelectDriving.ToString(); set => ModSettings.SelectDriving = bool.Parse(value); } + + [XmlElement("SelectPublicTransit")] + public string SelectPublicTransit { get => ModSettings.SelectPublicTransit.ToString(); set => ModSettings.SelectPublicTransit = bool.Parse(value); } + + [XmlElement("SelectService")] + public string SelectService { get => ModSettings.SelectService.ToString(); set => ModSettings.SelectService = bool.Parse(value); } + + [XmlElement("SelectCargo")] + public string SelectCargo { get => ModSettings.SelectCargo.ToString(); set => ModSettings.SelectCargo = bool.Parse(value); } + + [XmlElement("KeyCamToggle")] + public string KeyCamToggle { get => ModSettings.KeyCamToggle.ToString(); set => ModSettings.KeyCamToggle.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeySpeedUp")] + public string KeySpeedUp { get => ModSettings.KeySpeedUp.ToString(); set => ModSettings.KeySpeedUp.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyCamReset")] + public string KeyCamReset { get => ModSettings.KeyCamReset.ToString(); set => ModSettings.KeyCamReset.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyCursorToggle")] + public string KeyCursorToggle { get => ModSettings.KeyCursorToggle.ToString(); set => ModSettings.KeyCursorToggle.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyAutoMove")] + public string KeyAutoMove { get => ModSettings.KeyAutoMove.ToString(); set => ModSettings.KeyAutoMove.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeySaveOffset")] + public string KeySaveOffset { get => ModSettings.KeySaveOffset.ToString(); set => ModSettings.KeySaveOffset.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyMoveForward")] + public string KeyMoveForward { get => ModSettings.KeyMoveForward.ToString(); set => ModSettings.KeyMoveForward.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyMoveBackward")] + public string KeyMoveBackward { get => ModSettings.KeyMoveBackward.ToString(); set => ModSettings.KeyMoveBackward.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyMoveLeft")] + public string KeyMoveLeft { get => ModSettings.KeyMoveLeft.ToString(); set => ModSettings.KeyMoveLeft.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyMoveRight")] + public string KeyMoveRight { get => ModSettings.KeyMoveRight.ToString(); set => ModSettings.KeyMoveRight.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyMoveUp")] + public string KeyMoveUp { get => ModSettings.KeyMoveUp.ToString(); set => ModSettings.KeyMoveUp.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyMoveDown")] + public string KeyMoveDown { get => ModSettings.KeyMoveDown.ToString(); set => ModSettings.KeyMoveDown.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyRotateLeft")] + public string KeyRotateLeft { get => ModSettings.KeyRotateLeft.ToString(); set => ModSettings.KeyRotateLeft.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyRotateRight")] + public string KeyRotateRight { get => ModSettings.KeyRotateRight.ToString(); set => ModSettings.KeyRotateRight.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyRotateUp")] + public string KeyRotateUp { get => ModSettings.KeyRotateUp.ToString(); set => ModSettings.KeyRotateUp.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + [XmlElement("KeyRotateDown")] + public string KeyRotateDown { get => ModSettings.KeyRotateDown.ToString(); set => ModSettings.KeyRotateDown.Key = (int)Enum.Parse(typeof(KeyCode), value); } + + + [XmlElement("KeyUUIToggle")] + public string KeyUUIToggle + { + get => ModSettings.KeyUUIToggle.ToString(); + set + { + var split = value.Split('+'); + ModSettings.KeyUUIToggle = new AlgernonCommons.Keybinding.Keybinding((KeyCode)Enum.Parse(typeof(KeyCode), split[1]), + split[0] == "Control", + split[0] == "Shift", + split[0] == "Alt"); + } + } + + [XmlElement("SmoothTransition")] + public string SmoothTransition { get => ModSettings.SmoothTransition.ToString(); set => ModSettings.SmoothTransition = bool.Parse(value); } + + [XmlElement("GiveUpTransDistance")] + public float GiveUpTransDistance { get => ModSettings.MaxTransDistance; set => ModSettings.MaxTransDistance = value; } + + [XmlElement("LODOptimization")] + public string LODOptimization { get => (ModSettings.LodOpt >= 1).ToString(); set => ModSettings.LodOpt = bool.Parse(value) ? 1 : 0; } + + [XmlElement("ShadowsOptimization")] + public string ShadowsOptimization { get => ModSettings.ShadowsOpt.ToString(); set => ModSettings.ShadowsOpt = bool.Parse(value); } + + [XmlElement("MainPanelBtnPos")] + public string MainPanelBtnPos + { + get => $"{ModSettings.MainButtonPos.x},{ModSettings.MainButtonPos.y}"; + set + { + var split = value.Split(','); + ModSettings.MainButtonPos = new Vector2( + float.Parse(split[0]), + float.Parse(split[1]) + ); + } + } + + [XmlElement("CamNearClipPlane")] + public float CamNearClipPlane { get => ModSettings.CamNearClipPlane; set => ModSettings.CamNearClipPlane = value; } + + [XmlElement("FoViewScrollfactor")] + public float FoViewScrollfactor { get => ModSettings.FoViewScrollfactor; set => ModSettings.FoViewScrollfactor = value; } + + [XmlElement("VehicleFixedOffset")] + public string VehicleFixedOffset + { + get => $"{ModSettings.VehicleFixedOffset.z},{ModSettings.VehicleFixedOffset.y},{ModSettings.VehicleFixedOffset.x}"; + set + { + var split = value.Split(','); + ModSettings.VehicleFixedOffset = new Vector3( + float.Parse(split[2]), + float.Parse(split[1]), + float.Parse(split[0]) + ); + } + } + + [XmlElement("MidVehFixedOffset")] + public string MidVehFixedOffset + { + get => $"{ModSettings.MidVehFixedOffset.z},{ModSettings.MidVehFixedOffset.y},{ModSettings.MidVehFixedOffset.x}"; + set + { + var split = value.Split(','); + ModSettings.MidVehFixedOffset = new Vector3( + float.Parse(split[2]), + float.Parse(split[1]), + float.Parse(split[0]) + ); + } + } + + [XmlElement("PedestrianFixedOffset")] + public string PedestrianFixedOffset + { + get => $"{ModSettings.PedestrianFixedOffset.z},{ModSettings.PedestrianFixedOffset.y},{ModSettings.PedestrianFixedOffset.x}"; + set + { + var split = value.Split(','); + ModSettings.PedestrianFixedOffset = new Vector3( + float.Parse(split[2]), + float.Parse(split[1]), + float.Parse(split[0]) + ); + } + } + } +} diff --git a/FPSCamera/Code/Settings/v2/v2OffsetsSettings.cs b/FPSCamera/Code/Settings/v2/v2OffsetsSettings.cs new file mode 100644 index 0000000..ef11a19 --- /dev/null +++ b/FPSCamera/Code/Settings/v2/v2OffsetsSettings.cs @@ -0,0 +1,101 @@ +using AlgernonCommons.XML; +using ColossalFramework.IO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using UnityEngine; +using static FPSCamera.Utils.MathUtils; + +namespace FPSCamera.Settings.v2 +{ + [XmlRoot("CamOffset")] + public class v2OffsetsSettings : SettingsXMLBase, IXmlSerializable + { + [XmlIgnore] + private static readonly string SettingsFileName = Path.Combine(DataLocation.executableDirectory, "FPSCameraOffset.xml"); + + internal static void Load() + { + offsets.Clear(); + using (var reader = new StreamReader(SettingsFileName)) + { + var xmlSerializer = new XmlSerializer(typeof(v2OffsetsSettings)); + if (!(xmlSerializer.Deserialize(reader) is v2OffsetsSettings xmlFile)) + { + throw new FileLoadException("couldn't deserialize XML file ", SettingsFileName); + } + foreach (var kvp in offsets) + { + OffsetsSettings.Offsets[kvp.Key] = kvp.Value; + } + } + } + private static Dictionary offsets { get; set; } = new Dictionary(); + + public XmlSchema GetSchema() => null; + + public void ReadXml(XmlReader reader) + { + reader.ReadToDescendant("_offsets"); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + string tag = reader.Name; + string value = reader.ReadElementContentAsString(); + + string convertedTag = TagToStr(tag); + + var splitValues = value.Split(','); + float x = float.Parse(splitValues[0]); + float y = float.Parse(splitValues[1]); + float z = float.Parse(splitValues[2]); + float eulerX = float.Parse(splitValues[3]); + float eulerY = float.Parse(splitValues[4]); + + offsets[convertedTag] = new Positioning(new Vector3(z, y, x), Quaternion.Euler(eulerY, eulerX, 0f)); + } + } + } + + private static string TagToStr(string tag) + { + string str = ""; + for (int i = 1; i < tag.Length; i++) + { + if (tag[i] == '_') + { + if (i + 1 < tag.Length && tag[i + 1] == '_') + { + str += '_'; + i++; + } + else if (i + 3 < tag.Length && byte.TryParse(tag.Substring(i + 1, 3), out var ch)) + { + str += (char)ch; + i += 3; + } + else + { + throw new Exception($"Config import: xml tag({tag}) is invalid"); + } + } + else if (char.IsLetterOrDigit(tag[i])) + { + str += tag[i]; + } + else + { + throw new Exception($"Config import: xml tag({tag}) contains invalid character '{tag[i]}'"); + } + } + return str; + } + + public void WriteXml(XmlWriter writer) { } + } +} diff --git a/FPSCamera/Code/UI/CamInfoPanel.cs b/FPSCamera/Code/UI/CamInfoPanel.cs index 2064e59..16bfc49 100644 --- a/FPSCamera/Code/UI/CamInfoPanel.cs +++ b/FPSCamera/Code/UI/CamInfoPanel.cs @@ -1,6 +1,7 @@ namespace FPSCamera.UI { using AlgernonCommons; + using AlgernonCommons.Notifications; using AlgernonCommons.Translation; using FPSCamera.Cam; using FPSCamera.Cam.Controller; @@ -16,7 +17,7 @@ public class CamInfoPanel : MonoBehaviour public void EnableCamInfoPanel() { _elapsedTime = 0f; - _lastBufferStrUpdateTime = -1f; + _lastBufferStrUpdateTime = _tempFooterElapsedTime = -1f; enabled = true; } @@ -29,7 +30,7 @@ public void DisableCamInfoPanel() private void Awake() { Instance = this; - _elapsedTime = 0f; _lastBufferStrUpdateTime = -1f; + _elapsedTime = 0f; _lastBufferStrUpdateTime = _tempFooterElapsedTime = -1f; _mid = _footer = ""; _leftInfos = _rightInfos = new Dictionary(); @@ -47,37 +48,64 @@ private void Update() { try { - if (Cam != null && Cam.IsValid()) + if (Cam?.IsValid() ?? false) { _elapsedTime += Time.deltaTime; if (_elapsedTime - _lastBufferStrUpdateTime > _bufferUpdateInterval) { - UpdateStatus(); UpdateTargetInfos(); UpdateSpeed(); + UpdateStatus(); + UpdateTargetInfos(); + UpdateSpeed(); - _footer = Translations.Translate("INFO_TIME"); - if (Cam is WalkThruCam walkThruCam) + if (_tempFooterElapsedTime > _elapsedTime) { - var time = walkThruCam.GetElapsedTime(); - _footer += $"{(uint)time / 60:00}:{(uint)time % 60:00} / "; + _footer = _tempFooter; + } + else + { + _footer = Translations.Translate("INFO_TIME"); + if (Cam is WalkThruCam walkThruCam) + { + var time = walkThruCam.GetElapsedTime(); + _footer += $"{(uint)time / 60:00}:{(uint)time % 60:00} / "; + } + + _footer += $"{(uint)_elapsedTime / 60:00}:{(uint)_elapsedTime % 60:00}"; } - _footer += $"{(uint)_elapsedTime / 60:00}:{(uint)_elapsedTime % 60:00}"; _lastBufferStrUpdateTime = _elapsedTime; } } else { - _leftInfos.Clear(); _rightInfos.Clear(); - _footer = ""; _mid = Translations.Translate("INVALID"); + _leftInfos.Clear(); + _rightInfos.Clear(); + _footer = ""; + _mid = Translations.Translate("INVALID"); } } catch (System.Exception e) { + var notification = NotificationBase.ShowNotification(); + notification.AddParas(Translations.Translate("ERROR")); + notification.AddSpacer(); + notification.AddParas(e.ToString()); + Logging.Error("CamInfoPanel is disabled due to some issues"); Logging.LogException(e); enabled = false; } } + /// + /// Display a temporary message at the info panel's footer. + /// + /// Message to display. + /// Display time. + public void SetFooterMessage(string message, float duration = 3f) + { + _tempFooter = message; + _tempFooterElapsedTime = _elapsedTime + duration; + } private void UpdateStatus() { @@ -196,9 +224,11 @@ private void DrawListInRows(IEnumerable strings, private const float _fieldWidthRatio = .16f; private const float _fieldFontSizeRatio = .8f; - private float _elapsedTime, _lastBufferStrUpdateTime; + private string _tempFooter; + private float _tempFooterElapsedTime; + private string _mid, _footer; private Dictionary _leftInfos, _rightInfos; private Texture2D _panelTexture, _infoFieldTexture; diff --git a/FPSCamera/Code/UI/FollowButtons.cs b/FPSCamera/Code/UI/FollowButtons.cs index aa68c04..736d17c 100644 --- a/FPSCamera/Code/UI/FollowButtons.cs +++ b/FPSCamera/Code/UI/FollowButtons.cs @@ -1,7 +1,6 @@ using AlgernonCommons.Translation; using ColossalFramework.UI; using FPSCamera.Cam.Controller; -using FPSCamera.Utils; using System; using UnityEngine; @@ -82,7 +81,7 @@ private UIButton CreateCameraButton(T panel) where T : WorldInfoPanel button.pressedTextColor = new Color32(30, 30, 44, 255); button.eventClick += (_, p) => { - FPSCamController.Instance.StartFollowing(GetPanelInstanceID(panel)); + FPSCamController.Instance.StartFollowing(WorldInfoPanel.GetCurrentInstanceID()); panel.component.isVisible = false; }; button.AlignTo(panel.component, UIAlignAnchor.BottomRight); @@ -101,17 +100,10 @@ private void UpdateButtonVisibility(T panel, UIButton button, Func - /// Get the given panel's . - /// - /// The type of the panel. - /// Given panel. - /// The of the given panel. - private InstanceID GetPanelInstanceID(T panel) where T : WorldInfoPanel => AccessUtils.GetFieldValue(panel, "m_InstanceID"); private CitizenVehicleWorldInfoPanel citizenVehicleInfo_Panel; private UIButton citizenVehicleInfo_Button; diff --git a/FPSCamera/Code/UI/MainPanel.cs b/FPSCamera/Code/UI/MainPanel.cs index dafb5e8..b18ca5f 100644 --- a/FPSCamera/Code/UI/MainPanel.cs +++ b/FPSCamera/Code/UI/MainPanel.cs @@ -160,11 +160,11 @@ private void AddSettings() currentY += manualSwitchWalk_CheckBox.height + Margin; var walkThruBtn = UIButtons.AddButton(Panel, (Panel.width - 200f) / 2f, currentY, Translations.Translate("WALKTHRUBTN_TEXT"), 200f, 40f); - + walkThruBtn.playAudioEvents = true; walkThruBtn.eventClick += (_, m) => { FPSCamController.Instance.StartWalkThruCam(); - Panel.isVisible = false; + OnEsc(); }; Panel.height = currentY + walkThruBtn.height + Margin; } diff --git a/FPSCamera/FPSCamera.csproj b/FPSCamera/FPSCamera.csproj index 71f93bb..e044d81 100644 --- a/FPSCamera/FPSCamera.csproj +++ b/FPSCamera/FPSCamera.csproj @@ -98,10 +98,10 @@ PreserveNewest - PreserveNewest + Always - PreserveNewest + Always diff --git a/FPSCamera/Properties/AssemblyInfo.cs b/FPSCamera/Properties/AssemblyInfo.cs index 86506e8..a886f14 100644 --- a/FPSCamera/Properties/AssemblyInfo.cs +++ b/FPSCamera/Properties/AssemblyInfo.cs @@ -31,4 +31,4 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.9")] +[assembly: AssemblyVersion("3.1.0")] diff --git a/FPSCamera/Translations/en-EN.csv b/FPSCamera/Translations/en-EN.csv index 4abb5d1..c23afd7 100644 --- a/FPSCamera/Translations/en-EN.csv +++ b/FPSCamera/Translations/en-EN.csv @@ -23,6 +23,7 @@ "WHATSNEW_L1","This message is just to let you know that the mod has been updated.","" "WHATSNEW_L2","For a detailed list of changes, please visit the Steam Workshop or GitHub.","" "WHATSNEW_L3","Thank you for your use and support!","" +ERROR,Oops! Something went wrong: "MODDESCRIPTION","View your city from a different perspective","Mod's Description" "SETTINGS_GROUPNAME_GENERAL","General Options","" "SETTINGS_GROUPNAME_CAM","Camera Options","" @@ -34,6 +35,9 @@ "SETTINGS_GROUPNAME_SMOOTHTRANS","Smooth Transition Options","" "SETTINGS_GROUPNAME_OPT","Optimization Options","" "SETTINGS_RESETBTN","Reset Settings","" +SETTINGS_IMPORT,Import v2 settings +"SETTINGS_IMPORTCONFIRM","Do you confirm to import settings from First Person Camera v2 (including mod settings and offset settings)? Will overwrite existing mod settings, and merge imported offset settings with the existing." +SETTINGS_IMPORTSUCCESSED,Your settings has been successfully imported. "SETTINGS_HIDEUI","Hide Game's UI","" "SETTINGS_SETBACKCAMERA","Set camera back after exiting","" "SETTINGS_SETBACKCAMERA_DETAIL","When exiting FPS Camera, set the camera position back to where it's left beforehand","" @@ -170,6 +174,7 @@ "INFO_TIME","Time: ","" "INFO_NAME","Name","" "INFO_STATUS","Status","" +INFO_OFFSETSAVED,Saved offset and rotation for "{0}" "FOLLOWBTN_TOOLTIP","Start Follow Mode","" "WALKTHRUBTN_TEXT","Start Walk-Through","" "MAINPANELBTN_TOOLTIP","FPS Camera","That is the localized short name of this mod." \ No newline at end of file diff --git a/FPSCamera/Translations/zh-CN.csv b/FPSCamera/Translations/zh-CN.csv index b10df75..a2c43db 100644 --- a/FPSCamera/Translations/zh-CN.csv +++ b/FPSCamera/Translations/zh-CN.csv @@ -23,7 +23,8 @@ "WHATSNEW_L1","此消息只是为了让您知晓模组已经更新。","" "WHATSNEW_L2","请访问创意工坊或 GitHub 以获取详细更新日志。","" "WHATSNEW_L3","感谢您的使用及支持!","" -"MODDESCRIPTION","以不同的视角查看您的城市","Mod's Description" +ERROR,抱歉,似乎出现了一些问题: +"MODDESCRIPTION","以不同角度观察你的城市","Mod's Description" "SETTINGS_GROUPNAME_GENERAL","通用设置","" "SETTINGS_GROUPNAME_CAM","摄像机设置","" "SETTINGS_GROUPNAME_CAMCONTROL","摄像机控制","" @@ -33,7 +34,10 @@ "SETTINGS_GROUPNAME_KEYMAP","按键设置","" "SETTINGS_GROUPNAME_SMOOTHTRANS","平滑过渡设置","" "SETTINGS_GROUPNAME_OPT","优化设置","" -"SETTINGS_RESETBTN","重置配置","" +"SETTINGS_RESETBTN","重置模组设置","" +SETTINGS_IMPORT,导入v2设置 +SETTINGS_IMPORTCONFIRM,是否确认导入来自 First Person Camera v2 的设置(包括模组设置和偏移设置)?将覆盖现有的模组设置以及合并导入的偏移设置和现有偏移设置。 +SETTINGS_IMPORTSUCCESSED,设置导入成功。 "SETTINGS_HIDEUI","隐藏游戏UI","" "SETTINGS_SETBACKCAMERA","退出后重置摄像机位置","" "SETTINGS_SETBACKCAMERA_DETAIL","退出第一人称摄像机后,将摄像机位置重置回之前的位置","" @@ -170,6 +174,7 @@ "INFO_TIME","时间:","" "INFO_NAME","名称","" "INFO_STATUS","状态","" +INFO_OFFSETSAVED,已保存 “{0}” 的偏移与旋转 "FOLLOWBTN_TOOLTIP","进入跟随模式","" "WALKTHRUBTN_TEXT","进入漫游模式","" "MAINPANELBTN_TOOLTIP","第一人称摄像机","That is the localized short name of this mod." \ No newline at end of file From e0b10a39f41597c4d2f91b263b624863c05cbff0 Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sat, 14 Dec 2024 11:03:15 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20FPSCameraAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FPSCamera.API/Detector.cs | 29 --- FPSCamera.API/FPSCamera.API.csproj | 41 ++-- FPSCamera.API/FPSCamera.API.projitems | 14 -- FPSCamera.API/FPSCamera.API.shproj | 13 -- FPSCamera.API/Helper.cs | 62 ++++++ FPSCamera.API/L10n.cs | 70 +++++++ FPSCamera.API/Notification.cs | 233 +++++++++++++++++++++++ FPSCamera.API/Properties/AssemblyInfo.cs | 2 +- FPSCamera.API/packages.config | 5 - FPSCamera/FPSCamera.csproj | 4 +- FPSCamera/FPSCamera.sln | 7 +- 11 files changed, 396 insertions(+), 84 deletions(-) delete mode 100644 FPSCamera.API/Detector.cs delete mode 100644 FPSCamera.API/FPSCamera.API.projitems delete mode 100644 FPSCamera.API/FPSCamera.API.shproj create mode 100644 FPSCamera.API/Helper.cs create mode 100644 FPSCamera.API/L10n.cs create mode 100644 FPSCamera.API/Notification.cs delete mode 100644 FPSCamera.API/packages.config diff --git a/FPSCamera.API/Detector.cs b/FPSCamera.API/Detector.cs deleted file mode 100644 index 11e8c06..0000000 --- a/FPSCamera.API/Detector.cs +++ /dev/null @@ -1,29 +0,0 @@ -using AlgernonCommons; -using AlgernonCommons.Notifications; -using AlgernonCommons.Translation; -using HarmonyLib; - -namespace FPSCameraAPI -{ - public class Detector - { - public static bool CheckFPSCamera() - { - if (AssemblyUtils.GetEnabledAssembly("FPSCamera") == null || - AccessTools.TypeByName("FPSCamera.Utils.ModSupport, FPSCamera") == null) - { - Logging.Error("FPSCamera not detected"); - return false; - } - return true; - } - public static void ShowNotificationWhenFPSCameraIsNotDetected() - { - if (!CheckFPSCamera()) - { - var notification = NotificationBase.ShowNotification(); - notification.AddParas(Translations.Translate("FPSCAMERA_NOT_DETECTED")); - } - } - } -} \ No newline at end of file diff --git a/FPSCamera.API/FPSCamera.API.csproj b/FPSCamera.API/FPSCamera.API.csproj index af047e3..0f1e494 100644 --- a/FPSCamera.API/FPSCamera.API.csproj +++ b/FPSCamera.API/FPSCamera.API.csproj @@ -1,5 +1,6 @@  + Debug @@ -7,11 +8,14 @@ {92F27C26-188D-4CEB-9CA1-82872A545995} Library Properties - FPSCamera.API + FPSCameraAPI FPSCamera.API v3.5 512 true + latest + + true @@ -23,7 +27,7 @@ 4 - pdbonly + none true bin\Release\ TRACE @@ -31,11 +35,13 @@ 4 - - ..\FPSCamera\packages\CitiesHarmony.API.2.2.0\lib\net35\CitiesHarmony.API.dll + + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll + False - - ..\FPSCamera\packages\CitiesHarmony.Harmony.2.2.2\lib\net35\CitiesHarmony.Harmony.dll + + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll + False @@ -43,21 +49,20 @@ + + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll + False + + + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll + False + - - + + + - - - - - - {72c99e7c-c11b-4669-90ed-0944de5b9085} - FPSCamera - - - \ No newline at end of file diff --git a/FPSCamera.API/FPSCamera.API.projitems b/FPSCamera.API/FPSCamera.API.projitems deleted file mode 100644 index f283765..0000000 --- a/FPSCamera.API/FPSCamera.API.projitems +++ /dev/null @@ -1,14 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - dc080f92-7978-49cc-9e30-a4cf55909535 - - - FPSCamera.API - - - - - \ No newline at end of file diff --git a/FPSCamera.API/FPSCamera.API.shproj b/FPSCamera.API/FPSCamera.API.shproj deleted file mode 100644 index 563376f..0000000 --- a/FPSCamera.API/FPSCamera.API.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - dc080f92-7978-49cc-9e30-a4cf55909535 - 14.0 - - - - - - - - diff --git a/FPSCamera.API/Helper.cs b/FPSCamera.API/Helper.cs new file mode 100644 index 0000000..59ae248 --- /dev/null +++ b/FPSCamera.API/Helper.cs @@ -0,0 +1,62 @@ +using ColossalFramework.PlatformServices; +using ColossalFramework.Plugins; +using System; +using System.Reflection; +using static ColossalFramework.Plugins.PluginManager; + +namespace FPSCameraAPI +{ + /// + /// Based on boformer's CitiesHarmony.API.HarmonyHelper. Many thanks! + /// + public static class Helper + { + internal const ulong WorkshopId = 3198388677uL; + public static void CheckFPSCamera() + { + Notification.InstallNotification(); + } + + public static void GetFPSCameraStatus(out bool isInstalled, out bool isEnabled) + { + isInstalled = isEnabled = false; + if (Type.GetType("FPSCamera.Utils.ModSupport, FPSCamera") != null) isInstalled = true; + foreach (PluginInfo plugin in PluginManager.instance.GetPluginsInfo()) + { + if (plugin.isEnabled) + { + foreach (Assembly assembly in plugin.GetAssemblies()) + { + if (assembly.GetName().Name.Equals("FPSCamera") && assembly.GetType("FPSCamera.Utils.ModSupport") != null) + { + isEnabled = true; + } + } + } + } + } + public static bool IsFPSCameraInstalledAndEnabled + { + get + { + GetFPSCameraStatus(out var isInstalled, out var isEnabled); + return isInstalled && isEnabled; + } + } + public static bool IsWorkshopItemSubscribed + { + get + { + var subscribedIds = PlatformService.workshop.GetSubscribedItems(); + if (subscribedIds == null) return false; + + foreach (var id in subscribedIds) + { + if (id.AsUInt64 == WorkshopId) return true; + } + + return false; + } + } + } +} \ No newline at end of file diff --git a/FPSCamera.API/L10n.cs b/FPSCamera.API/L10n.cs new file mode 100644 index 0000000..01e3710 --- /dev/null +++ b/FPSCamera.API/L10n.cs @@ -0,0 +1,70 @@ +using ColossalFramework.Globalization; +using System.Collections.Generic; +namespace FPSCameraAPI +{ + internal static class L10n + { + private static bool IsZh => LocaleManager.exists && LocaleManager.instance.language == "zh"; + + private static readonly Dictionary EnTranslations = new() + { + ["MissingDependencyTitle"] = "Missing dependency: First Person Camera - Continued", + ["MissingDependencyMessage"] = "The dependency 'First Person Camera - Continued' is required for some mod(s) to work correctly.\n Do you want to subscribe to it right now?", + ["DependencyNotEnabledTitle"] = "Dependency not enabled: First Person Camera - Continued", + ["DependencyNotEnabledMessage"] = "The dependency 'First Person Camera - Continued' is not enabled.\n Do you want to enable it right now?", + ["SuccessSub"] = "First Person Camera - Continued has been installed successfully. It is recommended to restart the game now!", + ["ErrorSub"] = "An error occured while attempting to automatically subscribe to First Person Camera - Continued (no network connection?)", + ["ManualDownload"] = "You can manually download the First Person Camera - Continued mod from github.com/will258012/FPSCamera-Continued/releases", + ["ThenManualDownload"] = "then manually download the First Person Camera - Continued mod from github.com/will258012/FPSCamera-Continued/releases", + ["RejectSub"] = "You have rejected to automatically subscribe to First Person Camera - Continued :(", + ["RejectSubSln"] = "Either unsubscribe those mods or subscribe to the First Person Camera - Continued mod, then restart the game!", + ["SuccessEnabled"] = "First Person Camera - Continued has been enabled successfully.", + ["ErrorEnable"] = "An error occured while attempting to enable First Person Camera - Continued", + ["ManualEnable"] = "You could manually enable it in Content Manager", + ["RejectEnable"] = "You have rejected to enable First Person Camera - Continued :(", + ["RejectEnableSln"] = "Either unsubscribe those mods or enable the First Person Camera - Continued mod", + ["ShowError"] = "The mod(s):\n{0}require the dependency 'First Person Camera - Continued' to work correctly!\n\n{1}\n\nClose the game, {2}", + ["NotOnSteam"] = "First Person Camera - Continued could not be installed automatically because you are using a platform other than Steam.", + ["NoWorkShop"] = "First Person Camera - Continued could not be auto-subscribed because you are playing in --noWorkshop mode!", + ["NoWorkShopSln"] = "then restart without --noWorkshop \n or manually download and install the First Person Camera - Continued mod from github.com/will258012/FPSCamera-Continued/releases", + ["WorkShopNotAvailable"] = "First Person Camera - Continued could not be installed automatically because the Steam workshop is not available (no network connection?)", + ["AssemblyNotLoad"] = "It seems that First Person Camera - Continued has already been subscribed, \nbut Steam failed to download the files correctly or they were deleted,\nor the mod is not loaded in Skyve", + ["AssemblyNotLoadSln"] = "check your network connections \nOr (re)subscribe to the First Person Camera - Continued workshop item\nOr check the status in Skyve (if you have)", + }; + + private static readonly Dictionary ZhTranslations = new() + { + ["MissingDependencyTitle"] = "缺少前置:First Person Camera - Continued", + ["MissingDependencyMessage"] = "前置 First Person Camera - Continued 是某些模组正常运行所必需的。\n是否立即订阅?", + ["DependencyNotEnabledTitle"] = "前置未启用:First Person Camera - Continued", + ["DependencyNotEnabledMessage"] = "前置 First Person Camera - Continued 尚未启用。\n是否立即启用?", + ["SuccessSub"] = "已成功订阅!建议立即重启游戏", + ["ErrorSub"] = "尝试自动订阅 First Person Camera - Continued 时发生错误(无网络连接?)", + ["ManualDownload"] = "你可以手动从 github.com/will258012/FPSCamera-Continued/releases 下载该模组。", + ["ThenManualDownload"] = "随后手动下载 (github.com/will258012/FPSCamera-Continued/releases) \n并安装 First Person Camera - Continued 模组", + ["RejectSub"] = "已拒绝自动订阅 First Person Camera - Continued……", + ["RejectSubSln"] = "请退订以下模组或订阅 First Person Camera - Continued,并重启游戏", + ["SuccessEnabled"] = "已成功启用!", + ["ErrorEnable"] = "尝试启用 First Person Camera - Continued 时发生错误", + ["ManualEnable"] = "可在内容管理器中手动启用它", + ["RejectEnable"] = "已拒绝启用 First Person Camera - Continued……", + ["RejectEnableSln"] = "请退订以下模组或在内容管理器中启用 First Person Camera - Continued", + ["ShowError"] = "以下模组:\n{0}需要前置 First Person Camera - Continued 才能正常工作!\n{1}\n请关闭游戏,{2}", + ["NotOnSteam"] = "由于你使用的是 Steam 以外的平台,无法自动订阅 First Person Camera - Continued。", + ["NoWorkShop"] = "由于游戏在 --noWorkshop 模式下,无法自动订阅 First Person Camera - Continued。", + ["NoWorkShopSln"] = "请重启游戏并不带 --noWorkshop 参数,\n或者手动下载 (github.com/will258012/FPSCamera-Continued/releases) 并安装 First Person Camera - Continued。", + ["WorkShopNotAvailable"] = "由于创意工坊不可用,无法自动安装 First Person Camera - Continued (无网络连接?)", + ["AssemblyNotLoad"] = "似乎已经订阅了 First Person Camera - Continued,\n但 Steam 未能下载文件或文件被删除,\n或是模组未在 Skyve 中加载", + ["AssemblyNotLoadSln"] = "随后检查网络连接\n或者重新订阅 First Person Camera - Continued\n或者检查 Skyve 的状态(如有)", + }; + + internal static string Translate(string key) + { + if (IsZh && ZhTranslations.TryGetValue(key, out var value)) + return value; + else if (EnTranslations.TryGetValue(key, out var value2)) + return value2; + else return key; + } + } +} diff --git a/FPSCamera.API/Notification.cs b/FPSCamera.API/Notification.cs new file mode 100644 index 0000000..258339c --- /dev/null +++ b/FPSCamera.API/Notification.cs @@ -0,0 +1,233 @@ +using ColossalFramework.PlatformServices; +using ColossalFramework.Plugins; +using ColossalFramework.UI; +using ICities; +using System; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace FPSCameraAPI +{ + /// + /// Based on boformer's CitiesHarmony.API.SubscriptionPrompt. Many thanks! + /// + public static class Notification + { + private const string Marker = "FPSCameraAPINotification"; + + internal static void InstallNotification() + { + if (GameObject.Find(Marker)) return; + + var go = new GameObject(Marker); + UnityEngine.Object.DontDestroyOnLoad(go); + + if (LoadingManager.instance.m_currentlyLoading || UIView.library == null) + { + LoadingManager.instance.m_introLoaded += OnIntroLoaded; + LoadingManager.instance.m_levelLoaded += OnLevelLoaded; + } + else + { + ShowNotification(); + } + } + + private static void OnIntroLoaded() + { + LoadingManager.instance.m_introLoaded -= OnIntroLoaded; + LoadingManager.instance.m_levelLoaded -= OnLevelLoaded; + ShowNotification(); + } + + private static void OnLevelLoaded(SimulationManager.UpdateMode updateMode) + { + LoadingManager.instance.m_introLoaded -= OnIntroLoaded; + LoadingManager.instance.m_levelLoaded -= OnLevelLoaded; + ShowNotification(); + } + + private static void ShowNotification() + { + Helper.GetFPSCameraStatus(out var isInstalled, out var isEnabled); + if (!isInstalled) + ShowSubscriptionNotification(); + else if (!isEnabled) + ShowEnableNotification(); + } + + private static void ShowSubscriptionNotification() + { + if (!HasSubscriptionHelpMessages(out var reason, out var solution)) + { + ShowError(reason, solution); + return; + } + else + { + ConfirmPanel.ShowModal( + L10n.Translate("MissingDependencyTitle"), + L10n.Translate("MissingDependencyMessage"), + SubOnConfirm + ); + } + } + + private static void ShowEnableNotification() + { + ConfirmPanel.ShowModal( + L10n.Translate("DependencyNotEnabledTitle"), + L10n.Translate("DependencyNotEnabledMessage"), + EnableOnConfirm + ); + } + + private static void SubOnConfirm(UIComponent component, int result) + { + if (result == 1) + { + Debug.Log("Subscribing to FPSCamera workshop item!"); + + if (PlatformService.workshop.Subscribe(new PublishedFileId(Helper.WorkshopId))) + { + UIView.library.ShowModal("ExceptionPanel").SetMessage( + "Success!", + L10n.Translate("SuccessSub"), + false + ); + } + else + { + ShowError( + L10n.Translate("ErrorSub"), + L10n.Translate("ManualDownload") + ); + } + } + else + { + ShowError( + L10n.Translate("RejectSub"), + L10n.Translate("RejectSubSln") + ); + } + } + + private static void EnableOnConfirm(UIComponent component, int result) + { + if (result == 1) + { + Debug.Log("Enabling FPSCamera"); + foreach (var plugin in from PluginManager.PluginInfo plugin in PluginManager.instance.GetPluginsInfo() + where plugin.assembliesString.Contains("FPSCamera") && plugin.assembliesString.Contains("[3") && !plugin.isEnabled + select plugin) + { + plugin.isEnabled = true; + Debug.Log("Enabled FPSCamera successfully!"); + UIView.library.ShowModal("ExceptionPanel").SetMessage( + "Success!", + L10n.Translate("SuccessEnabled"), + false + ); + return; + } + ShowError( + L10n.Translate("ErrorEnable"), + L10n.Translate("ManualEnable") + ); + } + else + { + ShowError( + L10n.Translate("RejectEnable"), + L10n.Translate("RejectEnableSln") + ); + } + } + + private static void ShowError(string reason, string solution) + { + var affectedAssemblyNames = new StringBuilder(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in from assembly in assemblies + where IsRequiresFPSCamera(assembly) + select assembly) + { + affectedAssemblyNames.Append("• ").Append(GetModName(assembly)).Append('\n'); + } + + var message = string.Format(L10n.Translate("ShowError"), affectedAssemblyNames, reason, solution); + + UIView.library.ShowModal("ExceptionPanel").SetMessage( + L10n.Translate("MissingDependencyTitle"), + message, + false + ); + } + + private static bool HasSubscriptionHelpMessages(out string reason, out string solution) + { + reason = ""; + solution = ""; + + if (PlatformService.platformType != PlatformType.Steam) + { + Debug.LogError("Cannot auto-subscribe First Person Camera - Continued on platforms other than Steam!"); + reason = L10n.Translate("NotOnSteam"); + solution = L10n.Translate("ThenManualDownload"); + return false; + } + + if (PluginManager.noWorkshop) + { + Debug.LogError("Cannot auto-subscribe First Person Camera - Continued in --noWorkshop mode!"); + reason = L10n.Translate("NoWorkShop"); + solution = L10n.Translate("NoWorkShopSln"); + return false; + } + + if (!PlatformService.workshop.IsAvailable()) + { + Debug.LogError("Cannot auto-subscribe First Person Camera - Continued while workshop is not available"); + reason = L10n.Translate("WorkShopNotAvailable"); + solution = L10n.Translate("ThenManualDownload"); + return false; + } + + if (Helper.IsWorkshopItemSubscribed) + { + Debug.LogError("First Person Camera - Continued workshop item is subscribed, but assembly is not loaded or outdated!"); + reason = L10n.Translate("AssemblyNotLoad"); + solution = L10n.Translate("AssemblyNotLoadSln"); + return false; + } + + return true; + } + + private static bool IsRequiresFPSCamera(Assembly assembly) + { + if (assembly.GetName().Name == "FPSCamera") return false; + foreach (var _ in from assemblyName in assembly.GetReferencedAssemblies() + where (assemblyName.Name == "FPSCamera") && assemblyName.Version.Major >= 3 + select new { }) + { + return true; + } + + return false; + } + + private static string GetModName(Assembly assembly) + { + foreach (var plugin in PluginManager.instance.GetPluginsInfo()) + { + if (plugin.userModInstance is IUserMod mod && mod.GetType().Assembly == assembly) + return mod.Name; + } + return assembly.GetName().Name; + } + } +} diff --git a/FPSCamera.API/Properties/AssemblyInfo.cs b/FPSCamera.API/Properties/AssemblyInfo.cs index 14a0055..8f3a3e3 100644 --- a/FPSCamera.API/Properties/AssemblyInfo.cs +++ b/FPSCamera.API/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FPSCamera.API")] -[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyCopyright("Copyright © will258012 2024")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/FPSCamera.API/packages.config b/FPSCamera.API/packages.config deleted file mode 100644 index ca20533..0000000 --- a/FPSCamera.API/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/FPSCamera/FPSCamera.csproj b/FPSCamera/FPSCamera.csproj index e044d81..9d7f9e7 100644 --- a/FPSCamera/FPSCamera.csproj +++ b/FPSCamera/FPSCamera.csproj @@ -46,11 +46,11 @@ True - embedded + portable True - embedded + none diff --git a/FPSCamera/FPSCamera.sln b/FPSCamera/FPSCamera.sln index e941b15..a7a0038 100644 --- a/FPSCamera/FPSCamera.sln +++ b/FPSCamera/FPSCamera.sln @@ -6,7 +6,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FPSCamera", "FPSCamera.cspr EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "AlgernonCommonsPatchingShared", "..\AlgernonCommons\AlgernonCommonsPatchingShared.shproj", "{25AEF446-6F0D-43A8-BB84-D1306789B68C}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "FPSCamera.API", "..\FPSCamera.API\FPSCamera.API.shproj", "{DC080F92-7978-49CC-9E30-A4CF55909535}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FPSCamera.API", "..\FPSCamera.API\FPSCamera.API.csproj", "{92F27C26-188D-4CEB-9CA1-82872A545995}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -18,6 +18,10 @@ Global {72C99E7C-C11B-4669-90ED-0944DE5B9085}.Debug|Any CPU.Build.0 = Debug|Any CPU {72C99E7C-C11B-4669-90ED-0944DE5B9085}.Release|Any CPU.ActiveCfg = Release|Any CPU {72C99E7C-C11B-4669-90ED-0944DE5B9085}.Release|Any CPU.Build.0 = Release|Any CPU + {92F27C26-188D-4CEB-9CA1-82872A545995}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92F27C26-188D-4CEB-9CA1-82872A545995}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92F27C26-188D-4CEB-9CA1-82872A545995}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92F27C26-188D-4CEB-9CA1-82872A545995}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -28,6 +32,5 @@ Global GlobalSection(SharedMSBuildProjectFiles) = preSolution ..\AlgernonCommons\AlgernonCommonsPatchingShared.projitems*{25aef446-6f0d-43a8-bb84-d1306789b68c}*SharedItemsImports = 13 ..\AlgernonCommons\AlgernonCommonsPatchingShared.projitems*{72c99e7c-c11b-4669-90ed-0944de5b9085}*SharedItemsImports = 5 - ..\FPSCamera.API\FPSCamera.API.projitems*{dc080f92-7978-49cc-9e30-a4cf55909535}*SharedItemsImports = 13 EndGlobalSection EndGlobal From 00ab8c81b37f1462fd8cda71d3eac533169c42f1 Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:25:44 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E9=94=AE=E4=BD=8D=E6=97=B6=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FPSCamera/Code/Settings/v2/v2ModSettings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FPSCamera/Code/Settings/v2/v2ModSettings.cs b/FPSCamera/Code/Settings/v2/v2ModSettings.cs index ab4c27e..232669b 100644 --- a/FPSCamera/Code/Settings/v2/v2ModSettings.cs +++ b/FPSCamera/Code/Settings/v2/v2ModSettings.cs @@ -205,9 +205,9 @@ public string KeyUUIToggle { var split = value.Split('+'); ModSettings.KeyUUIToggle = new AlgernonCommons.Keybinding.Keybinding((KeyCode)Enum.Parse(typeof(KeyCode), split[1]), - split[0] == "Control", - split[0] == "Shift", - split[0] == "Alt"); + split[0].Contains("Control"), + split[0].Contains("Shift"), + split[0].Contains("Alt")); } } From cc67168fe402724b9a3c4f8e9ed148ccdfd22aba Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:25:55 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FPSCamera/Code/Settings/ModSettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FPSCamera/Code/Settings/ModSettings.cs b/FPSCamera/Code/Settings/ModSettings.cs index 9d63344..14e16cc 100644 --- a/FPSCamera/Code/Settings/ModSettings.cs +++ b/FPSCamera/Code/Settings/ModSettings.cs @@ -75,7 +75,7 @@ internal static void ResetToDefaults() StickToFrontVehicle = true; FollowCamOffset = Vector3.zero; VehicleFixedOffset = new Vector3(0f, 2f, 3f); - MidVehFixedOffset = new Vector3(0f, 3f, 2f); + MidVehFixedOffset = new Vector3(0f, 3f, -2f); PedestrianFixedOffset = new Vector3(0f, 2f, 0f); PeriodWalk = 20f; @@ -274,7 +274,7 @@ internal static void ResetToDefaults() [XmlElement("MidVehFixedOffset")] public Vector3 XMLMidVehFixedOffset { get => MidVehFixedOffset; set => MidVehFixedOffset = value; } [XmlIgnore] - internal static Vector3 MidVehFixedOffset = new Vector3(0f, 3f, 2f); + internal static Vector3 MidVehFixedOffset = new Vector3(0f, 3f, -2f); [XmlElement("PedestrianFixedOffset")] public Vector3 XMLPedestrianFixedOffset { get => PedestrianFixedOffset; set => PedestrianFixedOffset = value; } From e8eceb327a885dc4116d62a5251c3acf02187f5c Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:26:32 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FPSCamera/Code/Game/ShadowsManager.cs | 7 ++++--- FPSCamera/Code/Patches/LodPatches.cs | 27 +++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/FPSCamera/Code/Game/ShadowsManager.cs b/FPSCamera/Code/Game/ShadowsManager.cs index 5446832..524b65b 100644 --- a/FPSCamera/Code/Game/ShadowsManager.cs +++ b/FPSCamera/Code/Game/ShadowsManager.cs @@ -1,6 +1,7 @@ using AlgernonCommons; using System; using System.Collections; +using UnityEngine; namespace FPSCamera.Game { public class ShadowsManager @@ -12,12 +13,12 @@ public static IEnumerator ToggleShadowsOpt(bool status) Logging.Message("-- Setting shadows distance"); if (status) { - _cachedDist = UnityEngine.QualitySettings.shadowDistance; - UnityEngine.QualitySettings.shadowDistance = Opt; + _cachedDist = QualitySettings.shadowDistance; + QualitySettings.shadowDistance = Mathf.Min(Opt, _cachedDist); } else { - UnityEngine.QualitySettings.shadowDistance = _cachedDist; + QualitySettings.shadowDistance = _cachedDist; } } diff --git a/FPSCamera/Code/Patches/LodPatches.cs b/FPSCamera/Code/Patches/LodPatches.cs index 8b735b3..88779a5 100644 --- a/FPSCamera/Code/Patches/LodPatches.cs +++ b/FPSCamera/Code/Patches/LodPatches.cs @@ -22,8 +22,8 @@ private static void BuildingInfoBaseRefreshLOD(BuildingInfoBase __instance) { // If we're applying the saved LOD configuration: __instance.m_minLodDistance = ActiveConfig == Saved ? - // Apply the greater LOD distance. - Mathf.Max(__instance.m_minLodDistance, ActiveConfig.BuildingLodDistance) : + // Apply the saved LOD distance. + ActiveConfig.BuildingLodDistance : // Otherwise, apply the smaller LOD distance. Mathf.Min(__instance.m_minLodDistance, ActiveConfig.BuildingLodDistance); } @@ -38,9 +38,8 @@ private static void BuildingRefreshLOD(BuildingInfo __instance) if (__instance.m_lodMesh != null) { __instance.m_minLodDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_minLodDistance, ActiveConfig.BuildingLodDistance) : + ActiveConfig.BuildingLodDistance : Mathf.Min(__instance.m_minLodDistance, ActiveConfig.BuildingLodDistance); - } } @@ -53,7 +52,7 @@ private static void BuildingSubRefreshLOD(BuildingInfoSub __instance) if (__instance.m_lodMesh != null) { __instance.m_minLodDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_minLodDistance, ActiveConfig.BuildingLodDistance) : + ActiveConfig.BuildingLodDistance : Mathf.Min(__instance.m_minLodDistance, ActiveConfig.BuildingLodDistance); } @@ -68,7 +67,7 @@ private static void CitizenRefreshLOD(CitizenInfo __instance) if (__instance.m_lodMesh != null) { __instance.m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.CitizenLodDistance) : + ActiveConfig.CitizenLodDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.CitizenLodDistance); } } @@ -88,7 +87,7 @@ private static void NetRefreshLOD(NetInfo __instance) if (segments[i].m_lodMesh != null) { segments[i].m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(segments[i].m_lodRenderDistance, ActiveConfig.NetworkLodDistance) : + ActiveConfig.NetworkLodDistance : Mathf.Min(segments[i].m_lodRenderDistance, ActiveConfig.NetworkLodDistance); } } @@ -104,7 +103,7 @@ private static void NetRefreshLOD(NetInfo __instance) if (nodes[i].m_lodMesh != null) { nodes[i].m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(nodes[i].m_lodRenderDistance, ActiveConfig.NetworkLodDistance) : + ActiveConfig.NetworkLodDistance : Mathf.Min(nodes[i].m_lodRenderDistance, ActiveConfig.NetworkLodDistance); } } @@ -120,7 +119,7 @@ private static void PropRefreshLOD(PropInfo __instance) if (__instance.m_isDecal && __instance.m_material && __instance.m_material.shader.name.Equals("Custom/Props/Decal/Blend")) { var distence = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.DecalPropFadeDistance) : + ActiveConfig.DecalPropFadeDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.DecalPropFadeDistance); // Apply visibility. __instance.m_lodRenderDistance = distence; @@ -130,7 +129,7 @@ private static void PropRefreshLOD(PropInfo __instance) { // Non-decal prop. __instance.m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.PropLodDistance) : + ActiveConfig.PropLodDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.PropLodDistance); } } @@ -141,7 +140,7 @@ private static void TreeRefreshLOD(TreeInfo __instance) { if (ActiveConfig == null) return; __instance.m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.TreeLodDistance) : + ActiveConfig.TreeLodDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.TreeLodDistance); } @@ -151,7 +150,7 @@ private static void VehicleRefreshLOD(VehicleInfo __instance) { if (ActiveConfig == null) return; __instance.m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.VehicleLodDistance) : + ActiveConfig.VehicleLodDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.VehicleLodDistance); } @@ -161,7 +160,7 @@ private static void VehicleSubRefreshLOD(VehicleInfoBase __instance) { if (ActiveConfig == null) return; __instance.m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.VehicleLodDistance) : + ActiveConfig.VehicleLodDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.VehicleLodDistance); } @@ -171,7 +170,7 @@ private static void VehicleSubRefreshLOD(VehicleInfoSub __instance) { if (ActiveConfig == null) return; __instance.m_lodRenderDistance = ActiveConfig == Saved ? - Mathf.Max(__instance.m_lodRenderDistance, ActiveConfig.VehicleLodDistance) : + ActiveConfig.VehicleLodDistance : Mathf.Min(__instance.m_lodRenderDistance, ActiveConfig.VehicleLodDistance); } } From 9d860026217d380937bf461a1b6343e022604a94 Mon Sep 17 00:00:00 2001 From: Will <125041335+will258012@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:32:17 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E9=98=B2=E6=AD=A2Update()=E5=9C=A8?= =?UTF-8?q?=E7=A6=81=E7=94=A8=E6=91=84=E5=83=8F=E6=9C=BA=E6=97=B6=E8=A7=A6?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FPSCamera/Code/Cam/Controller/FPSCamController.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/FPSCamera/Code/Cam/Controller/FPSCamController.cs b/FPSCamera/Code/Cam/Controller/FPSCamController.cs index f4480ac..bc2d415 100644 --- a/FPSCamera/Code/Cam/Controller/FPSCamController.cs +++ b/FPSCamera/Code/Cam/Controller/FPSCamController.cs @@ -69,6 +69,7 @@ public void EnableCam(bool IsPlugin = false) private void DisableCam() { Logging.KeyMessage("Disabling FPS Camera"); + Status = CamStatus.Disabling; FPSCam?.DisableCam(); FPSCam = null; if (ModSettings.ShowInfoPanel) @@ -179,14 +180,17 @@ private void Update() } catch (Exception e) { + if (Status == CamStatus.Enabled || Status == CamStatus.PluginEnabled) + { + Logging.Error("FPS Camera is about to exit due to some issues (Update)"); + DisableCam(); + } + var notification = NotificationBase.ShowNotification(); notification.AddParas(Translations.Translate("ERROR")); notification.AddSpacer(); notification.AddParas(e.ToString()); - - Logging.Error(); - Logging.LogException(e, "FPS Camera is about to exit due to some issues (Update)"); - DisableCam(); + Logging.LogException(e); } } @@ -515,7 +519,8 @@ public enum CamStatus Disabled, Enabled, PluginEnabled, - Transitioning + Transitioning, + Disabling } private static Transform CameraTransform => GameCamController.Instance.MainCamera.transform; private bool _isScrollTransitioning = false;