Skip to content

Commit

Permalink
Merge pull request #4 from chark/bugfix/automatix-isntantiation
Browse files Browse the repository at this point in the history
Fix automatic isntantiation
  • Loading branch information
Edvinas01 authored Oct 6, 2023
2 parents c28434b + aef3d6d commit 343a565
Show file tree
Hide file tree
Showing 48 changed files with 830 additions and 341 deletions.
1 change: 0 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
root = true

[*]
max_line_length = 100
indent_style = space
indent_size = 4
charset = utf-8
Expand Down
8 changes: 7 additions & 1 deletion .github/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Game Management

[![Unity 2022.3+](https://img.shields.io/badge/unity-2022.3%2B-blue.svg)](https://unity3d.com/get-unity/download)
[![openupm](https://img.shields.io/npm/v/com.chark.game-management?label=openupm&registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.chark.game-management/)
[![Actions Status](https://github.com/chark/game-management/workflows/CI/badge.svg)](https://github.com/chark/game-management/actions)

Essential, minimalistic and code-first Game Management tools. Perfect for game-jams and medium-sized projects.
Expand Down Expand Up @@ -34,7 +35,12 @@ internal class MyGameManager : GameManager

## Installation

This package can be installed via the Package Manager by [Installing from a Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html):
This package can be installed via [OpenUPM](https://openupm.com/packages/com.chark.game-management):
```text
openupm add com.chark.game-management
```

Or via the Unity Package Manager by [Installing from a Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html):

```text
https://github.com/chark/game-management.git#upm
Expand Down
8 changes: 8 additions & 0 deletions Assets/Settings.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions Assets/Settings/GameManagerSettings.asset
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
%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: 4f41518ec4cd48f0977f72ee2845e8ee, type: 3}
m_Name: GameManagerSettings
m_EditorClassIdentifier:
profiles:
- {fileID: 11400000, guid: 52ae552f66999ab44a599fe9a5a43d3f, type: 2}
- {fileID: 11400000, guid: 35028f3c7e1cd994dadac07385689622, type: 2}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion Packages/com.chark.game-management/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.0.2](https://github.com/chark/game-management/compare/v0.0.1...v0.0.2) - 2023-XX-XX
## [v0.0.2](https://github.com/chark/game-management/compare/v0.0.1...v0.0.2) - 2023-10-06

### Added

- `GameManagerSettingsProfile` which can be used to load a specific `GameManager` configuration via `GameManagerSettings`.
- Better logging with a custom log message format.
- Property Drawer for `GameManagerSettingsProfile`, this way it's easier to manage lists of profiles.

### Changed

- `GameManagerSettings` will now be automatically created at `Assets/Settings/GameManagerSettings.asset` and added to preloaded asset list (you can move it later). This is needed to support automatic instantiation as previously using `Resources.FindObjectsOfTypeAll` was not working in builds.
- `GameManagerSettings` class visibility is now `private`.
- `GameManager` static methods will now throw an `Exception` if it's not initialized instead of just logging an error and pausing.
- Automatic `GameManager` instantiation now only supports loading **before** and **after** scene load.
- Menu item order to use `150` instead of `-1000`. This way `CHARK` won't dominate existing entries.

### Removed

- `GameManager.GetGameManagerSettings` method as a new profile system will be used instead. Overriding this doesn't make sense anymore.

## [v0.0.1](https://github.com/chark/game-management/compare/v0.0.1) - 2023-10-04

Initial preview version.
Expand Down
37 changes: 23 additions & 14 deletions Packages/com.chark.game-management/Documentation~/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

[Game Manager]: ../Runtime/GameManager.cs
[Game Manager Settings]: ../Runtime/GameManagerSettings.cs
[Game Manager Settings Profile]: ../Runtime/Settings/GameManagerSettingsProfile.cs

[Default Game Manager]: ../Samples%7E/Defaults/Scripts/DefaultGameManager.cs
[Default Game Manager Prefab]: ../Samples%7E/Defaults/Prefabs/DefaultGameManager.prefab
[Default Game Manager Settings]: ../Samples%7E/Defaults/Resources/DefaultGameManagerSettings.asset
[Default Game Manager Settings Profile]: ../Samples%7E/Defaults/Resources/DefaultGameManagerSettingsProfile.asset

[SimpleSystem]: ../Runtime/Systems/SimpleSystem.cs
[MonoSystem]: ../Runtime/Systems/MonoSystem.cs
Expand All @@ -35,25 +36,38 @@ Open [Unity Package Manager], select _Game Management_ package and import [Defau
This will import:

- [Default Game Manager] - script which can be used as a template for your custom game manager.
- [Default Game Manager Prefab] - prefab which can be used as a template for your custom game manager. By default, it has the [Default Game Manager] component.
- [Default Game Manager Settings] - settings asset used to define how the [Default Game Manager] should load.
- [Default Game Manager Prefab] - prefab which can be used as a template for your game manager prefab.
- [Default Game Manager Settings Profile] - asset which defines how the [Default Game Manager] should load.

After importing, hit play and the [Default Game Manager] should instantiate and be ready to go!
After importing, open the [Game Manager Settings] asset (located at `Assets/Settings/GameManagerSettings.asset` by default) and add [Default Game Manager Settings Profile] to the **Profiles** field. Also make sure this profile is active:

<p align="center">
<img hspace="2%" src="game-manager-settings.png"/>
</p>

Run the game!

## Game Manager Settings

Regardless if you use a [Game Manager] from [Samples~] or a custom one, you'll need to define a [Game Manager Settings] asset. This asset will be created automatically in `Resources` directory by the game management code. However, if that doesn't happen, right-click anywhere in the _Project Window_ and select _Create/CHARK/Game Management/Game Manager Settings_ and create it manually:
[Game Manager Settings] asset will be created automatically for you when you install this package. The default location is at `Assets/Settings/GameManagerSettings.asset` but you can move it anywhere in your project.

[Game Manager Settings] asset defines which [Game Manager] should load and how. If there are more than one profiles added to this asset, the first profile which is active will be used. If no profiles are active or the list is empty, a no-op default profile will be utilized.

When you create this asset for the first time, it will have no **Profiles** added. To override the defaults you'll need to define a custom [Game Manager Settings Profile] asset, configure it and add to this list. You can create [Game Manager Settings Profile] assets the following way:

- Right-click anywhere in the _Project Window_ and select _Create/CHARK/Game Management/Game Manager Settings Profile_.
- Add it to the [Game Manager Settings] asset **Profiles** list.

<p align="center">
<img src="settings.png"/>
<img hspace="2%" src="game-manager-settings-profile.png"/>
</p>

Available properties for customization:
Available properties for customization on [Game Manager Settings Profile]:

- **Is Active Settings** - useful when you have multiple [Game Manager Settings] assets. You can use this field to define which settings asset should be used.
- **Is Active Profile** - useful when you have multiple [Game Manager Settings Profile] assets. You can use this field to define which settings asset should be used.
- **Is Instantiate Automatically** - should [Game Manager] be instantiated automatically when the game starts. Disable this if you want to manage the lifecycle manually.
- **Instantiation Mode** - when to load the [Game Manager], for more info see [InitializeOnLoadAttribute](https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html).
- **Game Manager Prefab** - [Game Manager] prefab to instantiate when the game starts, used when **Is Instantiate Automatically** is set to `true`.
- **Load Type** - when to load the [Game Manager], for more info see [InitializeOnLoadAttribute](https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html).

## Scripting

Expand Down Expand Up @@ -93,11 +107,6 @@ internal sealed class MyGameManager : GameManager
return "My Game Manager";
}

protected override IGameManagerSettings GetGameManagerSettings()
{
// Provide custom settings implementation
}

protected override IGameStorage CreateRuntimeGameStorage()
{
// Provide a custom storage implementation
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
3 changes: 3 additions & 0 deletions Packages/com.chark.game-management/Editor.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "CHARK.GameManagement.Editor",
"rootNamespace": "CHARK.GameManagement",
"references": [
"CHARK.GameManagement"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Packages/com.chark.game-management/Editor/Settings.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CHARK.GameManagement.Settings;
using CHARK.GameManagement.Utilities;
using UnityEditor;
using UnityEngine;

namespace CHARK.GameManagement.Editor.Settings
{
/// <summary>
/// Creates game manager settings assets if they're missing and adds them to preloaded assets.
/// By using this approach, <see cref="GameManagerSettings"/> can be loaded using
/// <see cref="Resources.FindObjectsOfTypeAll{T}"/> during runtime (and in builds).
/// </summary>
internal static class GameManagerSettingsCreator
{
private const string DefaultSettingsAssetPath = "Assets/Settings/GameManagerSettings.asset";

[InitializeOnLoadMethod]
private static void OnInitializeEditor()
{
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;

UpdatePreloadedAssets();
}

private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingEditMode)
{
// We also need to update on play-mode change, otherwise assets added to preloaded
// list after hitting the play button will not persist.
UpdatePreloadedAssets();
}
}

private static void UpdatePreloadedAssets()
{
if (IsSettingsAssetPreloaded())
{
return;
}

if (TrgGetSettingsAsset(out var existingAsset))
{
PreloadSettingsAsset(existingAsset);
}
else
{
var newAsset = CreateSettingsAsset();
PreloadSettingsAsset(newAsset);
}
}

private static bool IsSettingsAssetPreloaded()
{
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
foreach (var preloadedAsset in preloadedAssets)
{
if (preloadedAsset && preloadedAsset is GameManagerSettings)
{
return true;
}
}

return false;
}

private static bool TrgGetSettingsAsset(out GameManagerSettings asset)
{
var existingAsset = AssetDatabase
.FindAssets($"t:{nameof(GameManagerSettings)}")
.Select(AssetDatabase.GUIDToAssetPath)
.Select(AssetDatabase.LoadAssetAtPath<GameManagerSettings>)
.FirstOrDefault();

if (existingAsset)
{
asset = existingAsset;
return true;
}

asset = default;
return false;
}

private static void PreloadSettingsAsset(GameManagerSettings asset)
{
var preloadedAssets = PlayerSettings.GetPreloadedAssets().ToList();
if (preloadedAssets.Contains(asset))
{
return;
}

preloadedAssets.Add(asset);

PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
}

private static GameManagerSettings CreateSettingsAsset()
{
var settings = ScriptableObject.CreateInstance<GameManagerSettings>();
settings.AddProfiles(GetAvailableProfilesEditor());

var directoryName = Path.GetDirectoryName(DefaultSettingsAssetPath);
if (string.IsNullOrWhiteSpace(directoryName) == false && Directory.Exists(directoryName) == false)
{
Directory.CreateDirectory(directoryName);
}

AssetDatabase.CreateAsset(settings, DefaultSettingsAssetPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

Logging.LogDebug(
""
+ $"Created new {nameof(GameManagerSettings)} at {DefaultSettingsAssetPath},"
+ $" you can move this asset to a any directory and rename it as you'd like."
+ $" <b>Make sure to add {nameof(GameManagerSettingsProfile)} to this asset!</b>",
settings
);

return settings;
}

private static IEnumerable<GameManagerSettingsProfile> GetAvailableProfilesEditor()
{
return AssetDatabase
.FindAssets($"t:{nameof(GameManagerSettingsProfile)}")
.Select(AssetDatabase.GUIDToAssetPath)
.Select(AssetDatabase.LoadAssetAtPath<GameManagerSettingsProfile>);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using CHARK.GameManagement.Settings;
using UnityEditor;
using UnityEngine;

namespace CHARK.GameManagement.Editor.Settings
{
[CustomPropertyDrawer(typeof(GameManagerSettingsProfile))]
internal sealed class GameManagerSettingsProfilePropertyDrawer : PropertyDrawer
{
private const float ToggleWidth = 16f;

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var profile = property.objectReferenceValue as GameManagerSettingsProfile;
EditorGUI.BeginProperty(position, label, property);

var initialColor = GUI.backgroundColor;
if (profile && profile.IsActiveProfile)
{
GUI.backgroundColor = Color.green;
}

// Active toggle
EditorGUI.BeginChangeCheck();

var togglePosition = position;
togglePosition.width = ToggleWidth;

var isActiveProfileNew = profile
? EditorGUI.Toggle(togglePosition, profile.IsActiveProfile)
: EditorGUI.Toggle(togglePosition, false);

if (EditorGUI.EndChangeCheck() && profile)
{
profile.IsActiveProfile = isActiveProfileNew;
}

// Profile object field
var propertyPosition = position;
propertyPosition.width -= ToggleWidth;
propertyPosition.x += ToggleWidth;

EditorGUI.PropertyField(propertyPosition, property, new GUIContent("Profile"));
GUI.backgroundColor = initialColor;

EditorGUI.EndProperty();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 343a565

Please sign in to comment.