Перейти к основному содержимому

Foundation Services

Слой OpenMon.Foundation — это общий фреймворк, на котором держится весь движок: внедрение зависимостей, персистентность, управление сценами и локализация. Эти интерфейсы стабильны, внедряемы через Zenject и переиспользуемы в ваших собственных системах. Эта страница документирует три сервисных интерфейса плюс два DI-помощника, от которых вы чаще всего наследуетесь.

Foundation не зависит от движка

Ничто в OpenMon.Foundation не знает о монстрах или боях. Внедрение этих интерфейсов (а не конкретных реализаций) сохраняет ваш код тестируемым и позволяет движку менять реализации, не ломая вас.

IPersister​

Namespace: OpenMon.Foundation.Persistence

Абстракция хранилища за каждым сохранением. Реализации (JsonFilePersister, ConfigurationJsonFilePersister, …) решают, куда попадают байты; вызывающие имеют дело только с типизированными сохранением/загрузкой.

public interface IPersister
{
bool Save<TOriginal>(TOriginal data, string destination, bool suppressErrors = false);
bool Load<TOriginal>(out TOriginal data, string origin, bool suppressErrors = false);
}

Save<TOriginal>(TOriginal data, string destination, bool suppressErrors = false)​

Сериализует data в destination.

ПараметрТипОписание
dataTOriginalСохраняемый объект
destinationstringКуда записать
suppressErrorsboolНе логировать ошибки — полезно для систем, работающих и при отсутствии ресурса (например, менеджер конфигурации, читающий отсутствующий конфиг при первом запуске)

Возвращает: bool — true при успехе.

Load<TOriginal>(out TOriginal data, string origin, bool suppressErrors = false)​

Десериализует из origin в data.

ПараметрТипОписание
dataout TOriginalПолучает загруженный объект
originstringОткуда читать
suppressErrorsboolНе логировать ошибки, когда ресурс может законно отсутствовать

Возвращает: bool — true при успехе (отсутствующий файл возвращает false, а не исключение).

ISceneManager​

Namespace: OpenMon.Foundation.SceneManagement

Оборачивает SceneManager Unity, добавляя отслеживание загруженных сцен, проверку доступности и рассылку событий. Сцены адресуются через SceneReference или по имени.

public interface ISceneManager
{
List<string> LoadedScenes { get; }
string[] SceneNames { get; }

bool IsSceneAvailable(SceneReference scene);
bool IsSceneAvailable(string scene);

void LoadScene(SceneReference sceneReference, Action<float> progressCallback,
Action<bool> callback, LoadSceneMode mode = LoadSceneMode.Additive);
void LoadScene(string sceneName, Action<float> progressCallback,
Action<bool> callback, LoadSceneMode mode = LoadSceneMode.Additive);

void UnloadScene(SceneReference sceneReference, Action<float> progressCallback, Action<bool> callback);
void UnloadScene(string sceneName, Action<float> progressCallback, Action<bool> callback);

Scene GetActiveScene();
string GetActiveSceneName();
void SetActiveScene(SceneReference scene);
void SetActiveScene(string sceneName);

void MoveObjectToActiveScene(GameObject gameObject);
void MoveObjectToScene(GameObject gameObject, SceneReference scene);
void MoveObjectToScene(GameObject gameObject, string scene);
}

LoadedScenes​

Имена всех загруженных на данный момент сцен.

Тип: List<string> (только чтение)

SceneNames​

Все известные имена сцен — как в Build Settings, так и addressable.

Тип: string[] (только чтение)

IsSceneAvailable(SceneReference scene)​

Можно ли действительно загрузить сцену (присутствует ли её ассет). Перегрузка принимает имя сцены.

Возвращает: bool.

LoadScene(SceneReference sceneReference, Action<float> progressCallback, Action<bool> callback, LoadSceneMode mode = LoadSceneMode.Additive)​

Загружает сцену, сообщая прогресс через progressCallback и успех через callback. По умолчанию Additive, чтобы стартовая/постоянная сцена оставалась загруженной. Есть перегрузка по имени.

UnloadScene(SceneReference sceneReference, Action<float> progressCallback, Action<bool> callback)​

Выгружает сцену, сообщая прогресс и успех. Есть перегрузка по имени.

GetActiveScene() / GetActiveSceneName() / SetActiveScene(...)​

Читает или задаёт активную сцену Unity (ту, в которую инстанцируются новые объекты).

MoveObjectToActiveScene(GameObject gameObject) / MoveObjectToScene(...)​

Перемещает GameObject в активную или конкретную сцену — стандартный способ передать пуленный/постоянный объект той сцене, которая должна им владеть.

ILocalizer​

Namespace: OpenMon.Foundation.Localization

Сервис локализации. Текст адресуется по ключу; valueModifiers подставляют плейсхолдеры {0}, {1}, … в разрешённой строке. Индексатор — удобный путь для одного ключа; перегрузки GetText / GetTexts добавляют выбор языка и пакетную обработку.

public interface ILocalizer
{
string this[string key, bool modifiersAreLocalizableKeys = true, params string[] valueModifiers] { get; }

string GetText(string key, bool modifiersAreLocalizableKeys = true, params string[] valueModifiers);
string GetText(string key, string language, bool modifiersAreLocalizableKeys = true, params string[] valueModifiers);
string GetText(string key, int languageIndex, bool modifiersAreLocalizableKeys = true, params string[] valueModifiers);

List<string> GetTexts(List<string> keys);
List<string> GetTexts(List<string> keys, string language);

string GetCurrentLanguage();
int GetCurrentLanguageIndex();
int GetLanguageIndex(string language);
List<string> GetAllLanguageIds();

void SetLanguage(string language);
void SetLanguage(int language);

void SubscribeToLanguageChange(Action<string> callback);
void SubscribeToLanguageChange(Action callback);
void UnsubscribeFromLanguageChange(Action<string> callback);
void UnsubscribeFromLanguageChange(Action callback);

void LoadNewLanguageValues(List<ScriptableLanguage> newLanguages);
void ReDownloadLanguagesFromGoogleSheet();
}

this[string key, bool modifiersAreLocalizableKeys = true, params string[] valueModifiers]​

Индексатор, возвращающий локализованную строку для key на текущем языке. valueModifiers заменяют плейсхолдеры {number}; когда modifiersAreLocalizableKeys равно true, модификаторы сами трактуются как ключи и локализуются первыми.

Возвращает: string.

GetText(string key, bool modifiersAreLocalizableKeys = true, params string[] valueModifiers)​

Методная форма индексатора. Перегрузки добавляют целевой language (по id или индексу), чтобы взять из конкретного языка независимо от текущего.

Возвращает: string.

GetTexts(List<string> keys)​

Разрешает сразу несколько ключей пакетом. Перегрузки добавляют целевой язык.

Возвращает: List<string>.

GetCurrentLanguage() / GetCurrentLanguageIndex() / GetAllLanguageIds()​

Запрашивает активный язык (ключ или индекс) и перечисляет все доступные id языков.

SetLanguage(string language) / SetLanguage(int language)​

Переключает активный язык по id или индексу. Вызывает событие смены языка.

SubscribeToLanguageChange / UnsubscribeFromLanguageChange​

Регистрирует/отменяет уведомления о смене языка (с id нового языка или без него). Для отмены используйте тот же экземпляр делегата.

Помощники внедрения зависимостей​

Namespace: OpenMon.Foundation.DependencyInjection

Движок связывает каждый общий ассет через небольшие инсталлеры Zenject. Когда делаете ассет данных внедряемым, наследуйтесь от одного из них.

LazySingletonScriptableInstaller<T>​

ScriptableObjectInstaller, связывающий назначенный в инспекторе ScriptableObject как ленивый синглтон типа T.

public class LazySingletonScriptableInstaller<T> : ScriptableObjectInstaller
where T : ScriptableObject
{
[SerializeField] protected T Reference;

public override void InstallBindings()
{
Container.QueueForInject(Reference);
Container.Bind<T>().FromInstance(Reference).AsSingle().Lazy();
}
}
QueueForInject обязателен

Container.QueueForInject(Reference) не опционален. ScriptableObject не внедряются Zenject автоматически — без этого вызова любые члены [Inject] на ассете остаются null. Затем связывание .AsSingle().Lazy() разделяет один экземпляр и откладывает разрешение до первого запроса T.

Чтобы сделать свой ассет данных внедряемым, наследуйтесь с конкретным T:

using OpenMon.Foundation.DependencyInjection;
using UnityEngine;

[CreateAssetMenu(menuName = "MyGame/MyConfig")]
public class MyConfig : ScriptableObject { public int Difficulty; }

public class MyConfigInstaller : LazySingletonScriptableInstaller<MyConfig> { }

Соседний LazySingletonMonoInstaller<T> делает то же самое для сценовых синглтонов MonoBehaviour.

AssetManagementUtils (только редактор)​

Namespace: OpenMon.Foundation.Editor.Utils

Редакторные помощники для массовой загрузки ассетов. Живут в сборке Runtime, но всё тело огорожено UNITY_EDITOR, поэтому никогда не попадает в билд игрока.

public static class AssetManagementUtils
{
public static void CreateFolderIfDoesNotExist(string path);
public static List<T> FindAssetsByType<T>() where T : Object;
}

FindAssetsByType<T>()​

Загружает все ассеты типа T в проекте.

Абстрактным базовым типам нужен запасной путь по подклассам

Обычный AssetDatabase.FindAssets("t:BaseType") возвращает ничего для абстрактного базового типа — Unity хранит ассеты как конкретные подклассы. Когда T абстрактен, FindAssetsByType<T> откатывается к сканированию каждого конкретного подкласса во всех загруженных сборках. Без этого запасного пути загрузка, например, абстрактной базы Move даёт пустой список, и вызывающий вроде MonsterDatabaseInstance.LoadAllMoves() перезапишет список приёмов базы данных пустотой при обновлении — стерев все приёмы в импортированных и демо-играх. Если вы пишете похожие массовые загрузчики, переиспользуйте этот помощник, а не вызывайте FindAssets напрямую.

Возвращает: List<T> — подходящие ассеты или пустой список, если ничего нет.

Пример использования​

using OpenMon.Foundation.Localization;
using OpenMon.Foundation.SceneManagement;
using Zenject;

public class TitleScreen : MonoBehaviour
{
[Inject] private ILocalizer localizer;
[Inject] private ISceneManager sceneManager;

private void Start()
{
// Локализованный текст с подстановкой плейсхолдеров.
Debug.Log(localizer["TitleScreen/Welcome", true, "Player"]);
Debug.Log($"Language: {localizer.GetCurrentLanguage()}");

// Загружаем первую карту аддитивно, логируя прогресс.
sceneManager.LoadScene(
"Overworld",
progress => Debug.Log($"Loading: {progress:P0}"),
success => Debug.Log(success ? "Loaded" : "Failed"));
}
}