Added the main menu

This commit is contained in:
jimmy tremblay-bernier 2023-11-13 15:56:39 -05:00 committed by Jimmy Tremblay-Bernier
parent 6b53e212d5
commit 75d191dfae
85 changed files with 3062 additions and 287 deletions

55
.vscode/settings.json vendored Normal file
View File

@ -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
}
}

View File

@ -1,7 +1,8 @@
fileFormatVersion: 2
guid: cc355dd4cf1e6173beaeb22c2858cbe1
timeCreated: 1488828285
guid: df1387ab23758dd4f9e36ec1aab17005
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,7 +1,8 @@
fileFormatVersion: 2
guid: f597f19f656ba56eae4f6a3a7cc528f4
timeCreated: 1488828285
guid: d4c9b5af1f2acb5498e569269f0c75c4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 21d4daaf24a1497b942bb1c26aaad40b
timeCreated: 1697466850

View File

@ -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();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42abcca807f2495aa5d59ff8d0570ed6
timeCreated: 1697466858

View File

@ -1,7 +1,8 @@
fileFormatVersion: 2
guid: 48e08dc33330d11e9d4a1b246c52e4f6
timeCreated: 1488828285
guid: c2ef9ab0502fe5b4b981fc372678110e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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.";
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ccef78ea2487524fb2c803e16661a6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 35055e949c56f364fb3146744c04237c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6700d94db788419897417a8bed51208a
timeCreated: 1697466157

View File

@ -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);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 039be1ac3aad4e8ebe52affd281ad81c
timeCreated: 1697466243

View File

@ -1,7 +1,8 @@
fileFormatVersion: 2
guid: ed09910c0094cb27be8f3ca264680da3
timeCreated: 1488828285
guid: 86ca34d4ff4ff724c962255b02e88d47
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<ConjureArcadeController> OnControllerAdded;
public static event Action<ConjureArcadeController> 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;
/// <summary>
/// The controller index of this specific Conjure Arcade Controller.
/// The value will be between 0 and <see cref="ControllerCount"/> - 1.
/// If the value is -1, it means this controller was not initialized correctly and is not valid.
/// </summary>
public int ControllerIndex
{
get
{
try
{
return allInstances.IndexOf(this);
}
catch (ArgumentOutOfRangeException)
{
return -1;
}
}
}
/// <summary>
/// Whether or not a Conjure Arcade Controller exist for the following index.
/// </summary>
public static bool ExistForIndex(int controllerIndex)
{
return allInstances.Exists(instance => instance.ControllerIndex == controllerIndex);
}
/// <summary>
/// Get the Conjure Arcade Controller associated with the specific controller index.
/// </summary>
/// <returns>The controller if it exist for the specific index or null if it does not exist.</returns>
public static ConjureArcadeController GetForIndex(int controllerIndex)
{
return allInstances.Find(instance => instance.ControllerIndex == controllerIndex);
}
protected override void FinishSetup()
{
stick = GetChildControl<ConjureArcadeStickControl>("stick");
home = GetChildControl<ButtonControl>("home");
start = GetChildControl<ButtonControl>("start");
button1 = GetChildControl<ButtonControl>("button1");
button2 = GetChildControl<ButtonControl>("button2");
button3 = GetChildControl<ButtonControl>("button3");
buttonA = GetChildControl<ButtonControl>("buttonA");
buttonB = GetChildControl<ButtonControl>("buttonB");
buttonC = GetChildControl<ButtonControl>("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<ConjureArcadeController> allInstances = new();
}
}
#endif

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 84cdd6b6829c4f5e9e31a78f96d5b9b8
timeCreated: 1695757344

View File

@ -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,
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e67d24a4d1184f43933bdd96b2720cbd
timeCreated: 1695758710

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c07dbb7bcebd4245be59b93c86cee5fd
timeCreated: 1695758555

View File

@ -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<ButtonControl>("up");
down = GetChildControl<ButtonControl>("down");
left = GetChildControl<ButtonControl>("left");
right = GetChildControl<ButtonControl>("right");
}
}
}
#endif

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef8fe9c76d3e4dcda92b275b68348e8e
timeCreated: 1695780776

View File

@ -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<Vector2>
{
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<float>
{
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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a2261cfa8c104770bad23d12a5194f9c
timeCreated: 1695774290

View File

@ -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<ConjureArcadeStickControl>("ConjureArcadeStick");
InputSystem.RegisterLayout<ConjureArcadeController>(
matches: new InputDeviceMatcher()
.WithInterface(ConjureArcadeControllerInfo.Interface)
.WithProduct(ConjureArcadeControllerInfo.Product));
#endif
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c4f9c6e992674c1bbcb497a7e194b0c6
timeCreated: 1695755563

View File

@ -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
{
/// <summary>
/// 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.
/// </summary>
/// <param name="keepOtherDevices">
/// 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.
/// </param>
public static void AssignConjureController(this InputActionAsset inputActionAsset, int controllerIndex, bool keepOtherDevices = true)
{
List<InputDevice> inputDevices = new List<InputDevice>();
if (keepOtherDevices)
{
if (inputActionAsset.devices == null)
{
inputDevices.AddRange(InputSystem.devices);
}
else
{
inputDevices = new List<InputDevice>(inputActionAsset.devices);
}
inputDevices.RemoveAll(inputDevice => inputDevice is ConjureArcadeController);
}
ConjureArcadeController controller = ConjureArcadeController.GetForIndex(controllerIndex);
if (controller != null)
{
inputDevices.Add(controller);
}
inputActionAsset.devices = inputDevices.ToArray();
}
/// <summary>
/// Whether or not it is possible to assign a specific controller index to this Input Action Asset.
/// </summary>
public static bool CanAssignConjureController(this InputActionAsset inputActionAsset, int controllerIndex)
{
return ConjureArcadeController.ExistForIndex(controllerIndex);
}
/// <summary>
/// Get the controller index of the Conjure Arcade Controller associated with this Input Action Asset.
/// </summary>
/// <returns>
/// 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.
/// </returns>
public static int GetConjureControllerIndex(this InputActionAsset inputActionAsset)
{
ConjureArcadeController[] controllers = GetConjureArcadeControllersFromDevices(inputActionAsset.devices);
if (controllers.Length == 0)
{
return -1;
}
return controllers[0].ControllerIndex;
}
/// <summary>
/// Get the controller index of all the Conjure Arcade Controllers associated with this Input Action Asset.
/// </summary>
/// <returns>
/// The controller indexes found.
/// If there was no Conjure Arcade Controller associated with this Input Action Asset, return an empty array.
/// </returns>
public static int[] GetConjureControllerIndexes(this InputActionAsset inputActionAsset)
{
ConjureArcadeController[] controllers = GetConjureArcadeControllersFromDevices(inputActionAsset.devices);
return controllers.Select(controller => controller.ControllerIndex).ToArray();
}
private static ConjureArcadeController[] GetConjureArcadeControllersFromDevices(ReadOnlyArray<InputDevice>? devices)
{
if (devices == null)
{
return ConjureArcadeController.allControllers;
}
List<ConjureArcadeController> controllers = new List<ConjureArcadeController>();
foreach (InputDevice inputDevice in devices)
{
if (inputDevice is ConjureArcadeController device)
{
controllers.Add(device);
}
}
return controllers.ToArray();
}
}
}
#endif

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ce5f252f61584da1be15a1aed6373337
timeCreated: 1697552346

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6fb8b8a42abb6ff4aa3af61ff2fa57a6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b9cd8c3ac9c7ce34896c85d0fcd2aa5c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
/// <summary>
/// Updates all uneditable settings
/// </summary>
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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6977c269ceb8edc4298ee30193e8a838
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<int> developersErrorIndex = new List<int>(); // Used to indicate which index have an error
public List<int> DevelopersErrorIndex => developersErrorIndex;
private int errorCount = -1; // Starts at -1 because no validation have been done yet
public int ErrorCount => errorCount;
/// <summary>
/// Validate the specified game metadata
/// </summary>
/// <param name="metadata">The metadata to be validated</param>
/// <returns>Return true if metadata are valid. Otherwise, returns false.</returns>
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 };
}
/// <summary>
/// Validate a developers list
/// </summary>
/// <param name="developers">The developers list to be analyzed</param>
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++;
}
}
}
/// <summary>
/// </summary>
/// <returns>Returns the validation state based on the current amount of errors detected</returns>
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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: edace48768db8a54e8806e8d703c6efa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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>(ConjureArcadeMetadata.MetadataAssetPath);
// Data exists
if (metadata)
{
return;
}
metadata = CreateInstance<ConjureArcadeMetadata>();
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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0cfd6670cf89b984bb971537d740f4c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,10 @@
using System;
namespace ConjureOS.MetadataWindow
{
[Serializable]
public struct GameGenre
{
public int selectedGenre;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2bf07614a284e334b8300836f4365f78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
namespace ConjureOS.MetadataWindow
{
public enum MetadataValidationStateType
{
NotVerified,
Validated,
Failed
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 90c3d1fd9b921034c964891b00a1594c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 696a1ff0be1f41e439b3185025356f09
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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>(ConjureArcadeMetadata.MetadataAssetPath);
// Data exists
if (metadata)
{
return;
}
metadata = CreateInstance<ConjureArcadeMetadata>();
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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd1c153b5930bca4aa2b62c24b229838
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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";
/// <summary>
/// Build and upload the game to the web server.
/// Must use valid Conjure Arcade metadata, or the process will fail.
/// </summary>
/// <param name="metadata">The Conjure Arcade metadata of the game</param>
/// <param name="metadataValidator">The metadata validator</param>
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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 67065d97fd394ab428022e93d776bcac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Gameplay.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

127
Assets/Gameplay.PNG.meta Normal file
View File

@ -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:

BIN
Assets/Gameplay.jpg (Stored with Git LFS) Normal file

Binary file not shown.

127
Assets/Gameplay.jpg.meta Normal file
View File

@ -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:

View File

@ -47,6 +47,17 @@
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "56e35fc7-3515-47d8-b863-76845c6f4447",
"path": "<ConjureArcadeController>/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": "<ConjureArcadeController>/button2",
"interactions": "",
"processors": "",
"groups": "",
"action": "Leave",
"isComposite": false,
"isPartOfComposite": false
}
]
}

View File

@ -118,6 +118,17 @@
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "b714db0b-e69a-4f21-938e-4f18ee1dc89d",
"path": "<ConjureArcadeController>/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": "<ConjureArcadeController>/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": "<ConjureArcadeController>/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": "<ConjureArcadeController>/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": "<ConjureArcadeController>/buttonA",
"interactions": "",
"processors": "",
"groups": "",
"action": "SwitchPlayer",
"isComposite": false,
"isPartOfComposite": false
}
]
}

View File

@ -317,6 +317,17 @@
"isComposite": false,
"isPartOfComposite": true
},
{
"name": "",
"id": "eb39813a-66de-41e9-a7ee-f6b5ab305254",
"path": "<ConjureArcadeController>/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": "<ConjureArcadeController>/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": "<ConjureArcadeController>/button2",
"interactions": "",
"processors": "",
"groups": "",
"action": "Cancel",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "6134beac-34df-4c4a-ae23-e5fac7cc7b2e",

BIN
Assets/MainMenu.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

127
Assets/MainMenu.PNG.meta Normal file
View File

@ -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:

BIN
Assets/MainMenu.jpg (Stored with Git LFS) Normal file

Binary file not shown.

127
Assets/MainMenu.jpg.meta Normal file
View File

@ -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:

View File

@ -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<InputDevice>();
}
public void OnJoin(int playerSeat)
{
if (inputSystemUIInputModule.actionsAsset.devices == null)
{
return;
}
InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent<InputManagerServer>();
List<InputDevice> devices =
new List<InputDevice>(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<InputDevice>(devices.ToArray());
}
public void OnLeave(int playerSeat)
{
if (inputSystemUIInputModule.actionsAsset.devices == null)
{
return;
}
InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent<InputManagerServer>();
if (playerSeat == 0 && inputManagerServer.GetNumberPlayers() == 0)
{
inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray<InputDevice>();
return;
}
InputDevice currentDevice = FindDeviceById(inputManagerServer.GetDeviceIdFromPlayerEnum(PlayerEnum.Player1));
inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray<InputDevice>(new []{currentDevice});
}
private InputDevice FindDeviceById(int deviceId)
{
foreach (InputDevice currentDevice in InputSystem.devices)
{
if (currentDevice.deviceId == deviceId)
{
return currentDevice;
}
}
return null;
}
}

View File

@ -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

View File

@ -13,7 +13,7 @@ MonoBehaviour:
m_Name: InspectorConfig
m_EditorClassIdentifier:
enableOdinInInspector: 1
defaultEditorBehaviour: 15
defaultEditorBehaviour: 11
processMouseMoveInInspector: 1
drawingConfig:
configs: []

View File

@ -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}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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<InputManagerServer>();
}
[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<InputManagerServer>();
}
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);
}
}
}

View File

@ -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<Vector2>();
vectorVariables[(int)player].Value = new Vector3(direction.x, 0, direction.y);
}
}
}

View File

@ -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<InputDevice>();
}
public void OnJoin(int playerSeat)
{
if (inputSystemUIInputModule.actionsAsset.devices == null)
{
return;
}
InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent<InputManagerServer>();
List<InputDevice> devices =
new List<InputDevice>(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<InputDevice>(devices.ToArray());
}
public void OnLeave(int playerSeat)
{
if (inputSystemUIInputModule.actionsAsset.devices == null)
{
return;
}
InputManagerServer inputManagerServer = inputServerReference.Value.GetComponent<InputManagerServer>();
if (playerSeat == 0 && inputManagerServer.GetNumberPlayers() == 0)
{
inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray<InputDevice>();
return;
}
InputDevice currentDevice = FindDeviceById(inputManagerServer.GetDeviceIdFromPlayerEnum(PlayerEnum.Player1));
inputSystemUIInputModule.actionsAsset.devices = new ReadOnlyArray<InputDevice>(new []{currentDevice});
}
private InputDevice FindDeviceById(int deviceId)
{
foreach (InputDevice currentDevice in InputSystem.devices)
{
if (currentDevice.deviceId == deviceId)
{
return currentDevice;
}
}
return null;
}
}
}

View File

@ -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<Vector2>();
vectorVariables[(int)player].Value = new Vector3(direction.x, 0, direction.y);
}
}

View File

@ -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<InputManagerServer>();
//OnUpdateEvent.OnEventRaised();
}
private void UpdateVisual()
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6cfeb73d1adc480bb87433ceaa1b5387
timeCreated: 1699897492

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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": {

View File

@ -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
}
}

View File

@ -1,6 +1,6 @@
{
"MonoBehaviour": {
"Version": 3,
"Version": 4,
"DisabledWarnings": ""
}
}

View File

@ -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:

View File

@ -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)

View File

@ -12,5 +12,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3}
m_Name:
m_EditorClassIdentifier:
shaderVariantLimit: 128
customInterpolatorErrorThreshold: 32
customInterpolatorWarningThreshold: 16