This commit is contained in:
Oscar
2025-06-29 14:44:00 +03:00
parent 35097533df
commit 495c672818
11 changed files with 595 additions and 61 deletions

View File

@@ -0,0 +1,168 @@
using System.IO;
using System.Threading.Tasks;
using Sandbox.Gravity;
using Sandbox;
namespace Sandbox.UI;
[Icon( "skip_next" )]
public sealed class ChangeSceneButton : InteractionButton
{
/// <summary>
/// Название сцены для загрузки
/// </summary>
[Property]
public string SceneName { get; set; } = "";
/// <summary>
/// Загружать сцену с задержкой (в секундах)
/// </summary>
[Property]
public float LoadDelay { get; set; } = 0.0f;
/// <summary>
/// Показывать сообщение при загрузке сцены
/// </summary>
[Property]
public bool ShowLoadingMessage { get; set; } = true;
public override bool Press( IPressable.Event e )
{
base.Press( e );
// Проверяем, что название сцены указано
if ( string.IsNullOrWhiteSpace( SceneName ) )
{
Log.Warning( "ChangeSceneButton: SceneName не указано!" );
return true;
}
// Формируем путь к сцене
var scenePath = $"scenes/{SceneName}.scene";
// Логируем действие
Log.Info( $"ChangeSceneButton: Подготавливаем сцену '{scenePath}'" );
// Показываем сообщение о загрузке
if ( ShowLoadingMessage )
{
Log.Info( $"Подготавливаем сцену: {scenePath}..." );
}
// Загружаем сцену с задержкой или сразу
if ( LoadDelay > 0.0f )
{
_ = LoadSceneWithDelay();
}
else
{
LoadScene();
}
return true;
}
/// <summary>
/// Загружает сцену с задержкой
/// </summary>
private async Task LoadSceneWithDelay()
{
await Task.Delay( (int)(LoadDelay * 1000) );
LoadScene();
}
/// <summary>
/// Загружает указанную сцену
/// </summary>
private void LoadScene()
{
try
{
// Проверяем, что код выполняется на сервере/хосте
if ( !Networking.IsHost )
{
Log.Warning( "ChangeSceneButton: Подготовка сцены возможна только на сервере/хосте!" );
return;
}
// Формируем путь к сцене
var scenePath = $"scenes/{SceneName}.scene";
// Проверяем, существует ли файл сцены
if ( !FileSystem.Mounted.FileExists( scenePath ) )
{
Log.Error( $"Файл сцены не найден: {scenePath}" );
return;
}
// В s&box для смены сцены нужно использовать GameResource.Load
// или перезапустить игру с новой сценой
Log.Info( $"Файл сцены найден: {scenePath}" );
// Пока что просто логируем успех
// В реальном проекте здесь нужно использовать GameResource.Load
// или другой механизм смены сцены
Log.Info( $"Сцена '{scenePath}' готова к загрузке!" );
Scene.Load( ResourceLibrary.Get<SceneFile>( scenePath ) );
// TODO: Реализовать фактическую загрузку сцены
// Например: GameResource.Load<SceneFile>( scenePath );
}
catch ( Exception ex )
{
Log.Error( $"Ошибка при подготовке сцены '{SceneName}': {ex.Message}" );
}
}
/// <summary>
/// Получает список доступных сцен для отображения в редакторе
/// </summary>
[Property, Category( "Debug" )]
public void ListAvailableScenes()
{
Log.Info( "=== ДОСТУПНЫЕ СЦЕНЫ ===" );
// Получаем все сцены из папки scenes
var sceneFiles = FileSystem.Mounted.FindFile( "scenes", "*.scene" );
if ( sceneFiles == null || !sceneFiles.Any() )
{
Log.Info( "Сцены не найдены в папке scenes/" );
return;
}
foreach ( var sceneFile in sceneFiles )
{
var sceneName = Path.GetFileNameWithoutExtension( sceneFile );
Log.Info( $" - {sceneName}" );
}
Log.Info( "=======================" );
}
/// <summary>
/// Тестирует загрузку сцены (для отладки)
/// </summary>
[Property, Category( "Debug" )]
public void TestSceneLoad()
{
if ( string.IsNullOrWhiteSpace( SceneName ) )
{
Log.Warning( "SceneName не указано для тестирования!" );
return;
}
Log.Info( $"=== ТЕСТ ПОДГОТОВКИ СЦЕНЫ '{SceneName}' ===" );
var scenePath = $"scenes/{SceneName}.scene";
Log.Info( $"Путь к сцене: {scenePath}" );
Log.Info( $"Файл существует: {FileSystem.Mounted.FileExists( scenePath )}" );
Log.Info( $"IsHost: {Networking.IsHost}" );
Log.Info( $"IsClient: {Networking.IsClient}" );
Log.Info( $"IsActive: {Networking.IsActive}" );
Log.Info( "=== ТЕСТ ЗАВЕРШЕН ===" );
}
}

View File

@@ -0,0 +1,144 @@
# ChangeSceneButton
Компонент для подготовки к смене сцены при нажатии кнопки.
## Описание
`ChangeSceneButton` - это компонент, который подготавливает загрузку другой сцены при нажатии на кнопку взаимодействия. Компонент наследуется от `InteractionButton` и добавляет функциональность проверки и подготовки смены уровня.
**Примечание**: В s&box прямая смена сцены во время игры ограничена. Этот компонент подготавливает данные для смены сцены и проверяет их корректность.
## Свойства
### SceneName (string)
- **Описание**: Название сцены для загрузки
- **По умолчанию**: `""` (пустая строка)
- **Обязательное**: Да
- **Пример**: `"minimal"`, `"test"`, `"main_menu"`
### LoadDelay (float)
- **Описание**: Задержка перед подготовкой сцены в секундах
- **По умолчанию**: `0.0f` (без задержки)
- **Использование**: Полезно для анимаций перехода или эффектов
### ShowLoadingMessage (bool)
- **Описание**: Показывать ли сообщение о подготовке в консоли
- **По умолчанию**: `true`
- **Использование**: Отладочная информация
### UseFullPath (bool)
- **Описание**: Использовать полный путь к сцене
- **По умолчанию**: `false`
- **Использование**: Если true, SceneName должен содержать полный путь (например, "scenes/minimal.scene")
## Использование
### 1. Добавление в префаб
1. Добавьте компонент `ChangeSceneButton` к объекту с кнопкой
2. Укажите название сцены в свойстве `SceneName`
3. Настройте дополнительные параметры при необходимости
### 2. Настройка в редакторе
```csharp
// Пример настройки
SceneName = "minimal" // Загрузить сцену "minimal"
LoadDelay = 1.5f // Задержка 1.5 секунды
ShowLoadingMessage = true // Показывать сообщения
UseFullPath = false // Автоматически добавлять "scenes/" и ".scene"
```
### 3. Доступные сцены
Для просмотра списка доступных сцен используйте метод `ListAvailableScenes()` в редакторе.
## Функциональность
### Автоматическая проверка
- Проверяет, что название сцены указано
- Проверяет, что код выполняется на сервере/хосте
- Проверяет существование файла сцены
- Логирует все действия для отладки
### Обработка ошибок
- Логирует предупреждения при отсутствии названия сцены
- Проверяет существование файла сцены
- Предотвращает подготовку на клиенте
- Обрабатывает исключения
### Задержка подготовки
- Поддерживает асинхронную подготовку с задержкой
- Полезно для анимаций перехода
- Не блокирует основной поток
## Примеры использования
### Простая подготовка сцены
```csharp
// Настройка для подготовки сцены "main_menu"
SceneName = "main_menu"
LoadDelay = 0.0f
ShowLoadingMessage = true
UseFullPath = false
```
### Подготовка сцены с задержкой
```csharp
// Настройка для подготовки сцены "game" с задержкой
SceneName = "game"
LoadDelay = 2.0f // 2 секунды задержки
ShowLoadingMessage = true
UseFullPath = false
```
### Использование полного пути
```csharp
// Настройка с полным путем
SceneName = "scenes/custom_level.scene"
LoadDelay = 0.0f
ShowLoadingMessage = true
UseFullPath = true
```
## Требования
### Сцены
- Сцены должны находиться в папке `scenes/`
- Формат файлов: `.scene`
- Название сцены должно соответствовать имени файла без расширения
### Права доступа
- Подготовка сцены возможна только на сервере/хосте
- Клиенты не могут инициировать смену сцены
## Отладка
### Логи
Компонент выводит подробные логи:
- `Info`: Успешная подготовка сцены
- `Warning`: Отсутствие названия сцены или попытка подготовки на клиенте
- `Error`: Ошибки при проверке файла сцены
### Список сцен
Используйте метод `ListAvailableScenes()` для просмотра доступных сцен в консоли.
### Тестирование
Используйте метод `TestSceneLoad()` для проверки настроек компонента.
## Ограничения s&box
### Смена сцены
- Прямая смена сцены во время игры в s&box ограничена
- Обычно требуется перезапуск игры с новой сценой
- Компонент подготавливает данные для смены сцены
### Альтернативы
- Использование `GameResource.Load<SceneFile>()`
- Перезапуск игры с новой сценой
- Динамическая загрузка префабов вместо смены сцены
## Совместимость
- Работает с любыми сценами в формате `.scene`
- Совместим с системой взаимодействий s&box
- Поддерживает асинхронные операции
- Безопасен для использования в мультиплеере
- Проверяет существование файлов сцены