diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e232cd65 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,55 @@ +{ + "files.exclude": + { + "**/.DS_Store":true, + "**/.git":true, + "**/.gitmodules":true, + "**/*.booproj":true, + "**/*.pidb":true, + "**/*.suo":true, + "**/*.user":true, + "**/*.userprefs":true, + "**/*.unityproj":true, + "**/*.dll":true, + "**/*.exe":true, + "**/*.pdf":true, + "**/*.mid":true, + "**/*.midi":true, + "**/*.wav":true, + "**/*.gif":true, + "**/*.ico":true, + "**/*.jpg":true, + "**/*.jpeg":true, + "**/*.png":true, + "**/*.psd":true, + "**/*.tga":true, + "**/*.tif":true, + "**/*.tiff":true, + "**/*.3ds":true, + "**/*.3DS":true, + "**/*.fbx":true, + "**/*.FBX":true, + "**/*.lxo":true, + "**/*.LXO":true, + "**/*.ma":true, + "**/*.MA":true, + "**/*.obj":true, + "**/*.OBJ":true, + "**/*.asset":true, + "**/*.cubemap":true, + "**/*.flare":true, + "**/*.mat":true, + "**/*.meta":true, + "**/*.prefab":true, + "**/*.unity":true, + "build/":true, + "Build/":true, + "Library/":true, + "library/":true, + "obj/":true, + "Obj/":true, + "ProjectSettings/":true, + "temp/":true, + "Temp/":true + } +} \ No newline at end of file diff --git a/Assets/Plugins/Sirenix/Demos/Sample - RPG Editor.unitypackage.meta b/Assets/ConjureOS.meta similarity index 54% rename from Assets/Plugins/Sirenix/Demos/Sample - RPG Editor.unitypackage.meta rename to Assets/ConjureOS.meta index 26bd5b8a..c5758ebb 100644 --- a/Assets/Plugins/Sirenix/Demos/Sample - RPG Editor.unitypackage.meta +++ b/Assets/ConjureOS.meta @@ -1,7 +1,8 @@ fileFormatVersion: 2 -guid: cc355dd4cf1e6173beaeb22c2858cbe1 -timeCreated: 1488828285 +guid: df1387ab23758dd4f9e36ec1aab17005 +folderAsset: yes DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/Plugins/Sirenix/Demos/Custom Attribute Processors.unitypackage.meta b/Assets/ConjureOS/Scripts.meta similarity index 54% rename from Assets/Plugins/Sirenix/Demos/Custom Attribute Processors.unitypackage.meta rename to Assets/ConjureOS/Scripts.meta index 92a6ac5a..9d035169 100644 --- a/Assets/Plugins/Sirenix/Demos/Custom Attribute Processors.unitypackage.meta +++ b/Assets/ConjureOS/Scripts.meta @@ -1,7 +1,8 @@ fileFormatVersion: 2 -guid: f597f19f656ba56eae4f6a3a7cc528f4 -timeCreated: 1488828285 +guid: d4c9b5af1f2acb5498e569269f0c75c4 +folderAsset: yes DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/ArcadeMenu.meta b/Assets/ConjureOS/Scripts/ArcadeMenu.meta new file mode 100644 index 00000000..fd6a8c05 --- /dev/null +++ b/Assets/ConjureOS/Scripts/ArcadeMenu.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 21d4daaf24a1497b942bb1c26aaad40b +timeCreated: 1697466850 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/ArcadeMenu/ConjureArcadeMenu.cs b/Assets/ConjureOS/Scripts/ArcadeMenu/ConjureArcadeMenu.cs new file mode 100644 index 00000000..924d9223 --- /dev/null +++ b/Assets/ConjureOS/Scripts/ArcadeMenu/ConjureArcadeMenu.cs @@ -0,0 +1,93 @@ +using System; +using UnityEngine; +using ConjureOS.Input; + +namespace ConjureOS.ArcadeMenu +{ + public class ConjureArcadeMenu : MonoBehaviour + { + public event Action OnOpen; + +#if !ENABLE_INPUT_SYSTEM && ENABLE_LEGACY_INPUT_MANAGER + [SerializeField] + private string homeButton = "Home"; +#endif + + public bool IsOpened { get; private set; } = false; + + private void Start() + { +#if !ENABLE_INPUT_SYSTEM && ENABLE_LEGACY_INPUT_MANAGER + if (!IsButtonAvailable(homeButton)) + { + Debug.LogWarning( + $"ConjureOS: {nameof(homeButton)} in {nameof(ConjureArcadeMenu)} must be a valid action name ('{homeButton}' is not set up). " + + "To modify actions, go to 'Edit > Project Settings > Input Manager'."); + } +#endif + } + +#if !ENABLE_INPUT_SYSTEM && ENABLE_LEGACY_INPUT_MANAGER + private bool IsButtonAvailable(string buttonName) + { + try + { + UnityEngine.Input.GetButton(buttonName); + return true; + } + catch (ArgumentException) + { + return false; + } + } + + private bool WasButtonPressedThisFrame(string buttonName) + { + try + { + return UnityEngine.Input.GetButtonDown(buttonName); + } + catch (ArgumentException) + { + return false; + } + } +#endif + + private void Update() + { +#if ENABLE_INPUT_SYSTEM + foreach (ConjureArcadeController arcadeController in ConjureArcadeController.allControllers) + { + if (arcadeController.home.wasPressedThisFrame) + { + OpenArcadeMenu(); + } + } +#elif ENABLE_LEGACY_INPUT_MANAGER + if (WasButtonPressedThisFrame(homeButton)) + { + OpenArcadeMenu(); + } +#endif + } + + private void OpenArcadeMenu() + { + if (IsOpened) + { + return; + } + IsOpened = true; + + // This will eventually open the arcade menu. + // However, for now, it will only close the game. + OnOpen?.Invoke(); + +#if UNITY_EDITOR + UnityEditor.EditorApplication.isPlaying = false; +#endif + Application.Quit(); + } + } +} \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/ArcadeMenu/ConjureArcadeMenu.cs.meta b/Assets/ConjureOS/Scripts/ArcadeMenu/ConjureArcadeMenu.cs.meta new file mode 100644 index 00000000..a347859c --- /dev/null +++ b/Assets/ConjureOS/Scripts/ArcadeMenu/ConjureArcadeMenu.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 42abcca807f2495aa5d59ff8d0570ed6 +timeCreated: 1697466858 \ No newline at end of file diff --git a/Assets/Plugins/Sirenix/Demos/Custom Drawers.unitypackage.meta b/Assets/ConjureOS/Scripts/CustomWindow.meta similarity index 54% rename from Assets/Plugins/Sirenix/Demos/Custom Drawers.unitypackage.meta rename to Assets/ConjureOS/Scripts/CustomWindow.meta index 71af8df2..9d5573c4 100644 --- a/Assets/Plugins/Sirenix/Demos/Custom Drawers.unitypackage.meta +++ b/Assets/ConjureOS/Scripts/CustomWindow.meta @@ -1,7 +1,8 @@ fileFormatVersion: 2 -guid: 48e08dc33330d11e9d4a1b246c52e4f6 -timeCreated: 1488828285 +guid: c2ef9ab0502fe5b4b981fc372678110e +folderAsset: yes DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeGUI.cs b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeGUI.cs new file mode 100644 index 00000000..38048e88 --- /dev/null +++ b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeGUI.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace ConjureOS.CustomWindow +{ + public class ConjureArcadeGUI + { + public struct Style + { + public const int UniformPadding = 10; + public const int TextSizeError = 10; + public readonly static Color32 ColorError = new Color(0.84f, 0.19f, 0.19f); + public readonly static Color32 ColorSuccess = new Color(0.19f, 0.84f, 0.35f); + + public static GUIStyle ErrorStyle = GenerateGUIStyle(ColorError); + public static GUIStyle SuccessStyle = GenerateGUIStyle(ColorSuccess); + + private static GUIStyle GenerateGUIStyle(Color32 color) + { + GUIStyle errorStyle = new GUIStyle(); + errorStyle.normal.textColor = color; + errorStyle.fontSize = TextSizeError; + errorStyle.wordWrap = true; + + return errorStyle; + } + } + + public struct Message + { + public const string MetadataFailedMessage = "{0} error{1} have been detected."; + public const string MetadataConfirmedMessage = "No errors detected. The game is ready to be published."; + } + } +} \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeGUI.cs.meta b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeGUI.cs.meta new file mode 100644 index 00000000..720c72c4 --- /dev/null +++ b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ccef78ea2487524fb2c803e16661a6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeMenuItem.cs b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeMenuItem.cs new file mode 100644 index 00000000..275fde03 --- /dev/null +++ b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeMenuItem.cs @@ -0,0 +1,25 @@ +#if UNITY_EDITOR +using ConjureOS.MetadataWindow; +using ConjureOS.UploaderWindow; +using UnityEditor; + +namespace ConjureOS.CustomWindow +{ + public class ConjureArcadeMenuItem + { + private const string MenuName = "Conjure Arcade/"; + + [MenuItem(MenuName + "Game Metadata Editor")] + private static void OpenGameMetadataWindow() + { + EditorWindow.GetWindow(typeof(ConjureArcadeMetadataWindow)); + } + + [MenuItem(MenuName + "Upload Game")] + private static void OpenUploadGameWindow() + { + EditorWindow.GetWindow(typeof(ConjureArcadeGameUploaderWindow)); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeMenuItem.cs.meta b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeMenuItem.cs.meta new file mode 100644 index 00000000..f2f97412 --- /dev/null +++ b/Assets/ConjureOS/Scripts/CustomWindow/ConjureArcadeMenuItem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35055e949c56f364fb3146744c04237c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/GlobalObject.meta b/Assets/ConjureOS/Scripts/GlobalObject.meta new file mode 100644 index 00000000..80d50694 --- /dev/null +++ b/Assets/ConjureOS/Scripts/GlobalObject.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6700d94db788419897417a8bed51208a +timeCreated: 1697466157 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/GlobalObject/ConjureGlobalObjectInitializer.cs b/Assets/ConjureOS/Scripts/GlobalObject/ConjureGlobalObjectInitializer.cs new file mode 100644 index 00000000..4f1f674b --- /dev/null +++ b/Assets/ConjureOS/Scripts/GlobalObject/ConjureGlobalObjectInitializer.cs @@ -0,0 +1,57 @@ +using ConjureOS.ArcadeMenu; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace ConjureOS.GlobalObject +{ +#if UNITY_EDITOR + [InitializeOnLoad] +#endif + public static class ConjureGlobalObjectInitializer + { + public const string GlobalObjectName = "ConjureGlobalObject"; + public static readonly System.Type[] GlobalObjectComponentTypes = + { + typeof(ConjureArcadeMenu) + }; + +#if UNITY_EDITOR + static ConjureGlobalObjectInitializer() + { + InitializeGlobalObject(); + } +#endif + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] + private static void InitializeGlobalObject() + { + GameObject globalObject = GameObject.Find(GlobalObjectName); + if (!globalObject) + { + globalObject = new GameObject(GlobalObjectName); + } + InitializeComponentsOnGlobalObject(globalObject); + } + + private static void InitializeComponentsOnGlobalObject(GameObject globalObject) + { + foreach (var globalObjectComponentType in GlobalObjectComponentTypes) + { + if (globalObject.GetComponent(globalObjectComponentType)) + { + continue; + } + + if (!globalObjectComponentType.IsSubclassOf(typeof(MonoBehaviour))) + { + Debug.LogError($"ConjureOS: Cannot add component '{nameof(globalObjectComponentType.FullName)}' to global object because it is not a component."); + continue; + } + + globalObject.AddComponent(globalObjectComponentType); + } + } + } +} \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/GlobalObject/ConjureGlobalObjectInitializer.cs.meta b/Assets/ConjureOS/Scripts/GlobalObject/ConjureGlobalObjectInitializer.cs.meta new file mode 100644 index 00000000..49cdfb95 --- /dev/null +++ b/Assets/ConjureOS/Scripts/GlobalObject/ConjureGlobalObjectInitializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 039be1ac3aad4e8ebe52affd281ad81c +timeCreated: 1697466243 \ No newline at end of file diff --git a/Assets/Plugins/Sirenix/Demos/Editor Windows.unitypackage.meta b/Assets/ConjureOS/Scripts/Input.meta similarity index 54% rename from Assets/Plugins/Sirenix/Demos/Editor Windows.unitypackage.meta rename to Assets/ConjureOS/Scripts/Input.meta index cc5570c5..7fd3aadf 100644 --- a/Assets/Plugins/Sirenix/Demos/Editor Windows.unitypackage.meta +++ b/Assets/ConjureOS/Scripts/Input.meta @@ -1,7 +1,8 @@ fileFormatVersion: 2 -guid: ed09910c0094cb27be8f3ca264680da3 -timeCreated: 1488828285 +guid: 86ca34d4ff4ff724c962255b02e88d47 +folderAsset: yes DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeController.cs b/Assets/ConjureOS/Scripts/Input/ConjureArcadeController.cs new file mode 100644 index 00000000..9595edf8 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeController.cs @@ -0,0 +1,135 @@ +#if ENABLE_INPUT_SYSTEM +using System; +using System.Collections.Generic; +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.Controls; +using UnityEngine.InputSystem.Layouts; + +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable ClassNeverInstantiated.Global +// Reason: It's normal that some stuff is not used here because this is meant to be used as a library. + +// ReSharper disable InconsistentNaming +// Reason: According to our code guidelines, property should be UpperCamelCase. +// However, to be consistent with other input devices in Unity (e.g. Joystick, Gamepad) we will use lowerCamelCase here. + +namespace ConjureOS.Input +{ + [InputControlLayout(stateType = typeof(ConjureArcadeControllerState), displayName = "Conjure Arcade Controller")] + public class ConjureArcadeController : InputDevice + { + public static event Action OnControllerAdded; + public static event Action OnControllerRemoved; + + public ConjureArcadeStickControl stick { get; protected set; } + + public ButtonControl home { get; protected set; } + public ButtonControl start { get; protected set; } + + public ButtonControl button1 { get; protected set; } + public ButtonControl button2 { get; protected set; } + public ButtonControl button3 { get; protected set; } + + public ButtonControl buttonA { get; protected set; } + public ButtonControl buttonB { get; protected set; } + public ButtonControl buttonC { get; protected set; } + + public static ConjureArcadeController current { get; private set; } + public static ConjureArcadeController[] allControllers => allInstances.ToArray(); + public static int ControllerCount => count; + + /// + /// The controller index of this specific Conjure Arcade Controller. + /// The value will be between 0 and - 1. + /// If the value is -1, it means this controller was not initialized correctly and is not valid. + /// + public int ControllerIndex + { + get + { + try + { + return allInstances.IndexOf(this); + } + catch (ArgumentOutOfRangeException) + { + return -1; + } + } + } + + /// + /// Whether or not a Conjure Arcade Controller exist for the following index. + /// + public static bool ExistForIndex(int controllerIndex) + { + return allInstances.Exists(instance => instance.ControllerIndex == controllerIndex); + } + + /// + /// Get the Conjure Arcade Controller associated with the specific controller index. + /// + /// The controller if it exist for the specific index or null if it does not exist. + public static ConjureArcadeController GetForIndex(int controllerIndex) + { + return allInstances.Find(instance => instance.ControllerIndex == controllerIndex); + } + + protected override void FinishSetup() + { + stick = GetChildControl("stick"); + + home = GetChildControl("home"); + start = GetChildControl("start"); + + button1 = GetChildControl("button1"); + button2 = GetChildControl("button2"); + button3 = GetChildControl("button3"); + + buttonA = GetChildControl("buttonA"); + buttonB = GetChildControl("buttonB"); + buttonC = GetChildControl("buttonC"); + + base.FinishSetup(); + } + + public override void MakeCurrent() + { + base.MakeCurrent(); + current = this; + } + + protected override void OnAdded() + { + base.OnAdded(); + + if (!allInstances.Contains(this)) + { + allInstances.Add(this); + ++count; + OnControllerAdded?.Invoke(this); + } + } + + protected override void OnRemoved() + { + if (current == this) + { + current = null; + } + + if (allInstances.Remove(this)) + { + --count; + OnControllerRemoved?.Invoke(this); + } + + base.OnRemoved(); + } + + private static int count; + private static readonly List allInstances = new(); + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeController.cs.meta b/Assets/ConjureOS/Scripts/Input/ConjureArcadeController.cs.meta new file mode 100644 index 00000000..8ac66fd1 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 84cdd6b6829c4f5e9e31a78f96d5b9b8 +timeCreated: 1695757344 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerInfo.cs b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerInfo.cs new file mode 100644 index 00000000..d55fc06f --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerInfo.cs @@ -0,0 +1,31 @@ +namespace ConjureOS.Input +{ + public static class ConjureArcadeControllerInfo + { + // The information in this class will need to change if we change the way the controller is made. + // Everything in this class needs to be static since it is used at compile time to setup the Conjure Arcade Controller state description. + + public const string Interface = "HID"; + public const string Product = "Generic USB Joystick "; // The extra spaces are normal as they are part of the product name created by the board's vendor + + public const int StateSizeInBytes = 8; + public const int ReportIdByte = 0; + public const int StickXByte = 1; + public const int StickYByte = 1; + public const int ButtonByte = 7; + + public enum ButtonBit : uint + { + Home = 0, + Start = 1, + + One = 2, + Two = 3, + Three = 4, + + A = 5, + B = 6, + C = 7, + } + } +} \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerInfo.cs.meta b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerInfo.cs.meta new file mode 100644 index 00000000..c175b69f --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e67d24a4d1184f43933bdd96b2720cbd +timeCreated: 1695758710 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerState.cs b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerState.cs new file mode 100644 index 00000000..ed9c8418 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerState.cs @@ -0,0 +1,53 @@ +#if ENABLE_INPUT_SYSTEM +using System.Runtime.InteropServices; +using UnityEngine.InputSystem.Layouts; +using UnityEngine.InputSystem.LowLevel; +using UnityEngine.InputSystem.Utilities; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable FieldCanBeMadeReadOnly.Global +// Reason: This is a configuration class with specific requirements for its interface. + +// ReSharper disable StringLiteralTypo +// ReSharper disable CommentTypo +// Reason: SHRT is not a typo in this case. + +// Inspired by: https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/HID.html +// This class describes the data received by the controller in a way that can be read by the new input system. +// If the physical controller ever changes, this class will need to be reworked. + +namespace ConjureOS.Input +{ + [StructLayout(LayoutKind.Explicit, Size = ConjureArcadeControllerInfo.StateSizeInBytes)] + public struct ConjureArcadeControllerState : IInputStateTypeInfo + { + public FourCC format => new FourCC('H', 'I', 'D'); + + [FieldOffset(ConjureArcadeControllerInfo.ReportIdByte)] + public byte reportId; + + [InputControl(name = "stick", layout = "ConjureArcadeStick", format = "VC2B", displayName = "Stick", processors = "ConjureArcadeVector2(minX=0.0, maxX=1.0, minY=0.0, maxY=1.0, invertY)")] + [InputControl(name = "stick/x", offset = 0, format = "BYTE", parameters = "clamp=false, invert=false, normalize=false")] + [InputControl(name = "stick/left", offset = 0, format = "BYTE")] + [InputControl(name = "stick/right", offset = 0, format = "BYTE")] + [InputControl(name = "stick/y", offset = 1, format = "BYTE", parameters = "clamp=false, invert=false, normalize=false")] + [InputControl(name = "stick/up", offset = 1, format = "BYTE")] + [InputControl(name = "stick/down", offset = 1, format = "BYTE")] + [FieldOffset(ConjureArcadeControllerInfo.StickXByte)] + public byte stickX; + [FieldOffset(ConjureArcadeControllerInfo.StickYByte)] + public byte stickY; + + [InputControl(name = "home", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.Home, displayName = "Home")] + [InputControl(name = "start", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.Start, displayName = "Start")] + [InputControl(name = "button1", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.One, displayName = "Button 1", shortDisplayName = "1")] + [InputControl(name = "button2", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.Two, displayName = "Button 2", shortDisplayName = "2")] + [InputControl(name = "button3", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.Three, displayName = "Button 3", shortDisplayName = "3")] + [InputControl(name = "buttonA", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.A, displayName = "Button A", shortDisplayName = "A")] + [InputControl(name = "buttonB", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.B, displayName = "Button B", shortDisplayName = "B")] + [InputControl(name = "buttonC", layout = "Button", bit = (uint) ConjureArcadeControllerInfo.ButtonBit.C, displayName = "Button C", shortDisplayName = "C")] + [FieldOffset(ConjureArcadeControllerInfo.ButtonByte)] + public byte buttons; + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerState.cs.meta b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerState.cs.meta new file mode 100644 index 00000000..aee2d569 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeControllerState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c07dbb7bcebd4245be59b93c86cee5fd +timeCreated: 1695758555 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickControl.cs b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickControl.cs new file mode 100644 index 00000000..add43233 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickControl.cs @@ -0,0 +1,46 @@ +#if ENABLE_INPUT_SYSTEM +using UnityEngine.InputSystem.Controls; +using UnityEngine.InputSystem.Layouts; + +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable MemberCanBePrivate.Global +// Reason: It's normal that some stuff is not used here because this is meant to be used as a library. + +// ReSharper disable InconsistentNaming +// Reason: According to our code guidelines, property should be UpperCamelCase. +// However, to be consistent with other input controls in Unity (e.g. StickControl) we will use lowerCamelCase here. + +// This class exists to allow the Conjure arcade stick input to work with the input system. +// It uses the ConjureArcadeValue processor in order to define the down/left/right/up buttons. +// It is registered in when ConjureInputSystem is initialized and is used for the stick input in the controller state. + +namespace ConjureOS.Input +{ + public class ConjureArcadeStickControl : Vector2Control + { + [InputControl(useStateFrom = "y", processors = "ConjureArcadeValue(min=0.0, max=1.0, invert)", synthetic = true, displayName = "Up")] + [InputControl(name = "x", minValue = -1f, maxValue = 1f, layout = "Axis", processors = "ConjureArcadeValue(min=0.0, max=1.0)", format = "BYTE", sizeInBits = 8)] + [InputControl(name = "y", minValue = -1f, maxValue = 1f, layout = "Axis", processors = "ConjureArcadeValue(min=0.0, max=1.0, invert)", format ="BYTE", sizeInBits = 8, offset = 1)] + public ButtonControl up { get; set; } + + [InputControl(useStateFrom = "y" , processors = "ConjureArcadeValue(min=0.0, max=1.0)", synthetic = true, displayName = "Down")] + public ButtonControl down { get; set; } + + [InputControl(useStateFrom = "x", processors = "ConjureArcadeValue(min=0.0, max=1.0, invert)", synthetic = true, displayName = "Left")] + public ButtonControl left { get; set; } + + [InputControl(useStateFrom = "x", processors = "ConjureArcadeValue(min=0.0, max=1.0)", synthetic = true, displayName = "Right")] + public ButtonControl right { get; set; } + + protected override void FinishSetup() + { + base.FinishSetup(); + up = GetChildControl("up"); + down = GetChildControl("down"); + left = GetChildControl("left"); + right = GetChildControl("right"); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickControl.cs.meta b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickControl.cs.meta new file mode 100644 index 00000000..0e55f46f --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickControl.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ef8fe9c76d3e4dcda92b275b68348e8e +timeCreated: 1695780776 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickProcessor.cs b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickProcessor.cs new file mode 100644 index 00000000..0202c2cb --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickProcessor.cs @@ -0,0 +1,79 @@ +#if ENABLE_INPUT_SYSTEM +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.InputSystem; + +// ReSharper disable ConvertToConstant.Local +// Reason: Attributes cannot be made into constants here since they are changed by Unity's internal input system. + +// Those classes exist to allow the conversion of the stick input into a normalized (-1.0, 1.0) range. +// They are registered when ConjureInputSystem is initialized and are used for stick inputs in the controller state and the stick control. + +namespace ConjureOS.Input +{ + [UsedImplicitly] + public class ConjureArcadeVector2Processor : InputProcessor + { + private readonly float minX = -1.0f; + private readonly float maxX = 1.0f; + private readonly bool invertX = false; + + private readonly float minY = -1.0f; + private readonly float maxY = 1.0f; + private readonly bool invertY = false; + + private readonly float deadZone = 0.1f; + + public override Vector2 Process(Vector2 value, InputControl control) + { + return new Vector2( + ConjureArcadeStickProcessorHelper.ProcessValue(value.x, minX, maxX, deadZone, invertX), + ConjureArcadeStickProcessorHelper.ProcessValue(value.y, minY, maxY, deadZone, invertY)); + } + } + + [UsedImplicitly] + public class ConjureArcadeValueProcessor : InputProcessor + { + private readonly float min = -1.0f; + private readonly float max = 1.0f; + private readonly bool invert = false; + + private readonly float deadZone = 0.1f; + + public override float Process(float value, InputControl control) + { + return ConjureArcadeStickProcessorHelper.ProcessValue(value, min, max, deadZone, invert); + } + } + + internal static class ConjureArcadeStickProcessorHelper + { + private const float MinStickValue = -1.0f; + private const float MaxStickValue = 1.0f; + private const float StickRange = MaxStickValue - MinStickValue; + + internal static float ProcessValue(float originalValue, float min, float max, float deadZone, bool invert) + { + float zero = (min + max) / 2; + if (Mathf.Approximately(originalValue, zero)) + { + return 0.0f; + } + + float originalRange = max - min; + if (Mathf.Approximately(originalRange, 0.0f)) + { + return 0.0f; + } + + float processedValue = (((originalValue - min) * StickRange) / originalRange) + MinStickValue; + processedValue = Mathf.Clamp(processedValue, MinStickValue, MaxStickValue); + processedValue = invert ? -processedValue : processedValue; + processedValue = processedValue > -deadZone && processedValue < deadZone ? 0.0f : processedValue; + + return processedValue; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickProcessor.cs.meta b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickProcessor.cs.meta new file mode 100644 index 00000000..35280c4e --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureArcadeStickProcessor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a2261cfa8c104770bad23d12a5194f9c +timeCreated: 1695774290 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/ConjureInputSystem.cs b/Assets/ConjureOS/Scripts/Input/ConjureInputSystem.cs new file mode 100644 index 00000000..943bc019 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureInputSystem.cs @@ -0,0 +1,38 @@ +using UnityEditor; +using UnityEngine; +#if ENABLE_INPUT_SYSTEM +using UnityEngine.InputSystem.Layouts; +using UnityEngine.InputSystem; +#endif + +namespace ConjureOS.Input +{ +#if UNITY_EDITOR + [InitializeOnLoad] +#endif + public static class ConjureInputSystem + { +#if UNITY_EDITOR + static ConjureInputSystem() + { + Initialize(); + } +#endif + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)] + private static void Initialize() + { +#if ENABLE_INPUT_SYSTEM + InputSystem.RegisterProcessor(typeof(ConjureArcadeVector2Processor), "ConjureArcadeVector2"); + InputSystem.RegisterProcessor(typeof(ConjureArcadeValueProcessor), "ConjureArcadeValue"); + + InputSystem.RegisterLayout("ConjureArcadeStick"); + + InputSystem.RegisterLayout( + matches: new InputDeviceMatcher() + .WithInterface(ConjureArcadeControllerInfo.Interface) + .WithProduct(ConjureArcadeControllerInfo.Product)); +#endif + } + } +} diff --git a/Assets/ConjureOS/Scripts/Input/ConjureInputSystem.cs.meta b/Assets/ConjureOS/Scripts/Input/ConjureInputSystem.cs.meta new file mode 100644 index 00000000..83705df3 --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/ConjureInputSystem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c4f9c6e992674c1bbcb497a7e194b0c6 +timeCreated: 1695755563 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/InputActionAssetExtension.cs b/Assets/ConjureOS/Scripts/Input/InputActionAssetExtension.cs new file mode 100644 index 00000000..ac6e33bb --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/InputActionAssetExtension.cs @@ -0,0 +1,109 @@ +#if ENABLE_INPUT_SYSTEM +using System.Collections.Generic; +using System.Linq; +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.Utilities; + +// ReSharper disable InvalidXmlDocComment +// Reason: We don't want to comment the "this" parameter in the extension functions. + +namespace ConjureOS.Input +{ + public static class InputActionAssetExtension + { + /// + /// Assign a specific Conjure Arcade Controller to this Input Action Asset. + /// All other Conjure Arcade Controllers will be disabled for this asset. + /// If the controller cannot be found for the controller index, there will be no assigned Conjure Arcade Controller. + /// + /// + /// If this is false, all devices will be disabled for this Input Action Asset except for the Conjure Arcade Controller associated to the given controller index. + /// If this is true, the devices that are not Conjure Arcade Controller (e.g. mouse/keyboard) will not be disabled. + /// + public static void AssignConjureController(this InputActionAsset inputActionAsset, int controllerIndex, bool keepOtherDevices = true) + { + List inputDevices = new List(); + if (keepOtherDevices) + { + if (inputActionAsset.devices == null) + { + inputDevices.AddRange(InputSystem.devices); + } + else + { + inputDevices = new List(inputActionAsset.devices); + } + + inputDevices.RemoveAll(inputDevice => inputDevice is ConjureArcadeController); + } + + ConjureArcadeController controller = ConjureArcadeController.GetForIndex(controllerIndex); + if (controller != null) + { + inputDevices.Add(controller); + } + + inputActionAsset.devices = inputDevices.ToArray(); + } + + /// + /// Whether or not it is possible to assign a specific controller index to this Input Action Asset. + /// + public static bool CanAssignConjureController(this InputActionAsset inputActionAsset, int controllerIndex) + { + return ConjureArcadeController.ExistForIndex(controllerIndex); + } + + /// + /// Get the controller index of the Conjure Arcade Controller associated with this Input Action Asset. + /// + /// + /// The controller index found. + /// If there was no Conjure Arcade Controller associated with this Input Action Asset, return false. + /// If there was multiple Conjure Arcade Controllers associated with this Input Action Asset, return the index of the first controller found. + /// + public static int GetConjureControllerIndex(this InputActionAsset inputActionAsset) + { + ConjureArcadeController[] controllers = GetConjureArcadeControllersFromDevices(inputActionAsset.devices); + if (controllers.Length == 0) + { + return -1; + } + + return controllers[0].ControllerIndex; + } + + /// + /// Get the controller index of all the Conjure Arcade Controllers associated with this Input Action Asset. + /// + /// + /// The controller indexes found. + /// If there was no Conjure Arcade Controller associated with this Input Action Asset, return an empty array. + /// + public static int[] GetConjureControllerIndexes(this InputActionAsset inputActionAsset) + { + ConjureArcadeController[] controllers = GetConjureArcadeControllersFromDevices(inputActionAsset.devices); + return controllers.Select(controller => controller.ControllerIndex).ToArray(); + } + + private static ConjureArcadeController[] GetConjureArcadeControllersFromDevices(ReadOnlyArray? devices) + { + if (devices == null) + { + return ConjureArcadeController.allControllers; + } + + List controllers = new List(); + foreach (InputDevice inputDevice in devices) + { + if (inputDevice is ConjureArcadeController device) + { + controllers.Add(device); + } + } + + return controllers.ToArray(); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/Input/InputActionAssetExtension.cs.meta b/Assets/ConjureOS/Scripts/Input/InputActionAssetExtension.cs.meta new file mode 100644 index 00000000..421de18d --- /dev/null +++ b/Assets/ConjureOS/Scripts/Input/InputActionAssetExtension.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ce5f252f61584da1be15a1aed6373337 +timeCreated: 1697552346 \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/MetadataWindow.meta b/Assets/ConjureOS/Scripts/MetadataWindow.meta new file mode 100644 index 00000000..ba4171f2 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fb8b8a42abb6ff4aa3af61ff2fa57a6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset new file mode 100644 index 00000000..4395db33 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6977c269ceb8edc4298ee30193e8a838, type: 3} + m_Name: ConjureArcadeMetadata + m_EditorClassIdentifier: + gameTitle: Overmelted + version: 0.1.0 + description: An overcooked inspired game where you gotta work in team to smith + weapons, tools and armors for you clients. The levels are quick and packed with + action for up to two players + minNumPlayer: 1 + maxNumPlayer: 2 + useLeaderboard: 0 + thumbnail: {fileID: 2800000, guid: 4082b7995fb3a974fb4b5853d98e37fb, type: 3} + gameplayImage: {fileID: 2800000, guid: f77d9fb0ed4f7ad459db7c688a37d2f9, type: 3} + developers: + - Jimmy Tremblay-Bernier + genres: + - selectedGenre: 14 + - selectedGenre: 28 + id: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset.meta b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset.meta new file mode 100644 index 00000000..50945553 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9cd8c3ac9c7ce34896c85d0fcd2aa5c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.cs b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.cs new file mode 100644 index 00000000..df24c6bf --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.cs @@ -0,0 +1,118 @@ +#if UNITY_EDITOR +using System; +using UnityEngine; + +namespace ConjureOS.MetadataWindow +{ + [Serializable] + public class ConjureArcadeMetadata : ScriptableObject + { + // Save location + public const string MetadataAssetPath = "Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.asset"; + + // Properties Validation + public const int GameTitleLimit = 100; + public const int DescriptionLimit = 250; + public const int DevelopersNameLimit = 100; + public const int MaxSelectedGenres = 3; + public const float MaxThumbnailFileSize = 1024; // In Kb + public const float MaxGameplayImageFileSize = 1024; // In Kb + public static readonly float[] RequiredThumbnailAR = { 16f, 9f }; // Aspect Ratio + public static readonly float[] RequiredGameplayImageAR = { 1f, 1f }; // Aspect Ratio + public static readonly string[] GenreOptions = + { + "Platformer", "Shooter", "Fighting", "Beat 'em up", "Stealth", "Survival", + "Rhythm", "Horror", "Metroidvania", "Puzzle", "RPG", "Roguelike", + "Simulation", "Strategy", "Action", "Adventure", "RTS", "MOBA", + "Battle Royale", "Racing", "Sports", "Board", "Idle", "Trivia", + "Art", "Educational", "Sandbox", "Open World", "Other" + }; + + // Editable settings + [SerializeField, HideInInspector] + [Tooltip("The title of the game. Can't exceed 100 characters.")] + private string gameTitle; + public string GameTitle => gameTitle; + + [SerializeField, HideInInspector] + [Tooltip("Current version of the game. Must follow the format 'x.x.x' where x are either numbers or letters.")] + private string version; + public string Version => version; + + [SerializeField, HideInInspector] + [TextArea] + [Tooltip("Small description of the game. Can't exceed 250 characters.")] + private string description; + public string Description => description; + + [SerializeField, HideInInspector] + [Tooltip("The minimum required number of players to play the game.")] + private int minNumPlayer = 1; + public int MinNumPlayer => minNumPlayer; + + [SerializeField, HideInInspector] + [Tooltip("The maximum required number of players to play the game.")] + private int maxNumPlayer = 1; + public int MaxNumPlayer => maxNumPlayer; + + [SerializeField, HideInInspector] + [Tooltip("Indicates if the game uses a leaderboard.")] + private bool useLeaderboard; + public bool UseLeaderboard => useLeaderboard; + + [SerializeField, HideInInspector] + [Tooltip("Thumbnail image of the game. Displayed in the game selection screen. The image format must be 16:9, and its size can't exceed 1 MB.")] + private Texture2D thumbnail; + public Texture2D Thumbnail => thumbnail; + + [SerializeField, HideInInspector] + [Tooltip("An image that shows what the game looks like. The image format must be 1:1, and its size can't exceed 1 MB.")] + private Texture2D gameplayImage; + public Texture2D GameplayImage => gameplayImage; + + [SerializeField, HideInInspector] + [Tooltip("The names of the game developers.")] + private string[] developers; + public string[] Developers => developers; + + [SerializeField, HideInInspector] + [Tooltip("Genres associated with the game.")] + private GameGenre[] genres; + public GameGenre[] Genres => genres; + + + // Uneditable settings + [SerializeField, HideInInspector] + private string id; + public string Id => id; + + [SerializeField, HideInInspector] + private DateTime releaseDate; + public DateTime ReleaseDate => releaseDate; + + [SerializeField, HideInInspector] + private DateTime lastGameUpdate; + public DateTime LastGameUpdate => lastGameUpdate; + + /// + /// Updates all uneditable settings + /// + public void UpdateUneditableData() + { + // Generate GUID + if (string.IsNullOrEmpty(id)) + { + id = Guid.NewGuid().ToString(); + } + + // Generate dates + if (releaseDate == DateTime.MinValue) + { + releaseDate = DateTime.Now; + } + + lastGameUpdate = DateTime.Now; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.cs.meta b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.cs.meta new file mode 100644 index 00000000..b77c6ea3 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadata.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6977c269ceb8edc4298ee30193e8a838 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataValidator.cs b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataValidator.cs new file mode 100644 index 00000000..48e7ed45 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataValidator.cs @@ -0,0 +1,292 @@ +#if UNITY_EDITOR +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace ConjureOS.MetadataWindow +{ + public class ConjureArcadeMetadataValidator + { + // String errors + private const string EmptyStringError = "Text field cannot be empty. "; + private const string CharLimitExceededError = "The field should contain less than {0} characters. "; + private const string VersionFormatError = "The version doesn't match the required format 'x.y.z'."; + private const string DevelopersCharLimitExceedError = "One or more names exceed the maximum characters limit of {0}."; + + // Min/max player errors + private const string IncorrectPlayerValueError = "Incorrect value. The number of players can't be 0 or lower. "; + private const string MinPlayerHigherThanMaxError = "Minimum number of players can't be higher than the maximum. "; + private const string MaxPlayerLowerThanMinError = "Maximum number of players can't be lower than the minimum. "; + + // Image errors + private const string MissingImageError = "No image was selected. "; + private const string InvalidAspectRatioError = "Invalid aspect ratio. Aspect ratio of the image should be {0}:{1}. "; + private const string InvalidFileSizeError = "Invalid file size. File size should be lower than {0} MB. "; + private const string InvalidImagePathError = "Invalid path. Chosen picture should be placed inside the 'Assets/' folder. "; + + // Other errors + private const string SameGenreSelectedMultipleTimeError = "Same genre is selected twice or more"; + + // Metadata error messages + private string gameTitleErrorMessage = ""; + public string GameTitleErrorMessage => gameTitleErrorMessage; + + private string versionErrorMessage = ""; + public string VersionErrorMessage => versionErrorMessage; + + private string descriptionErrorMessage = ""; + public string DescriptionErrorMessage => descriptionErrorMessage; + + private string developersErrorMessage = ""; + public string DevelopersErrorMessage => developersErrorMessage; + + private string minNumPlayerErrorMessage = ""; + public string MinNumPlayerErrorMessage => minNumPlayerErrorMessage; + + private string maxNumPlayerErrorMessage = ""; + public string MaxNumPlayerErrorMessage => maxNumPlayerErrorMessage; + + private string thumbnailErrorMessage = ""; + public string ThumbnailErrorMessage => thumbnailErrorMessage; + + private string gameplayImageErrorMessage = ""; + public string GameplayImageErrorMessage => gameplayImageErrorMessage; + + private string genresErrorMessage = ""; + public string GenresErrorMessage => genresErrorMessage; + + + private List developersErrorIndex = new List(); // Used to indicate which index have an error + public List DevelopersErrorIndex => developersErrorIndex; + + private int errorCount = -1; // Starts at -1 because no validation have been done yet + public int ErrorCount => errorCount; + + + /// + /// Validate the specified game metadata + /// + /// The metadata to be validated + /// Return true if metadata are valid. Otherwise, returns false. + public bool ValidateMetadata(ConjureArcadeMetadata metadata) + { + errorCount = 0; + + // Validate text fields + ValidateTextField(metadata.GameTitle, ConjureArcadeMetadata.GameTitleLimit, out gameTitleErrorMessage); + ValidateVersion(metadata.Version); + ValidateTextField(metadata.Description, ConjureArcadeMetadata.DescriptionLimit, out descriptionErrorMessage); + + // Validate player fields + ValidateNumPlayerFields(metadata.MinNumPlayer, metadata.MaxNumPlayer); + + // Validate image fields + Texture2D thumbnailTexture = metadata.Thumbnail; + ValidateImageField(thumbnailTexture, ConjureArcadeMetadata.RequiredThumbnailAR, ConjureArcadeMetadata.MaxThumbnailFileSize, out thumbnailErrorMessage); + + Texture2D gameplayImageTexture = metadata.GameplayImage; + ValidateImageField(gameplayImageTexture, ConjureArcadeMetadata.RequiredGameplayImageAR, ConjureArcadeMetadata.MaxGameplayImageFileSize, out gameplayImageErrorMessage); + + // Other validations + ValidateDevelopersList(metadata.Developers); + ValidateGenresList(metadata.Genres); + + return errorCount == 0; + } + + private void ValidateTextField(string text, int limit, out string outErrorMessage) + { + outErrorMessage = ""; + + // Check for empty string + if (string.IsNullOrWhiteSpace(text)) + { + outErrorMessage = EmptyStringError; + errorCount++; + return; + } + + // Check if string exceeds char limit + if (limit > 0) + { + if (text.Length > limit) + { + outErrorMessage = string.Format(CharLimitExceededError, limit); + errorCount++; + } + } + } + + private void ValidateVersion(string version) + { + versionErrorMessage = ""; + + // Required format is "x.y.z" + Regex rx = new Regex(@"^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\.[a-zA-Z-0-9]+$"); + var matches = rx.Match(version); + if (!matches.Success) + { + versionErrorMessage += VersionFormatError; + errorCount++; + } + } + + private void ValidateNumPlayerFields(int minNumPlayer, int maxNumPlayer) + { + minNumPlayerErrorMessage = ""; + maxNumPlayerErrorMessage = ""; + + if (minNumPlayer <= 0) + { + minNumPlayerErrorMessage += IncorrectPlayerValueError; + errorCount++; + } + + if (maxNumPlayer <= 0) + { + maxNumPlayerErrorMessage += IncorrectPlayerValueError; + errorCount++; + } + + if (minNumPlayer > maxNumPlayer) + { + minNumPlayerErrorMessage += MinPlayerHigherThanMaxError; + maxNumPlayerErrorMessage += MaxPlayerLowerThanMinError; + errorCount += 2; + } + } + + private void ValidateImageField(Texture2D image, float[] desiredRatio, float maxFileSize, out string outErrorMessage) + { + outErrorMessage = ""; + + if (image == null) + { + outErrorMessage += MissingImageError; + errorCount++; + return; + } + + // Verifying file size and aspect ratio + string imageRelativePath = AssetDatabase.GetAssetPath(image); + if (imageRelativePath.StartsWith("Assets/")) + { + // We check and remove "Assets" at the start of the relative path because + // Application.dataPath already gives us the path to the assets folder + string imageAbsolutePath = Application.dataPath + imageRelativePath.Substring(6); + + long length = new System.IO.FileInfo(imageAbsolutePath).Length; + if (length / 1024f > maxFileSize) + { + // File is bigger + outErrorMessage += string.Format(InvalidFileSizeError, maxFileSize); + errorCount++; + } + + // Verifying aspect ratio + float delta = 0.00001f; + float[] originalImageDimension = GetOriginalImageDimension(imageRelativePath); + float ratioW = originalImageDimension[0] / desiredRatio[0]; + float ratioH = originalImageDimension[1] / desiredRatio[1]; + if (Mathf.Abs(ratioW - ratioH) > delta) + { + outErrorMessage += string.Format(InvalidAspectRatioError, desiredRatio[0], desiredRatio[1]); + errorCount++; + } + } + else + { + // Images should be located inside the Assets folder + outErrorMessage += InvalidImagePathError; + errorCount++; + } + } + + private void ValidateGenresList(GameGenre[] genres) + { + genresErrorMessage = ""; + + // Check if a genre has been selected twice or more + for (int i = 0; i < genres.Length - 1; i++) + { + for (int j = 0; j < genres.Length; j++) + { + if (i == j) + { + continue; + } + + if (genres[i].selectedGenre == genres[j].selectedGenre) + { + genresErrorMessage += SameGenreSelectedMultipleTimeError; + errorCount++; + return; + } + } + } + } + + private float[] GetOriginalImageDimension(string assetPath) + { + int width = 0; + int height = 0; + TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter; + + if (importer != null) + { + object[] args = new object[2] { 0, 0 }; + MethodInfo mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance); + mi.Invoke(importer, args); + + width = (int)args[0]; + height = (int)args[1]; + } + + return new float[] { width, height }; + } + + /// + /// Validate a developers list + /// + /// The developers list to be analyzed + public void ValidateDevelopersList(string[] developers) + { + developersErrorIndex.Clear(); + developersErrorMessage = ""; + for (int i = 0; i < developers.Length; i++) + { + if (developers[i].Length > ConjureArcadeMetadata.DevelopersNameLimit) + { + developersErrorMessage += string.Format(DevelopersCharLimitExceedError, ConjureArcadeMetadata.DevelopersNameLimit); + developersErrorIndex.Add(i); + errorCount++; + } + } + } + + /// + /// + /// Returns the validation state based on the current amount of errors detected + public MetadataValidationStateType GetValidationStateType() + { + if (errorCount < 0) + { + // Smaller than 0, which means data haven't been verified yet + return MetadataValidationStateType.NotVerified; + } + else if (errorCount == 0) + { + // No error, means it's a success + return MetadataValidationStateType.Validated; + } + else + { + // Errors were detected + return MetadataValidationStateType.Failed; + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataValidator.cs.meta b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataValidator.cs.meta new file mode 100644 index 00000000..bd9a05db --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: edace48768db8a54e8806e8d703c6efa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataWindow.cs b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataWindow.cs new file mode 100644 index 00000000..1865bcf8 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataWindow.cs @@ -0,0 +1,301 @@ +#if UNITY_EDITOR +using System; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; +using ConjureOS.CustomWindow; + +namespace ConjureOS.MetadataWindow +{ + public class ConjureArcadeMetadataWindow : EditorWindow + { + private const string WindowName = "Arcade Game Metadata Editor"; + + // Game Metadata + private static ConjureArcadeMetadata metadata; + private ConjureArcadeMetadataValidator metadataValidator; + private SerializedObject serializedObject; + + // Metadata Properties + private SerializedProperty gameTitleProperty; + private SerializedProperty versionProperty; + private SerializedProperty descriptionProperty; + private SerializedProperty minNumPlayerProperty; + private SerializedProperty maxNumPlayerProperty; + private SerializedProperty useLeaderboardProperty; + private SerializedProperty thumbnailProperty; + private SerializedProperty gameplayImageProperty; + private SerializedProperty developersProperty; + private SerializedProperty genresProperty; + + private ReorderableList developersList; + private ReorderableList genresList; + + // UI Properties + private Vector2 scrollPos = Vector2.zero; + + private void OnEnable() + { + metadataValidator = new ConjureArcadeMetadataValidator(); + titleContent = new GUIContent(WindowName); + + if (!metadata) + { + OnLoad(); + } + + serializedObject = new SerializedObject(metadata); + SetUpProperties(serializedObject); + } + + [InitializeOnLoadMethod] + private static void OnLoad() + { + if (!metadata) + { + metadata = AssetDatabase.LoadAssetAtPath(ConjureArcadeMetadata.MetadataAssetPath); + + // Data exists + if (metadata) + { + return; + } + + metadata = CreateInstance(); + + AssetDatabase.CreateAsset(metadata, ConjureArcadeMetadata.MetadataAssetPath); + AssetDatabase.Refresh(); + } + } + + private void OnGUI() + { + serializedObject.Update(); + + // Add padding to the window + int globalSpace = 2; + int uniformPadding = ConjureArcadeGUI.Style.UniformPadding; + RectOffset padding = new RectOffset(uniformPadding, uniformPadding, 0, 0); + Rect area = new Rect( + padding.right, + padding.top, + position.width - (padding.left), + position.height - (padding.top + padding.bottom)); + + // Generate input fields + GUILayout.BeginArea(area); + + // Scrollbar + RectOffset vertScrollbarPadding = new RectOffset(uniformPadding, 0, 0, 0); + GUIStyle vertScrollbarSkin = new GUIStyle(GUI.skin.verticalScrollbar); + vertScrollbarSkin.margin = vertScrollbarPadding; + + scrollPos = GUILayout.BeginScrollView(scrollPos, false, true, new GUIStyle(GUI.skin.horizontalScrollbar), vertScrollbarSkin); + + GUILayout.Space(uniformPadding); + GUILayout.Label("GAME METADATA", EditorStyles.boldLabel); + + EditorGUILayout.PropertyField(gameTitleProperty, new GUIContent("Game Title")); + ShowErrorMessage(metadataValidator.GameTitleErrorMessage); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(versionProperty, new GUIContent("Version")); + ShowErrorMessage(metadataValidator.VersionErrorMessage); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(descriptionProperty, new GUIContent("Description"), GUILayout.Height(150)); + ShowErrorMessage(metadataValidator.DescriptionErrorMessage); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(minNumPlayerProperty, new GUIContent("Min Number of Players")); + ShowErrorMessage(metadataValidator.MinNumPlayerErrorMessage); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(maxNumPlayerProperty, new GUIContent("Max Number of Players")); + ShowErrorMessage(metadataValidator.MaxNumPlayerErrorMessage); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(useLeaderboardProperty, new GUIContent("Use Leaderboard")); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(thumbnailProperty, new GUIContent("Thumbnail")); + ShowErrorMessage(metadataValidator.ThumbnailErrorMessage); + GUILayout.Space(globalSpace); + + EditorGUILayout.PropertyField(gameplayImageProperty, new GUIContent("Gameplay Image")); + ShowErrorMessage(metadataValidator.GameplayImageErrorMessage); + GUILayout.Space(globalSpace); + + GUILayout.Space(10); + developersList.DoLayoutList(); + ShowErrorMessage(metadataValidator.DevelopersErrorMessage); + + GUILayout.Space(10); + UpdateReorderableListInteractions(genresList, ConjureArcadeMetadata.MaxSelectedGenres); + genresList.DoLayoutList(); + ShowErrorMessage(metadataValidator.GenresErrorMessage); + + GUILayout.Space(10); + + // Show release date and last change date ONLY if a date has been set + if (metadata.ReleaseDate != DateTime.MinValue) + { + GUILayout.Label("Release Date: " + metadata.ReleaseDate.ToString()); + } + if (metadata.LastGameUpdate != DateTime.MinValue) + { + GUILayout.Label("Last Change: " + metadata.LastGameUpdate.ToString()); + } + + // Validate properties and save data + serializedObject.ApplyModifiedProperties(); + + GUILayout.Space(30); + if (GUILayout.Button("Execute Validation", GUILayout.Width(150))) + { + metadataValidator.ValidateMetadata(metadata); + } + + GUILayout.Space(globalSpace); + + ShowValidationResultMessage(); + + GUILayout.Space(uniformPadding); + + GUILayout.EndScrollView(); + GUILayout.EndArea(); + } + + private void ShowErrorMessage(string errorMessage) + { + if (errorMessage != string.Empty) + { + GUILayout.Label(errorMessage, ConjureArcadeGUI.Style.ErrorStyle); + GUILayout.Space(3); + } + } + + private void ShowValidationResultMessage() + { + MetadataValidationStateType validationState = metadataValidator.GetValidationStateType(); + + switch (validationState) + { + case MetadataValidationStateType.NotVerified: + // No message is displayed + return; + + case MetadataValidationStateType.Validated: + // No error, means it's a success + GUILayout.Label(ConjureArcadeGUI.Message.MetadataConfirmedMessage, ConjureArcadeGUI.Style.SuccessStyle); + GUILayout.Space(3); + break; + + case MetadataValidationStateType.Failed: + // Errors were detected + string plural = (metadataValidator.ErrorCount > 1) ? "s" : ""; + string formatedMessage = string.Format(ConjureArcadeGUI.Message.MetadataFailedMessage, metadataValidator.ErrorCount, plural); + ShowErrorMessage(formatedMessage); + break; + } + } + + private void SetUpProperties(SerializedObject serializedObject) + { + // Get data + gameTitleProperty = serializedObject.FindProperty("gameTitle"); + versionProperty = serializedObject.FindProperty("version"); + descriptionProperty = serializedObject.FindProperty("description"); + minNumPlayerProperty = serializedObject.FindProperty("minNumPlayer"); + maxNumPlayerProperty = serializedObject.FindProperty("maxNumPlayer"); + useLeaderboardProperty = serializedObject.FindProperty("useLeaderboard"); + thumbnailProperty = serializedObject.FindProperty("thumbnail"); + gameplayImageProperty = serializedObject.FindProperty("gameplayImage"); + + // Get developers data and prepare list + developersProperty = serializedObject.FindProperty("developers"); + developersList = new ReorderableList(serializedObject, developersProperty, true, true, true, true); + developersList.drawElementCallback = DrawDevelopersListItems; + developersList.drawHeaderCallback = DrawDevelopersListHeader; + developersList.onReorderCallback = OnDevelopersReorder; + + + // Get genres data and prepare list + genresProperty = serializedObject.FindProperty("genres"); + genresList = new ReorderableList(serializedObject, genresProperty, true, true, true, true); + genresList.drawElementCallback = DrawGenresListItems; + genresList.drawHeaderCallback = DrawGenresListHeader; + } + + private void UpdateReorderableListInteractions(ReorderableList list, int countLimit) + { + // Hide or show the "Add" button only if the count limit has not been reached + if (genresList.count >= countLimit) + { + list.displayAdd = false; + } + else + { + list.displayAdd = true; + } + } + + + // ReorderableList Callbacks ===== + private void DrawGenresListItems(Rect rect, int index, bool isActive, bool isFocused) + { + // Get the selected genre of the current item + var element = genresProperty.GetArrayElementAtIndex(index); + var selectedGenre = element.FindPropertyRelative(nameof(GameGenre.selectedGenre)); + + var popupHeight = EditorGUI.GetPropertyHeight(selectedGenre); + + // Create popup + selectedGenre.intValue = EditorGUI.Popup(new Rect(rect.x, rect.y, rect.width, popupHeight), selectedGenre.intValue, ConjureArcadeMetadata.GenreOptions); + } + + private void DrawDevelopersListItems(Rect rect, int index, bool isActive, bool isFocused) + { + // Get the selected genre of the current item + var element = developersProperty.GetArrayElementAtIndex(index); + + // Create popup + GUIStyle fieldErrorIndicatorStyle = new GUIStyle(EditorStyles.textField); + fieldErrorIndicatorStyle.normal.textColor = ConjureArcadeGUI.Style.ColorError; + + for (int i = 0; i < metadataValidator.DevelopersErrorIndex.Count; i++) + { + if (index == metadataValidator.DevelopersErrorIndex[i]) + { + element.stringValue = EditorGUI.TextField(new Rect(rect.x, rect.y, rect.width, rect.height), element.stringValue, fieldErrorIndicatorStyle); + return; + } + } + + element.stringValue = EditorGUI.TextField(new Rect(rect.x, rect.y, rect.width, rect.height), element.stringValue); + } + + private void DrawGenresListHeader(Rect rect) + { + DrawListHeader(rect, "Genres"); + } + + private void DrawDevelopersListHeader(Rect rect) + { + DrawListHeader(rect, "Developers"); + } + + private void DrawListHeader(Rect rect, string name) + { + EditorGUI.LabelField(rect, name); + } + + private void OnDevelopersReorder(ReorderableList reList) + { + // On reorder of the developers list, data are revalidated because of the new order + serializedObject.ApplyModifiedProperties(); + metadataValidator.ValidateDevelopersList(metadata.Developers); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataWindow.cs.meta b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataWindow.cs.meta new file mode 100644 index 00000000..3be98c38 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/ConjureArcadeMetadataWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0cfd6670cf89b984bb971537d740f4c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/GameGenre.cs b/Assets/ConjureOS/Scripts/MetadataWindow/GameGenre.cs new file mode 100644 index 00000000..6da87029 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/GameGenre.cs @@ -0,0 +1,10 @@ +using System; + +namespace ConjureOS.MetadataWindow +{ + [Serializable] + public struct GameGenre + { + public int selectedGenre; + } +} \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/GameGenre.cs.meta b/Assets/ConjureOS/Scripts/MetadataWindow/GameGenre.cs.meta new file mode 100644 index 00000000..5c09ba93 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/GameGenre.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bf07614a284e334b8300836f4365f78 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/MetadataValidation.cs b/Assets/ConjureOS/Scripts/MetadataWindow/MetadataValidation.cs new file mode 100644 index 00000000..6c9efa8c --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/MetadataValidation.cs @@ -0,0 +1,9 @@ +namespace ConjureOS.MetadataWindow +{ + public enum MetadataValidationStateType + { + NotVerified, + Validated, + Failed + } +} \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/MetadataWindow/MetadataValidation.cs.meta b/Assets/ConjureOS/Scripts/MetadataWindow/MetadataValidation.cs.meta new file mode 100644 index 00000000..bec0a7b5 --- /dev/null +++ b/Assets/ConjureOS/Scripts/MetadataWindow/MetadataValidation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90c3d1fd9b921034c964891b00a1594c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/UploadWindow.meta b/Assets/ConjureOS/Scripts/UploadWindow.meta new file mode 100644 index 00000000..1f491b89 --- /dev/null +++ b/Assets/ConjureOS/Scripts/UploadWindow.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 696a1ff0be1f41e439b3185025356f09 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeGameUploaderWindow.cs b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeGameUploaderWindow.cs new file mode 100644 index 00000000..b256c3c3 --- /dev/null +++ b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeGameUploaderWindow.cs @@ -0,0 +1,122 @@ +#if UNITY_EDITOR +using ConjureOS.MetadataWindow; +using ConjureOS.CustomWindow; +using UnityEditor; +using UnityEngine; + +namespace ConjureOS.UploaderWindow +{ + public class ConjureArcadeGameUploaderWindow : EditorWindow + { + private const string WindowName = "Arcade Game Uploader"; + + // Game Metadata + private static ConjureArcadeMetadata metadata; + private ConjureArcadeMetadataValidator metadataValidator; + private ConjureArcadeUploadProcessor uploadProcessor; + + private void OnEnable() + { + metadataValidator = new ConjureArcadeMetadataValidator(); + uploadProcessor = new ConjureArcadeUploadProcessor(); + titleContent = new GUIContent(WindowName); + + if (!metadata) + { + OnLoad(); + } + } + + private static void OnLoad() + { + if (!metadata) + { + metadata = AssetDatabase.LoadAssetAtPath(ConjureArcadeMetadata.MetadataAssetPath); + + // Data exists + if (metadata) + { + return; + } + + metadata = CreateInstance(); + + AssetDatabase.CreateAsset(metadata, ConjureArcadeMetadata.MetadataAssetPath); + AssetDatabase.Refresh(); + } + } + + private void OnGUI() + { + // Add padding to the window + int sectionSpace = 20; + int uniformPadding = ConjureArcadeGUI.Style.UniformPadding; + RectOffset padding = new RectOffset(uniformPadding, uniformPadding, 0, 0); + Rect area = new Rect( + padding.right, + padding.top, + position.width - (padding.left), + position.height - (padding.top + padding.bottom)); + + GUILayout.BeginArea(area); + + // Web Server Info section + GUILayout.Label("WEB SERVER INFO", EditorStyles.boldLabel); + // TODO Add server connection data / fields + + GUILayout.Space(sectionSpace); + + // Metadata section + GUILayout.Label("METADATA", EditorStyles.boldLabel); + GUILayout.Label("Be sure to have valid metadata before uploading the game to the web server.", EditorStyles.wordWrappedLabel); + + ShowValidationResultMessage(); + if (GUILayout.Button("Validate Metadata", GUILayout.Width(150))) + { + metadataValidator.ValidateMetadata(metadata); + } + + GUILayout.Space(sectionSpace); + + // Build and Upload section + GUILayout.Label("BUILD AND UPLOAD", EditorStyles.boldLabel); + GUILayout.Label("When ready, you can build and upload the game to the web server.", EditorStyles.wordWrappedLabel); + if (GUILayout.Button("Build & Upload", GUILayout.Width(150))) + { + uploadProcessor.BuildAndUpload(metadata, metadataValidator); + GUIUtility.ExitGUI(); + } + + GUILayout.EndArea(); + } + + private void ShowValidationResultMessage() + { + MetadataValidationStateType validationState = metadataValidator.GetValidationStateType(); + + switch (validationState) + { + case MetadataValidationStateType.NotVerified: + // No message is displayed + return; + + case MetadataValidationStateType.Validated: + // No error, means it's a success + GUILayout.Label(ConjureArcadeGUI.Message.MetadataConfirmedMessage, ConjureArcadeGUI.Style.SuccessStyle); + GUILayout.Space(3); + break; + + case MetadataValidationStateType.Failed: + // Errors were detected + string plural = (metadataValidator.ErrorCount > 1) ? "s" : ""; + string formatedMessage = + string.Format(ConjureArcadeGUI.Message.MetadataFailedMessage, metadataValidator.ErrorCount, plural) + + string.Format(" Please, fix the error{0} in the Game Metadata window ('Arcade > Game Metadata Editor').", plural); + GUILayout.Label(formatedMessage, ConjureArcadeGUI.Style.ErrorStyle); + GUILayout.Space(3); + break; + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeGameUploaderWindow.cs.meta b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeGameUploaderWindow.cs.meta new file mode 100644 index 00000000..ed41d21c --- /dev/null +++ b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeGameUploaderWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd1c153b5930bca4aa2b62c24b229838 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeUploadProcessor.cs b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeUploadProcessor.cs new file mode 100644 index 00000000..eb448fca --- /dev/null +++ b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeUploadProcessor.cs @@ -0,0 +1,239 @@ +#if UNITY_EDITOR +using ConjureOS.MetadataWindow; +using System; +using System.IO; +using System.IO.Compression; +using UnityEditor; +using UnityEngine; + +namespace ConjureOS.UploaderWindow +{ + public class ConjureArcadeUploadProcessor + { + private const string logConjureArcade = "Conjure Arcade: "; + + private const string GameFolder = "game\\"; + private const string MediasFolder = "medias\\"; + private const string TempFolder = "temp\\"; + private const string MetadataFileName = "metadata.txt"; + + /// + /// Build and upload the game to the web server. + /// Must use valid Conjure Arcade metadata, or the process will fail. + /// + /// The Conjure Arcade metadata of the game + /// The metadata validator + public void BuildAndUpload(ConjureArcadeMetadata metadata, ConjureArcadeMetadataValidator metadataValidator) + { + // Step 1: Validate metadata + if (!metadataValidator.ValidateMetadata(metadata)) + { + ShowErrorDialog( + "Some entries in the game metadata are incorrect. " + + "You must fix them in order to upload the game to the web server."); + return; + } + + + // Step 2: Build game + string fileName; // Name of the executable file + string fileExtension; // Extension of the executable file + string buildDirectoryPath; // Path to the build directory + string tempDirectoryPath; // Path to the temp directory, located inside the build directory + try + { + // Get current build settings + BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions(); + buildPlayerOptions = BuildPlayerWindow.DefaultBuildMethods.GetBuildPlayerOptions(buildPlayerOptions); + + // Get file and directory data + fileName = Path.GetFileNameWithoutExtension(buildPlayerOptions.locationPathName); + fileExtension = Path.GetExtension(buildPlayerOptions.locationPathName); + buildDirectoryPath = Path.GetDirectoryName(buildPlayerOptions.locationPathName) + "\\"; + tempDirectoryPath = buildDirectoryPath + TempFolder; + + // Change Build Settings build directory to the temp directory + // Generated location for the game is of the format "...BuildDirectory\temp\game\ProductName.extension" + buildPlayerOptions.locationPathName = + tempDirectoryPath + + GameFolder + + fileName + + fileExtension; + + // Build the game + BuildPipeline.BuildPlayer(buildPlayerOptions); + } + catch (BuildPlayerWindow.BuildMethodException) + { + // Exception called when the user manually closes the "File Chooser" window + Debug.Log(logConjureArcade + "Build & Upload canceled."); + return; + } + catch (Exception e) + { + ShowErrorDialog("An error occured when building the game."); + Debug.LogError(e); + return; + } + + // "game" folder content is compressed + CompressAndDelete(tempDirectoryPath + GameFolder, tempDirectoryPath + "game.zip"); + + + // Step 3: Copy images to the temp directory + string mediasDirectoryPath = tempDirectoryPath + MediasFolder; + string thumbnailPath = CopyAndRenameImage(metadata.Thumbnail, mediasDirectoryPath, "thumbnail"); + string gameplayImagePath = CopyAndRenameImage(metadata.GameplayImage, mediasDirectoryPath, "gameplayImage"); + + + // Step 4: Generate metadata inside the temp directory + metadata.UpdateUneditableData(); + string metadataContent = GenerateMetadata(metadata, thumbnailPath, gameplayImagePath, fileName + fileExtension); + if (!WriteMetadataFile(metadataContent, tempDirectoryPath)) + { + ShowErrorDialog("An error occured when generating the metadata file."); + return; + } + + + // Step 5: Convert all files int a ".conj" + string conjFilePath = buildDirectoryPath + fileName + ".conj"; + CompressAndDelete(tempDirectoryPath, conjFilePath); + + + // Step 6: Upload game and metadata to the webserver + // TODO Add server connection / upload + + + // Step 7: Show success feedback to the user + Debug.Log(logConjureArcade + "Game was build and upload to the web server."); + EditorUtility.DisplayDialog( + "Success", + "Game was build and upload to the web server.", + "Ok"); + } + + private static void ShowErrorDialog(string description) + { + EditorUtility.DisplayDialog("Fail to Build and Upload Game", description, "Ok"); + Debug.LogError(logConjureArcade + description); + } + + private static string CopyAndRenameImage(Texture2D image, string newDirectoryPath, string newFileName) + { + string relativePath = AssetDatabase.GetAssetPath(image); + + // We check and remove "Assets" at the start of the relative path because + // Application.dataPath already gives us the path to the assets folder + // Ex: Assets/Images/ --> Images/ + string oldAbsolutePath = Application.dataPath + relativePath.Substring(6); + + // We find the image, copy it to the new folder (newDirectoryPath), change its name and keep its extension + FileInfo file = new FileInfo(oldAbsolutePath); + string fullFileName = string.Format("{0}{1}", newFileName, file.Extension); + if (file.Exists) + { + // Delete file in new directory if it already exists + string newFilePath = string.Format("{0}{1}", newDirectoryPath, fullFileName); + + if (!Directory.Exists(newDirectoryPath)) + { + // Check if new directory exists, and create it + // If folder doesn't exist, the file cannot be copied + Directory.CreateDirectory(newDirectoryPath); + } + else if (File.Exists(newFilePath)) + { + // Check if file exists, and delete it + File.Delete(newFilePath); + } + + file.CopyTo(newFilePath); + } + + return fullFileName; + } + + private string GenerateMetadata( + ConjureArcadeMetadata metadata, + string thumbnailFileName, + string gameplayImageFileName, + string fileName) + { + string newLine = Environment.NewLine; + string content = ""; + content += + "id: " + metadata.Id + newLine + + "game: " + metadata.GameTitle + newLine + + "version: " + metadata.Version + newLine + + "description: " + metadata.Description + newLine + + "players: " + metadata.MinNumPlayer + "-" + metadata.MaxNumPlayer + newLine + + "leaderboard: " + metadata.UseLeaderboard + newLine + + "thumbnailPath: " + thumbnailFileName + newLine + + "imagePath: " + gameplayImageFileName + newLine + + "release: " + FormatDate(metadata.ReleaseDate) + newLine + + "modification: " + FormatDate(metadata.LastGameUpdate) + newLine + + "file: " + GameFolder + fileName + newLine; + + // Adding developers + content += "developers: "; + foreach (string developer in metadata.Developers) + { + content += developer + ", "; + } + content += newLine; + + // Adding genres + content += "genres:" + newLine; + foreach (GameGenre gameGenre in metadata.Genres) + { + string genre = ConjureArcadeMetadata.GenreOptions[gameGenre.selectedGenre]; + content += " " + genre + newLine; + } + + return content; + } + + private bool WriteMetadataFile(string content, string directoryPath) + { + string fullPath = directoryPath + MetadataFileName; + + try + { + if (File.Exists(fullPath)) + { + File.Delete(fullPath); + } + + // Write content + using (FileStream fs = File.Create(fullPath)) + { + byte[] encodedContent = new System.Text.UTF8Encoding(true).GetBytes(content); + fs.Write(encodedContent, 0, encodedContent.Length); + } + } + catch (Exception e) + { + Debug.LogError(e.Message); + return false; + } + + return true; + } + + private void CompressAndDelete(string sourceDirectoryPath, string destinationArchiveFileName) + { + ZipFile.CreateFromDirectory(sourceDirectoryPath, destinationArchiveFileName); + Directory.Delete(sourceDirectoryPath, true); + } + + private string FormatDate(DateTime date) + { + return + date.Day.ToString() + "-" + + date.Month.ToString() + "-" + + date.Year.ToString(); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeUploadProcessor.cs.meta b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeUploadProcessor.cs.meta new file mode 100644 index 00000000..3709667b --- /dev/null +++ b/Assets/ConjureOS/Scripts/UploadWindow/ConjureArcadeUploadProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 67065d97fd394ab428022e93d776bcac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Gameplay.PNG b/Assets/Gameplay.PNG new file mode 100644 index 00000000..6ab08514 Binary files /dev/null and b/Assets/Gameplay.PNG differ diff --git a/Assets/Gameplay.PNG.meta b/Assets/Gameplay.PNG.meta new file mode 100644 index 00000000..d69cf6ec --- /dev/null +++ b/Assets/Gameplay.PNG.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 10d56716671742243b83b63164772384 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Gameplay.jpg b/Assets/Gameplay.jpg new file mode 100644 index 00000000..1de6d4a5 --- /dev/null +++ b/Assets/Gameplay.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28fb0ef313d91802f5704986bba0bcc5a84d0aeabf8c6f55fb943153828d87a8 +size 263473 diff --git a/Assets/Gameplay.jpg.meta b/Assets/Gameplay.jpg.meta new file mode 100644 index 00000000..1ca2bed5 --- /dev/null +++ b/Assets/Gameplay.jpg.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: f77d9fb0ed4f7ad459db7c688a37d2f9 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/InputActions/CommonInput.inputactions b/Assets/InputActions/CommonInput.inputactions index e18154d4..90c68dd3 100644 --- a/Assets/InputActions/CommonInput.inputactions +++ b/Assets/InputActions/CommonInput.inputactions @@ -47,6 +47,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "56e35fc7-3515-47d8-b863-76845c6f4447", + "path": "/start", + "interactions": "", + "processors": "", + "groups": "", + "action": "Join", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "b38c5aaa-31ba-4881-b6c9-a2316c144b2d", @@ -68,6 +79,17 @@ "action": "Leave", "isComposite": false, "isPartOfComposite": false + }, + { + "name": "", + "id": "9cea3501-b3f2-45a9-a359-5ae29f83da77", + "path": "/button2", + "interactions": "", + "processors": "", + "groups": "", + "action": "Leave", + "isComposite": false, + "isPartOfComposite": false } ] } diff --git a/Assets/InputActions/GameMovementsPlayer.inputactions b/Assets/InputActions/GameMovementsPlayer.inputactions index 9b639af1..0ea7f9a7 100644 --- a/Assets/InputActions/GameMovementsPlayer.inputactions +++ b/Assets/InputActions/GameMovementsPlayer.inputactions @@ -118,6 +118,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "b714db0b-e69a-4f21-938e-4f18ee1dc89d", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "4d10aaef-32d6-4c7a-8449-1c849dda257e", @@ -140,6 +151,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "9d8d83a4-3c84-43f8-9803-b7b08077dbd4", + "path": "/button2", + "interactions": "", + "processors": "", + "groups": "", + "action": "SecondaryAction", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "b0bf774f-f879-4c0c-8608-96f39ad24d03", @@ -162,6 +184,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "ac1c47b6-b41f-4497-a860-f9f9a9b77211", + "path": "/button1", + "interactions": "", + "processors": "", + "groups": "", + "action": "PrimaryAction", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "e9736063-d308-4c4a-a55d-4b8db3126a92", @@ -184,6 +217,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "3352fcb0-4077-4135-96ac-d6e80b239aa5", + "path": "/start", + "interactions": "", + "processors": "", + "groups": "", + "action": "Pause", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "2502bf06-81a2-4053-a57d-be08e7cb61c6", @@ -205,6 +249,17 @@ "action": "SwitchPlayer", "isComposite": false, "isPartOfComposite": false + }, + { + "name": "", + "id": "9bbb6b94-304e-42b1-aa57-b4c8eadf99f9", + "path": "/buttonA", + "interactions": "", + "processors": "", + "groups": "", + "action": "SwitchPlayer", + "isComposite": false, + "isPartOfComposite": false } ] } diff --git a/Assets/InputActions/MenuAction.inputactions b/Assets/InputActions/MenuAction.inputactions index e9446409..f411f58d 100644 --- a/Assets/InputActions/MenuAction.inputactions +++ b/Assets/InputActions/MenuAction.inputactions @@ -317,6 +317,17 @@ "isComposite": false, "isPartOfComposite": true }, + { + "name": "", + "id": "eb39813a-66de-41e9-a7ee-f6b5ab305254", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "aa21891e-8f0b-40c8-ba7e-fd97e7ca38e5", @@ -328,6 +339,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "f5a82c0f-021d-42d6-981e-316cf08c637f", + "path": "/button1", + "interactions": "", + "processors": "", + "groups": "", + "action": "Submit", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "5de9312c-2df2-40ab-b3fc-3f64bdba64c5", @@ -339,6 +361,17 @@ "isComposite": false, "isPartOfComposite": false }, + { + "name": "", + "id": "e4c84fc6-a05a-4d3b-891b-184add45ce56", + "path": "/button2", + "interactions": "", + "processors": "", + "groups": "", + "action": "Cancel", + "isComposite": false, + "isPartOfComposite": false + }, { "name": "", "id": "6134beac-34df-4c4a-ae23-e5fac7cc7b2e", diff --git a/Assets/MainMenu.PNG b/Assets/MainMenu.PNG new file mode 100644 index 00000000..d4b997ff Binary files /dev/null and b/Assets/MainMenu.PNG differ diff --git a/Assets/MainMenu.PNG.meta b/Assets/MainMenu.PNG.meta new file mode 100644 index 00000000..9aecde8e --- /dev/null +++ b/Assets/MainMenu.PNG.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 87ea2a8e44e913e43850f3a9b4e9a884 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MainMenu.jpg b/Assets/MainMenu.jpg new file mode 100644 index 00000000..396a55cc --- /dev/null +++ b/Assets/MainMenu.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60c4296d93c1ba348b3a082405f4a3540c43acf739052aa1d2abc25addc745be +size 212536 diff --git a/Assets/MainMenu.jpg.meta b/Assets/MainMenu.jpg.meta new file mode 100644 index 00000000..1e917d0b --- /dev/null +++ b/Assets/MainMenu.jpg.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 4082b7995fb3a974fb4b5853d98e37fb +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MenuInputManager.cs b/Assets/MenuInputManager.cs deleted file mode 100644 index 6f4faaac..00000000 --- a/Assets/MenuInputManager.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using Conjure.Input; -using Sirenix.OdinInspector; -using UnityEngine; -using UnityEngine.InputSystem; -using UnityEngine.InputSystem.UI; -using UnityEngine.InputSystem.Utilities; -using InputDevice = UnityEngine.InputSystem.InputDevice; - -public class MenuInputManager : SerializedMonoBehaviour -{ - [SerializeField, Required] private InputSystemUIInputModule inputSystemUIInputModule; - [SerializeField, Required] private InputServerReference inputServerReference; - - // Start is called before the first frame update - void Start() - { - inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(); - } - - public void OnJoin(int playerSeat) - - { - if (inputSystemUIInputModule.actionsAsset.devices == null) - { - return; - } - - InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent(); - - List devices = - new List(inputSystemUIInputModule.actionsAsset.devices.Value.ToArray()); - - PlayerEnum player = inputManagerServer.GetPlayerFromInt(playerSeat); - - // shouldn't be reachable - if (player == PlayerEnum.None) - { - return; - } - - InputDevice currentDevice = FindDeviceById(inputManagerServer.GetDeviceIdFromPlayerEnum(player)); - - // shouldn't be reachable - if (currentDevice is not null) - { - devices.Add(currentDevice); - } - - inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(devices.ToArray()); - } - - public void OnLeave(int playerSeat) - { - if (inputSystemUIInputModule.actionsAsset.devices == null) - { - return; - } - - InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent(); - - if (playerSeat == 0 && inputManagerServer.GetNumberPlayers() == 0) - { - inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(); - return; - } - - InputDevice currentDevice = FindDeviceById(inputManagerServer.GetDeviceIdFromPlayerEnum(PlayerEnum.Player1)); - inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(new []{currentDevice}); - } - - private InputDevice FindDeviceById(int deviceId) - { - foreach (InputDevice currentDevice in InputSystem.devices) - { - if (currentDevice.deviceId == deviceId) - { - return currentDevice; - } - } - - return null; - } -} \ No newline at end of file diff --git a/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/AOTGenerationConfig.asset b/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/AOTGenerationConfig.asset index d024af96..d2bb0a2d 100644 --- a/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/AOTGenerationConfig.asset +++ b/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/AOTGenerationConfig.asset @@ -16,5 +16,35 @@ MonoBehaviour: deleteDllAfterBuilds: 1 AutomateForAllAOTPlatforms: 1 automateForPlatforms: 0900000014000000 - lastScan: 638328066783784121 - supportSerializedTypes: [] + lastScan: 638354871209628840 + supportSerializedTypes: + - TypeName: System.Collections.Generic.Dictionary`2[[Conjure.Input.PlayerEnum, + Assembly-CSharp],[System.Int32, mscorlib]], mscorlib + IsCustom: 0 + Emit: 1 + - TypeName: System.Collections.Generic.EnumEqualityComparer`1[[Conjure.Input.PlayerEnum, + Assembly-CSharp]], mscorlib + IsCustom: 0 + Emit: 1 + - TypeName: UnityEngine.GameObject, UnityEngine.CoreModule + IsCustom: 0 + Emit: 1 + - TypeName: System.Collections.Generic.IEqualityComparer`1[[Conjure.Input.PlayerEnum, + Assembly-CSharp]], mscorlib + IsCustom: 0 + Emit: 1 + - TypeName: Conjure.Interraction.IInteractable, Assembly-CSharp + IsCustom: 0 + Emit: 1 + - TypeName: System.Int32, mscorlib + IsCustom: 0 + Emit: 1 + - TypeName: Conjure.Input.PlayerEnum, Assembly-CSharp + IsCustom: 0 + Emit: 1 + - TypeName: Obvious.Soap.ScriptableEventNoParam, Obvious.Soap + IsCustom: 0 + Emit: 1 + - TypeName: Obvious.Soap.Vector3Variable, Obvious.Soap + IsCustom: 0 + Emit: 1 diff --git a/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/InspectorConfig.asset b/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/InspectorConfig.asset index 323eb61c..5b650431 100644 --- a/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/InspectorConfig.asset +++ b/Assets/Plugins/Sirenix/Odin Inspector/Config/Editor/InspectorConfig.asset @@ -13,7 +13,7 @@ MonoBehaviour: m_Name: InspectorConfig m_EditorClassIdentifier: enableOdinInInspector: 1 - defaultEditorBehaviour: 15 + defaultEditorBehaviour: 11 processMouseMoveInInspector: 1 drawingConfig: configs: [] diff --git a/Assets/Scenes/Entry.unity b/Assets/Scenes/Entry.unity index 2ff6671a..3937b131 100644 --- a/Assets/Scenes/Entry.unity +++ b/Assets/Scenes/Entry.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.12731713, g: 0.13414738, b: 0.121078536, a: 1} + m_IndirectSpecularColor: {r: 0.12731749, g: 0.13414757, b: 0.1210787, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -273,6 +273,50 @@ Transform: type: 3} m_PrefabInstance: {fileID: 356792912} m_PrefabAsset: {fileID: 0} +--- !u!1 &908587195 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 908587197} + - component: {fileID: 908587196} + m_Layer: 0 + m_Name: ConjureGlobalObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &908587196 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 908587195} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 42abcca807f2495aa5d59ff8d0570ed6, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &908587197 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 908587195} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1111584621 GameObject: m_ObjectHideFlags: 0 @@ -383,7 +427,7 @@ MonoBehaviour: PrefabModificationsReferencedUnityObjects: [] PrefabModifications: [] SerializationNodes: [] - sceneToLoad: {fileID: 102900000, guid: c71ef66ffab2d95479284caa29000a51, type: 3} + scene: MainMenu --- !u!114 &2107510171 MonoBehaviour: m_ObjectHideFlags: 0 @@ -422,3 +466,4 @@ SceneRoots: m_Roots: - {fileID: 181845378} - {fileID: 320152712} + - {fileID: 908587197} diff --git a/Assets/Scenes/MainMenu.unity b/Assets/Scenes/MainMenu.unity index 28573fa5..76df49fb 100644 --- a/Assets/Scenes/MainMenu.unity +++ b/Assets/Scenes/MainMenu.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.1838259, g: 0.22910246, b: 0.30390218, a: 1} + m_IndirectSpecularColor: {r: 0.18382604, g: 0.22910279, b: 0.30390263, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -1486,14 +1486,13 @@ MonoBehaviour: type: 3} m_TargetAssemblyTypeName: Conjure.SceneNavigation, Assembly-CSharp m_MethodName: StartGame - m_Mode: 2 + m_Mode: 5 m_Arguments: - m_ObjectArgument: {fileID: 102900000, guid: a8881575ffff7b64dac12cdf05a8b5b4, - type: 3} - m_ObjectArgumentAssemblyTypeName: UnityEditor.SceneAsset, UnityEditor.CoreModule + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 - m_StringArgument: + m_StringArgument: Level1 m_BoolArgument: 0 m_CallState: 2 --- !u!114 &576113626 @@ -2474,7 +2473,7 @@ Canvas: m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 m_VertexColorAlwaysGammaSpace: 1 - m_AdditionalShaderChannelsFlag: 7 + m_AdditionalShaderChannelsFlag: 31 m_UpdateRectTransformForStandalone: 0 m_SortingLayerID: 0 m_SortingOrder: 0 diff --git a/Assets/Scripts/Conjure/Input/onLeaveEvent.asset b/Assets/ScriptableObjects/Events/onLeaveEvent.asset similarity index 100% rename from Assets/Scripts/Conjure/Input/onLeaveEvent.asset rename to Assets/ScriptableObjects/Events/onLeaveEvent.asset diff --git a/Assets/Scripts/Conjure/Input/onLeaveEvent.asset.meta b/Assets/ScriptableObjects/Events/onLeaveEvent.asset.meta similarity index 100% rename from Assets/Scripts/Conjure/Input/onLeaveEvent.asset.meta rename to Assets/ScriptableObjects/Events/onLeaveEvent.asset.meta diff --git a/Assets/Scripts/Conjure/GameInitialization/FirstSceneSelector.cs b/Assets/Scripts/Conjure/GameInitialization/FirstSceneSelector.cs index 766b44d7..6f91813c 100644 --- a/Assets/Scripts/Conjure/GameInitialization/FirstSceneSelector.cs +++ b/Assets/Scripts/Conjure/GameInitialization/FirstSceneSelector.cs @@ -10,11 +10,11 @@ namespace Conjure.GameInitialization public class FirstSceneSelector : SerializedMonoBehaviour { [Required] - [SerializeField] private SceneAsset sceneToLoad; + [SerializeField] private String scene; public void LoadFirstScene() { - SceneManager.LoadScene(sceneToLoad.name); + SceneManager.LoadScene(scene); } } } diff --git a/Assets/Scripts/Conjure/Input/GameJoiner.cs b/Assets/Scripts/Conjure/Input/GameJoiner.cs index db853673..27de91aa 100644 --- a/Assets/Scripts/Conjure/Input/GameJoiner.cs +++ b/Assets/Scripts/Conjure/Input/GameJoiner.cs @@ -1,71 +1,70 @@ using System; -using System.Collections; -using System.Collections.Generic; -using Conjure.Input; using Obvious.Soap; -using Obvious.Soap.Attributes; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.InputSystem; -public class GameJoiner : SerializedMonoBehaviour +namespace Conjure.Input { - [Required, SerializeField] - private ScriptableEventInt onJoinEvent; - [Required, SerializeField] - private ScriptableEventInt onLeaveEvent; - - [SerializeField, Required] - private InputServerReference inputManagerGameobjectReference; - - private InputManagerServer _inputManagerServer; - - private void Awake() + public class GameJoiner : SerializedMonoBehaviour { - if (inputManagerGameobjectReference.Value is not null) - { - _inputManagerServer = inputManagerGameobjectReference.Value.GetComponent(); - } + [Required, SerializeField] + private ScriptableEventInt onJoinEvent; + [Required, SerializeField] + private ScriptableEventInt onLeaveEvent; - if (_inputManagerServer is null) + [SerializeField, Required] + private InputServerReference inputManagerGameobjectReference; + + private InputManagerServer _inputManagerServer; + + private void Awake() { - throw new NullReferenceException( - $"The gameobject referenced by {inputManagerGameobjectReference.name} should have a InputManagerServer Component attached"); + if (inputManagerGameobjectReference.Value is not null) + { + _inputManagerServer = inputManagerGameobjectReference.Value.GetComponent(); + } + + if (_inputManagerServer is null) + { + throw new NullReferenceException( + $"The gameobject referenced by {inputManagerGameobjectReference.name} should have a InputManagerServer Component attached"); + } } - } - public void Join(InputAction.CallbackContext context) - { - InputDevice device = context.control.device; - - // CHECK IF MAPPED TO A PLAYER - if (_inputManagerServer.GetPlayerFromDeviceId(device.deviceId) != PlayerEnum.None) + public void Join(InputAction.CallbackContext context) { - return; + InputDevice device = context.control.device; + + // CHECK IF MAPPED TO A PLAYER + if (_inputManagerServer.GetPlayerFromDeviceId(device.deviceId) != PlayerEnum.None) + { + return; + } + + // TRY TO REGISTER IF THERE'S A SLOT FREE + PlayerEnum player = _inputManagerServer.RegisterDevice(device.deviceId); + if (player == PlayerEnum.None) + { + return; + } + + + onJoinEvent.Raise((int)player); } - // TRY TO REGISTER IF THERE'S A SLOT FREE - PlayerEnum player = _inputManagerServer.RegisterDevice(device.deviceId); - if (player == PlayerEnum.None) + public void Leave(InputAction.CallbackContext context) { - return; - } + InputDevice device = context.control.device; + PlayerEnum player = _inputManagerServer.GetPlayerFromDeviceId(device.deviceId); - onJoinEvent.Raise((int)player); - } - - - public void Leave(InputAction.CallbackContext context) - { - InputDevice device = context.control.device; - PlayerEnum player = _inputManagerServer.GetPlayerFromDeviceId(device.deviceId); - - if (player == PlayerEnum.None) - { - return; - } - _inputManagerServer.UnregisterDevice(device.deviceId); + if (player == PlayerEnum.None) + { + return; + } + _inputManagerServer.UnregisterDevice(device.deviceId); - onLeaveEvent.Raise((int)player); + onLeaveEvent.Raise((int)player); + } } } diff --git a/Assets/Scripts/Conjure/Input/InputManager.cs b/Assets/Scripts/Conjure/Input/InputManager.cs new file mode 100644 index 00000000..77f23d59 --- /dev/null +++ b/Assets/Scripts/Conjure/Input/InputManager.cs @@ -0,0 +1,24 @@ +using Obvious.Soap; +using Sirenix.OdinInspector; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace Conjure.Input +{ + public class InputManager : SerializedMonoBehaviour + { + [SerializeField] private PlayerEnum player = PlayerEnum.Player1; + [SerializeField] private Vector3Variable[] vectorVariables = new Vector3Variable[2]; + + [ReadOnly] + [BoxGroup("Debug")] + + public void OnMove(InputAction.CallbackContext context) + { + int id = context.control.device.deviceId; + + Vector2 direction = context.action.ReadValue(); + vectorVariables[(int)player].Value = new Vector3(direction.x, 0, direction.y); + } + } +} diff --git a/Assets/Scripts/Conjure/InputManager.cs.meta b/Assets/Scripts/Conjure/Input/InputManager.cs.meta similarity index 100% rename from Assets/Scripts/Conjure/InputManager.cs.meta rename to Assets/Scripts/Conjure/Input/InputManager.cs.meta diff --git a/Assets/Scripts/Conjure/Input/MenuInputManager.cs b/Assets/Scripts/Conjure/Input/MenuInputManager.cs new file mode 100644 index 00000000..a81dc776 --- /dev/null +++ b/Assets/Scripts/Conjure/Input/MenuInputManager.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using Sirenix.OdinInspector; +using UnityEngine; +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.UI; +using UnityEngine.InputSystem.Utilities; +using InputDevice = UnityEngine.InputSystem.InputDevice; + +namespace Conjure.Input +{ + public class MenuInputManager : SerializedMonoBehaviour + { + [SerializeField, Required] private InputSystemUIInputModule inputSystemUIInputModule; + [SerializeField, Required] private InputServerReference inputServerReference; + + // Start is called before the first frame update + void Start() + { + inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(); + } + + public void OnJoin(int playerSeat) + + { + if (inputSystemUIInputModule.actionsAsset.devices == null) + { + return; + } + + InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent(); + + List devices = + new List(inputSystemUIInputModule.actionsAsset.devices.Value.ToArray()); + + PlayerEnum player = inputManagerServer.GetPlayerFromInt(playerSeat); + + // shouldn't be reachable + if (player == PlayerEnum.None) + { + return; + } + + InputDevice currentDevice = FindDeviceById(inputManagerServer.GetDeviceIdFromPlayerEnum(player)); + + // shouldn't be reachable + if (currentDevice is not null) + { + devices.Add(currentDevice); + } + + inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(devices.ToArray()); + } + + public void OnLeave(int playerSeat) + { + if (inputSystemUIInputModule.actionsAsset.devices == null) + { + return; + } + + InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent(); + + if (playerSeat == 0 && inputManagerServer.GetNumberPlayers() == 0) + { + inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(); + return; + } + + InputDevice currentDevice = FindDeviceById(inputManagerServer.GetDeviceIdFromPlayerEnum(PlayerEnum.Player1)); + inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray(new []{currentDevice}); + } + + private InputDevice FindDeviceById(int deviceId) + { + foreach (InputDevice currentDevice in InputSystem.devices) + { + if (currentDevice.deviceId == deviceId) + { + return currentDevice; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/MenuInputManager.cs.meta b/Assets/Scripts/Conjure/Input/MenuInputManager.cs.meta similarity index 100% rename from Assets/MenuInputManager.cs.meta rename to Assets/Scripts/Conjure/Input/MenuInputManager.cs.meta diff --git a/Assets/Scripts/Conjure/InputManager.cs b/Assets/Scripts/Conjure/InputManager.cs deleted file mode 100644 index aad89602..00000000 --- a/Assets/Scripts/Conjure/InputManager.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Conjure.Input; -using Obvious.Soap; -using Sirenix.OdinInspector; -using UnityEngine; -using UnityEngine.InputSystem; - -public class InputManager : SerializedMonoBehaviour -{ - [SerializeField] private PlayerEnum player = PlayerEnum.Player1; - [SerializeField] private Vector3Variable[] vectorVariables = new Vector3Variable[2]; - - [ReadOnly] - [BoxGroup("Debug")] - - public void OnMove(InputAction.CallbackContext context) - { - int id = context.control.device.deviceId; - - Vector2 direction = context.action.ReadValue(); - vectorVariables[(int)player].Value = new Vector3(direction.x, 0, direction.y); - } -} diff --git a/Assets/Scripts/Conjure/JoinUi.cs b/Assets/Scripts/Conjure/JoinUi.cs new file mode 100644 index 00000000..b9f9cc0d --- /dev/null +++ b/Assets/Scripts/Conjure/JoinUi.cs @@ -0,0 +1,35 @@ +using System; +using Conjure.Input; +using Sirenix.OdinInspector; +using Obvious.Soap; +using UnityEngine; + +namespace Conjure +{ + public class JoinUi : SerializedMonoBehaviour + { + [SerializeField, ReadOnly] private InputManagerServer inputManagerServer; + [SerializeField, Required] private InputServerReference inputManagerGameobjectReference; + [SerializeField, Required] private EventListenerNoParam OnUpdateEvent; + + private void Awake() + { + if (inputManagerGameobjectReference is null) + { + throw new NullReferenceException($"inputManagerGameobjectReference shouldn't be null on {transform.name}"); + } + if (inputManagerGameobjectReference.Value is null) + { + throw new NullReferenceException($"inputManagerGameobjectReference shouldn't be null on {inputManagerGameobjectReference.name}"); + } + inputManagerServer = inputManagerGameobjectReference.Value.GetComponent(); + + //OnUpdateEvent.OnEventRaised(); + } + + private void UpdateVisual() + { + + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Conjure/JoinUi.cs.meta b/Assets/Scripts/Conjure/JoinUi.cs.meta new file mode 100644 index 00000000..0555ffac --- /dev/null +++ b/Assets/Scripts/Conjure/JoinUi.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6cfeb73d1adc480bb87433ceaa1b5387 +timeCreated: 1699897492 \ No newline at end of file diff --git a/Assets/Scripts/Conjure/SceneNavigation.cs b/Assets/Scripts/Conjure/SceneNavigation.cs index 19daf345..6dd8efd9 100644 --- a/Assets/Scripts/Conjure/SceneNavigation.cs +++ b/Assets/Scripts/Conjure/SceneNavigation.cs @@ -1,3 +1,4 @@ +using System; using Sirenix.OdinInspector; using UnityEditor; using UnityEngine; @@ -12,9 +13,9 @@ namespace Conjure Application.Quit(); } - public static void StartGame(SceneAsset scene) + public static void StartGame(String scene) { - SceneManager.LoadScene(scene.name); + SceneManager.LoadScene(scene); } } } diff --git a/Assets/Settings/Balanced_PipelineAsset.asset b/Assets/Settings/Balanced_PipelineAsset.asset index f7f7d685..3f8aeff3 100644 --- a/Assets/Settings/Balanced_PipelineAsset.asset +++ b/Assets/Settings/Balanced_PipelineAsset.asset @@ -82,33 +82,33 @@ MonoBehaviour: m_Textures: blueNoise64LTex: {fileID: 0} bayerMatrixTex: {fileID: 0} - m_PrefilteringModeMainLightShadows: 1 - m_PrefilteringModeAdditionalLight: 4 - m_PrefilteringModeAdditionalLightShadows: 1 - m_PrefilterXRKeywords: 0 - m_PrefilteringModeForwardPlus: 1 - m_PrefilteringModeDeferredRendering: 1 - m_PrefilteringModeScreenSpaceOcclusion: 1 - m_PrefilterDebugKeywords: 0 - m_PrefilterWriteRenderingLayers: 0 - m_PrefilterHDROutput: 0 - m_PrefilterSSAODepthNormals: 0 - m_PrefilterSSAOSourceDepthLow: 0 - m_PrefilterSSAOSourceDepthMedium: 0 - m_PrefilterSSAOSourceDepthHigh: 0 - m_PrefilterSSAOInterleaved: 0 - m_PrefilterSSAOBlueNoise: 0 - m_PrefilterSSAOSampleCountLow: 0 - m_PrefilterSSAOSampleCountMedium: 0 - m_PrefilterSSAOSampleCountHigh: 0 - m_PrefilterDBufferMRT1: 0 - m_PrefilterDBufferMRT2: 0 - m_PrefilterDBufferMRT3: 0 - m_PrefilterSoftShadowsQualityLow: 0 - m_PrefilterSoftShadowsQualityMedium: 0 - m_PrefilterSoftShadowsQualityHigh: 0 + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 2 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 m_PrefilterSoftShadows: 0 - m_PrefilterScreenCoord: 0 - m_PrefilterNativeRenderPass: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 diff --git a/Assets/Settings/High Fidelity_PipelineAsset.asset b/Assets/Settings/High Fidelity_PipelineAsset.asset index 8313bfa7..67b36b97 100644 --- a/Assets/Settings/High Fidelity_PipelineAsset.asset +++ b/Assets/Settings/High Fidelity_PipelineAsset.asset @@ -82,33 +82,33 @@ MonoBehaviour: m_Textures: blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} - m_PrefilteringModeMainLightShadows: 1 - m_PrefilteringModeAdditionalLight: 4 - m_PrefilteringModeAdditionalLightShadows: 1 - m_PrefilterXRKeywords: 0 - m_PrefilteringModeForwardPlus: 1 - m_PrefilteringModeDeferredRendering: 1 - m_PrefilteringModeScreenSpaceOcclusion: 1 - m_PrefilterDebugKeywords: 0 - m_PrefilterWriteRenderingLayers: 0 - m_PrefilterHDROutput: 0 - m_PrefilterSSAODepthNormals: 0 - m_PrefilterSSAOSourceDepthLow: 0 - m_PrefilterSSAOSourceDepthMedium: 0 - m_PrefilterSSAOSourceDepthHigh: 0 - m_PrefilterSSAOInterleaved: 0 - m_PrefilterSSAOBlueNoise: 0 - m_PrefilterSSAOSampleCountLow: 0 - m_PrefilterSSAOSampleCountMedium: 0 - m_PrefilterSSAOSampleCountHigh: 0 - m_PrefilterDBufferMRT1: 0 - m_PrefilterDBufferMRT2: 0 - m_PrefilterDBufferMRT3: 0 - m_PrefilterSoftShadowsQualityLow: 0 - m_PrefilterSoftShadowsQualityMedium: 0 - m_PrefilterSoftShadowsQualityHigh: 0 + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 2 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 m_PrefilterSoftShadows: 0 - m_PrefilterScreenCoord: 0 - m_PrefilterNativeRenderPass: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 diff --git a/Assets/Settings/Performant_PipelineAsset.asset b/Assets/Settings/Performant_PipelineAsset.asset index c1be73c1..14fb8ecb 100644 --- a/Assets/Settings/Performant_PipelineAsset.asset +++ b/Assets/Settings/Performant_PipelineAsset.asset @@ -82,33 +82,33 @@ MonoBehaviour: m_Textures: blueNoise64LTex: {fileID: 0} bayerMatrixTex: {fileID: 0} - m_PrefilteringModeMainLightShadows: 1 - m_PrefilteringModeAdditionalLight: 4 - m_PrefilteringModeAdditionalLightShadows: 1 - m_PrefilterXRKeywords: 0 - m_PrefilteringModeForwardPlus: 1 - m_PrefilteringModeDeferredRendering: 1 - m_PrefilteringModeScreenSpaceOcclusion: 1 - m_PrefilterDebugKeywords: 0 - m_PrefilterWriteRenderingLayers: 0 - m_PrefilterHDROutput: 0 - m_PrefilterSSAODepthNormals: 0 - m_PrefilterSSAOSourceDepthLow: 0 - m_PrefilterSSAOSourceDepthMedium: 0 - m_PrefilterSSAOSourceDepthHigh: 0 - m_PrefilterSSAOInterleaved: 0 - m_PrefilterSSAOBlueNoise: 0 - m_PrefilterSSAOSampleCountLow: 0 - m_PrefilterSSAOSampleCountMedium: 0 - m_PrefilterSSAOSampleCountHigh: 0 - m_PrefilterDBufferMRT1: 0 - m_PrefilterDBufferMRT2: 0 - m_PrefilterDBufferMRT3: 0 - m_PrefilterSoftShadowsQualityLow: 0 - m_PrefilterSoftShadowsQualityMedium: 0 - m_PrefilterSoftShadowsQualityHigh: 0 + m_PrefilteringModeMainLightShadows: 0 + m_PrefilteringModeAdditionalLight: 1 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 m_PrefilterSoftShadows: 0 - m_PrefilterScreenCoord: 0 - m_PrefilterNativeRenderPass: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 diff --git a/Packages/manifest.json b/Packages/manifest.json index c704f5c2..c8effb82 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,12 +1,12 @@ { "dependencies": { "com.unity.cinemachine": "2.9.7", - "com.unity.collab-proxy": "2.1.0", + "com.unity.collab-proxy": "2.2.0", "com.unity.connect.share": "4.2.3", "com.unity.feature.characters-animation": "1.0.0", "com.unity.feature.development": "1.0.1", "com.unity.ide.rider": "3.0.26", - "com.unity.ide.visualstudio": "2.0.21", + "com.unity.ide.visualstudio": "2.0.22", "com.unity.ide.vscode": "1.2.5", "com.unity.inputsystem": "1.7.0", "com.unity.localization": "1.4.5", @@ -15,7 +15,7 @@ "com.unity.render-pipelines.universal": "14.0.9", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.7.5", + "com.unity.timeline": "1.7.6", "com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.6", "com.unity.ugui": "1.0.0", "com.unity.visualscripting": "1.9.1", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index e349389d..a42a40a2 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -8,11 +8,11 @@ "url": "https://packages.unity.com" }, "com.unity.addressables": { - "version": "1.21.18", + "version": "1.21.19", "depth": 1, "source": "registry", "dependencies": { - "com.unity.scriptablebuildpipeline": "1.21.20", + "com.unity.scriptablebuildpipeline": "1.21.21", "com.unity.modules.assetbundle": "1.0.0", "com.unity.modules.imageconversion": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0", @@ -50,7 +50,7 @@ "url": "https://packages.unity.com" }, "com.unity.collab-proxy": { - "version": "2.1.0", + "version": "2.2.0", "depth": 0, "source": "registry", "dependencies": {}, @@ -97,7 +97,7 @@ "source": "builtin", "dependencies": { "com.unity.animation.rigging": "1.2.1", - "com.unity.timeline": "1.7.5", + "com.unity.timeline": "1.7.6", "com.unity.cinemachine": "2.9.5", "com.unity.formats.fbx": "4.2.1" } @@ -107,8 +107,8 @@ "depth": 0, "source": "builtin", "dependencies": { - "com.unity.ide.visualstudio": "2.0.21", - "com.unity.ide.rider": "3.0.25", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.rider": "3.0.26", "com.unity.ide.vscode": "1.2.5", "com.unity.editorcoroutines": "1.0.0", "com.unity.performance.profile-analyzer": "1.2.2", @@ -136,7 +136,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.21", + "version": "2.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -245,13 +245,13 @@ "source": "builtin", "dependencies": { "com.unity.mathematics": "1.2.1", - "com.unity.burst": "1.8.4", + "com.unity.burst": "1.8.9", "com.unity.render-pipelines.core": "14.0.9", "com.unity.shadergraph": "14.0.9" } }, "com.unity.scriptablebuildpipeline": { - "version": "1.21.20", + "version": "1.21.21", "depth": 2, "source": "registry", "dependencies": {}, @@ -327,7 +327,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.7.5", + "version": "1.7.6", "depth": 0, "source": "registry", "dependencies": { diff --git a/ProjectSettings/BurstAotSettings_StandaloneWindows.json b/ProjectSettings/BurstAotSettings_StandaloneWindows.json index 2144f6dc..36e6a2c0 100644 --- a/ProjectSettings/BurstAotSettings_StandaloneWindows.json +++ b/ProjectSettings/BurstAotSettings_StandaloneWindows.json @@ -1,16 +1,18 @@ { "MonoBehaviour": { - "Version": 3, + "Version": 4, "EnableBurstCompilation": true, "EnableOptimisations": true, "EnableSafetyChecks": false, "EnableDebugInAllBuilds": false, - "UsePlatformSDKLinker": false, + "DebugDataKind": 0, + "EnableArmv9SecurityFeatures": false, "CpuMinTargetX32": 0, "CpuMaxTargetX32": 0, "CpuMinTargetX64": 0, "CpuMaxTargetX64": 0, "CpuTargetsX32": 6, - "CpuTargetsX64": 72 + "CpuTargetsX64": 72, + "OptimizeFor": 0 } } diff --git a/ProjectSettings/CommonBurstAotSettings.json b/ProjectSettings/CommonBurstAotSettings.json index 3dffdba7..0293dafc 100644 --- a/ProjectSettings/CommonBurstAotSettings.json +++ b/ProjectSettings/CommonBurstAotSettings.json @@ -1,6 +1,6 @@ { "MonoBehaviour": { - "Version": 3, + "Version": 4, "DisabledWarnings": "" } } diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 1033c195..944958e7 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -12,7 +12,7 @@ PlayerSettings: targetDevice: 2 useOnDemandResources: 0 accelerometerFrequency: 60 - companyName: DefaultCompany + companyName: Conjure productName: Overmelted defaultCursor: {fileID: 0} cursorHotspot: {x: 0, y: 0} @@ -48,6 +48,7 @@ PlayerSettings: defaultScreenHeightWeb: 600 m_StereoRenderingPath: 0 m_ActiveColorSpace: 1 + unsupportedMSAAFallback: 0 m_SpriteBatchVertexThreshold: 300 m_MTRendering: 1 mipStripping: 0 @@ -563,7 +564,6 @@ PlayerSettings: switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 switchEnableFileSystemTrace: 0 - switchUseGOLDLinker: 0 switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 37f39b7b..91206fdc 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2022.3.11f1 -m_EditorVersionWithRevision: 2022.3.11f1 (d00248457e15) +m_EditorVersion: 2022.3.13f1 +m_EditorVersionWithRevision: 2022.3.13f1 (5f90a5ebde0f) diff --git a/ProjectSettings/ShaderGraphSettings.asset b/ProjectSettings/ShaderGraphSettings.asset index 9b28428b..3250b068 100644 --- a/ProjectSettings/ShaderGraphSettings.asset +++ b/ProjectSettings/ShaderGraphSettings.asset @@ -12,5 +12,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3} m_Name: m_EditorClassIdentifier: + shaderVariantLimit: 128 customInterpolatorErrorThreshold: 32 customInterpolatorWarningThreshold: 16