save
This commit is contained in:
parent
eaeb0c45ac
commit
db31f362d1
@ -125,6 +125,7 @@ public class Inventar : Component
|
||||
}
|
||||
|
||||
// 3. Возвращаем остаток, если не всё удалось добавить
|
||||
AutoSave(); // Автоматическое сохранение
|
||||
return toAdd;
|
||||
}
|
||||
|
||||
@ -141,6 +142,7 @@ public class Inventar : Component
|
||||
_cacheDirty = true; // Помечаем кэш как устаревший
|
||||
OnChanged?.Invoke();
|
||||
OnItemRemoved?.Invoke( item );
|
||||
AutoSave(); // Автоматическое сохранение
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -149,6 +151,7 @@ public class Inventar : Component
|
||||
item.Count -= count;
|
||||
_cacheDirty = true; // Помечаем кэш как устаревший
|
||||
OnChanged?.Invoke();
|
||||
AutoSave(); // Автоматическое сохранение
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -181,6 +184,7 @@ public class Inventar : Component
|
||||
item.OnEquipped();
|
||||
OnEquipped?.Invoke( item );
|
||||
OnChanged?.Invoke();
|
||||
AutoSave(); // Автоматическое сохранение
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -219,6 +223,7 @@ public class Inventar : Component
|
||||
item.OnUnEquipped();
|
||||
OnUnEquipped?.Invoke( item );
|
||||
OnChanged?.Invoke();
|
||||
AutoSave(); // Автоматическое сохранение
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,4 +290,49 @@ public class Inventar : Component
|
||||
|
||||
return (float)Items.Count / MaxInventorySlots * 100f;
|
||||
}
|
||||
|
||||
#region Сохранение и загрузка
|
||||
|
||||
/// <summary>
|
||||
/// Автоматически сохраняет инвентарь при изменениях
|
||||
/// </summary>
|
||||
public void AutoSave()
|
||||
{
|
||||
if ( Network.IsOwner )
|
||||
{
|
||||
InventorySaveSystem.SaveInventory( this );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Загружает инвентарь из файла сохранения
|
||||
/// </summary>
|
||||
public void LoadFromSave()
|
||||
{
|
||||
if ( Network.IsOwner )
|
||||
{
|
||||
InventorySaveSystem.LoadInventory( this );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет, существует ли файл сохранения
|
||||
/// </summary>
|
||||
public bool HasSaveFile()
|
||||
{
|
||||
return InventorySaveSystem.HasSaveFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удаляет файл сохранения
|
||||
/// </summary>
|
||||
public void DeleteSaveFile()
|
||||
{
|
||||
if ( Network.IsOwner )
|
||||
{
|
||||
InventorySaveSystem.DeleteSaveFile();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
186
Code/Inventory/InventorySaveSystem.cs
Normal file
186
Code/Inventory/InventorySaveSystem.cs
Normal file
@ -0,0 +1,186 @@
|
||||
// Система сохранения инвентаря для s&box
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sandbox;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Sasalka;
|
||||
|
||||
public class InventorySaveData
|
||||
{
|
||||
public List<SavedInventoryItem> Items { get; set; } = new();
|
||||
public Dictionary<string, string> EquippedItems { get; set; } = new(); // slot -> itemId
|
||||
}
|
||||
|
||||
public class SavedInventoryItem
|
||||
{
|
||||
public string ItemDefinitionPath { get; set; } = "";
|
||||
public int Count { get; set; } = 1;
|
||||
public int MagazineAmmo { get; set; } = 0;
|
||||
public string Id { get; set; } = "";
|
||||
}
|
||||
|
||||
public static class InventorySaveSystem
|
||||
{
|
||||
private const string SAVE_FILE_NAME = "inventory_save.json";
|
||||
|
||||
/// <summary>
|
||||
/// Сохраняет инвентарь игрока в файл
|
||||
/// </summary>
|
||||
public static void SaveInventory( Inventar inventory )
|
||||
{
|
||||
if ( inventory == null ) return;
|
||||
|
||||
try
|
||||
{
|
||||
var saveData = new InventorySaveData();
|
||||
|
||||
// Сохраняем предметы в инвентаре
|
||||
foreach ( var item in inventory.Items )
|
||||
{
|
||||
if ( item.Definition == null ) continue;
|
||||
|
||||
var savedItem = new SavedInventoryItem
|
||||
{
|
||||
ItemDefinitionPath = item.Definition.ResourcePath,
|
||||
Count = item.Count,
|
||||
MagazineAmmo = item.MagazineAmmo,
|
||||
Id = Guid.NewGuid().ToString() // Генерируем уникальный ID для предмета
|
||||
};
|
||||
|
||||
saveData.Items.Add( savedItem );
|
||||
}
|
||||
|
||||
// Сохраняем экипированные предметы
|
||||
foreach ( var kvp in inventory.EquippedItems )
|
||||
{
|
||||
var slot = kvp.Key;
|
||||
var item = kvp.Value;
|
||||
|
||||
// Находим соответствующий сохраненный предмет
|
||||
var savedItem = saveData.Items.FirstOrDefault( x =>
|
||||
x.ItemDefinitionPath == item.Definition?.ResourcePath &&
|
||||
x.Count == item.Count &&
|
||||
x.MagazineAmmo == item.MagazineAmmo );
|
||||
|
||||
if ( savedItem != null )
|
||||
{
|
||||
saveData.EquippedItems[slot.ToString()] = savedItem.Id;
|
||||
}
|
||||
}
|
||||
|
||||
// Сериализуем и сохраняем в файл
|
||||
var json = JsonSerializer.Serialize( saveData, new JsonSerializerOptions { WriteIndented = true } );
|
||||
FileSystem.Data.WriteAllText( SAVE_FILE_NAME, json );
|
||||
|
||||
Log.Info( "Инвентарь успешно сохранен" );
|
||||
}
|
||||
catch ( Exception ex )
|
||||
{
|
||||
Log.Error( $"Ошибка при сохранении инвентаря: {ex.Message}" );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Загружает инвентарь игрока из файла
|
||||
/// </summary>
|
||||
public static void LoadInventory( Inventar inventory )
|
||||
{
|
||||
if ( inventory == null ) return;
|
||||
|
||||
try
|
||||
{
|
||||
if ( !FileSystem.Data.FileExists( SAVE_FILE_NAME ) )
|
||||
{
|
||||
Log.Info( "Файл сохранения инвентаря не найден" );
|
||||
return;
|
||||
}
|
||||
|
||||
var json = FileSystem.Data.ReadAllText( SAVE_FILE_NAME );
|
||||
var saveData = JsonSerializer.Deserialize<InventorySaveData>( json );
|
||||
|
||||
if ( saveData == null )
|
||||
{
|
||||
Log.Error( "Не удалось десериализовать данные сохранения" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Очищаем текущий инвентарь
|
||||
inventory.ClearInventory();
|
||||
|
||||
// Словарь для связи ID предметов с объектами InventoryItem
|
||||
var itemIdMap = new Dictionary<string, InventoryItem>();
|
||||
|
||||
// Загружаем предметы в инвентарь
|
||||
foreach ( var savedItem in saveData.Items )
|
||||
{
|
||||
var itemDefinition = ResourceLibrary.Get<BaseItemDefinition>( savedItem.ItemDefinitionPath );
|
||||
if ( itemDefinition == null )
|
||||
{
|
||||
Log.Warning( $"Не удалось загрузить определение предмета: {savedItem.ItemDefinitionPath}" );
|
||||
continue;
|
||||
}
|
||||
|
||||
var inventoryItem = new InventoryItem
|
||||
{
|
||||
Definition = itemDefinition,
|
||||
Count = savedItem.Count,
|
||||
MagazineAmmo = savedItem.MagazineAmmo
|
||||
};
|
||||
|
||||
inventory.Items.Add( inventoryItem );
|
||||
itemIdMap[savedItem.Id] = inventoryItem;
|
||||
}
|
||||
|
||||
// Экипируем предметы
|
||||
foreach ( var kvp in saveData.EquippedItems )
|
||||
{
|
||||
var slotName = kvp.Key;
|
||||
var itemId = kvp.Value;
|
||||
|
||||
if ( Enum.TryParse<Inventar.InventorySlot>( slotName, out var slot ) &&
|
||||
itemIdMap.TryGetValue( itemId, out var item ) )
|
||||
{
|
||||
inventory.EquipItem( item );
|
||||
}
|
||||
}
|
||||
|
||||
// Уведомляем об изменениях
|
||||
inventory.NotifyChanged();
|
||||
|
||||
Log.Info( "Инвентарь успешно загружен" );
|
||||
}
|
||||
catch ( Exception ex )
|
||||
{
|
||||
Log.Error( $"Ошибка при загрузке инвентаря: {ex.Message}" );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет, существует ли файл сохранения
|
||||
/// </summary>
|
||||
public static bool HasSaveFile()
|
||||
{
|
||||
return FileSystem.Data.FileExists( SAVE_FILE_NAME );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удаляет файл сохранения
|
||||
/// </summary>
|
||||
public static void DeleteSaveFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( FileSystem.Data.FileExists( SAVE_FILE_NAME ) )
|
||||
{
|
||||
FileSystem.Data.DeleteFile( SAVE_FILE_NAME );
|
||||
Log.Info( "Файл сохранения инвентаря удален" );
|
||||
}
|
||||
}
|
||||
catch ( Exception ex )
|
||||
{
|
||||
Log.Error( $"Ошибка при удалении файла сохранения: {ex.Message}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
118
Code/Inventory/README_SaveSystem.md
Normal file
118
Code/Inventory/README_SaveSystem.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Система сохранения инвентаря
|
||||
|
||||
## Описание
|
||||
|
||||
Система автоматического сохранения и загрузки инвентаря игрока, включая экипированные предметы (одежда, оружие).
|
||||
|
||||
## Функциональность
|
||||
|
||||
### Автоматическое сохранение
|
||||
- Инвентарь автоматически сохраняется при любых изменениях:
|
||||
- Добавление предметов
|
||||
- Удаление предметов
|
||||
- Экипировка предметов
|
||||
- Снятие предметов
|
||||
|
||||
### Сохранение при выходе из игры
|
||||
- **При отключении от сервера** - инвентарь сохраняется автоматически
|
||||
- **При закрытии игры** - инвентарь сохраняется при уничтожении объекта игрока
|
||||
- **При разрыве соединения** - дополнительное сохранение для защиты от потери данных
|
||||
|
||||
### Периодическое сохранение
|
||||
- **Каждые 60 секунд** - автоматическое сохранение для защиты от сбоев
|
||||
- Защищает от потери прогресса при неожиданном закрытии игры
|
||||
|
||||
### Автоматическая загрузка
|
||||
- При входе в игру система автоматически проверяет наличие сохранения
|
||||
- Если сохранение найдено, инвентарь загружается автоматически
|
||||
- Если сохранения нет, начинается с пустым инвентарем
|
||||
|
||||
### Сохраняемые данные
|
||||
- Все предметы в инвентаре (название, количество, патроны в магазине)
|
||||
- Экипированные предметы (одежда, оружие)
|
||||
- Слоты экипировки
|
||||
|
||||
## Использование
|
||||
|
||||
### В игре
|
||||
1. **UI панель**: В правом верхнем углу экрана отображается панель управления сохранением
|
||||
- Зеленая индикация = есть сохранение
|
||||
- Красная индикация = нет сохранения
|
||||
- Кнопки: Сохранить, Загрузить, Очистить
|
||||
|
||||
### Автоматическое сохранение
|
||||
- **При изменениях** - сохранение происходит автоматически
|
||||
- **При выходе** - сохранение при отключении/закрытии игры
|
||||
- **Периодически** - каждые 60 секунд для защиты от сбоев
|
||||
|
||||
## Технические детали
|
||||
|
||||
### Файл сохранения
|
||||
- Расположение: `data/inventory_save.json`
|
||||
- Формат: JSON
|
||||
- Структура:
|
||||
```json
|
||||
{
|
||||
"Items": [
|
||||
{
|
||||
"ItemDefinitionPath": "path/to/item.resource",
|
||||
"Count": 1,
|
||||
"MagazineAmmo": 0,
|
||||
"Id": "unique-id"
|
||||
}
|
||||
],
|
||||
"EquippedItems": {
|
||||
"RightHand": "item-id",
|
||||
"Body": "item-id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Классы системы
|
||||
- `InventorySaveSystem` - статический класс для работы с сохранением
|
||||
- `InventorySaveData` - модель данных для сохранения
|
||||
- `SavedInventoryItem` - модель сохраненного предмета
|
||||
|
||||
### Интеграция
|
||||
- `Inventar` - добавлены методы `AutoSave()`, `LoadFromSave()`, `HasSaveFile()`, `DeleteSaveFile()`
|
||||
- `Dedugan.Inventory.cs` - автоматическая загрузка при старте и периодическое сохранение
|
||||
- `Dedugan.cs` - сохранение при выходе из игры (`OnDestroy`, `SaveInventoryOnExit()`)
|
||||
- `NetworkManager.cs` - сохранение при отключении игрока (`OnDisconnected`, `OnBecomeInactive`)
|
||||
- `GUI.razor` - интегрированная панель управления сохранением
|
||||
|
||||
## Безопасность
|
||||
|
||||
- Сохранение происходит только на клиенте (Network.IsOwner)
|
||||
- Проверка валидности данных при загрузке
|
||||
- Обработка ошибок с логированием
|
||||
- Fallback на пустой инвентарь при ошибках
|
||||
- **Множественные точки сохранения** для максимальной защиты данных
|
||||
|
||||
## Совместимость
|
||||
|
||||
- Работает со всеми типами предметов (оружие, одежда, патроны и т.д.)
|
||||
- Поддерживает все слоты экипировки
|
||||
- Сохраняет патроны в магазине оружия
|
||||
- Совместима с существующей системой инвентаря
|
||||
|
||||
## Устранение неполадок
|
||||
|
||||
### Проблема: Инвентарь не загружается
|
||||
1. Проверьте консоль на ошибки
|
||||
2. Убедитесь, что файл `data/inventory_save.json` существует
|
||||
3. Проверьте права доступа к папке data
|
||||
|
||||
### Проблема: Предметы не сохраняются
|
||||
1. Убедитесь, что вы владелец игрока (Network.IsOwner)
|
||||
2. Проверьте, что предметы имеют валидные определения
|
||||
3. Проверьте консоль на ошибки сериализации
|
||||
|
||||
### Проблема: UI не отображается
|
||||
1. Убедитесь, что панель сохранения интегрирована в GUI.razor
|
||||
2. Проверьте, что стили добавлены в GUI.razor
|
||||
3. Перезапустите игру
|
||||
|
||||
### Проблема: Сохранение не работает при выходе
|
||||
1. Проверьте, что метод `SaveInventoryOnExit()` вызывается
|
||||
2. Убедитесь, что NetworkManager правильно обрабатывает отключения
|
||||
3. Проверьте логи на наличие ошибок сохранения
|
||||
@ -73,6 +73,13 @@ public sealed class NetworkManager : Component, Component.INetworkListener
|
||||
/// </summary>
|
||||
public void OnDisconnected( Connection channel )
|
||||
{
|
||||
// Сохраняем инвентарь игрока перед отключением
|
||||
var player = Dedugan.GetByID( channel.Id );
|
||||
if ( player != null )
|
||||
{
|
||||
player.SaveInventoryOnExit();
|
||||
}
|
||||
|
||||
Dedugan.InternalPlayers.Remove( Dedugan.GetByID( channel.Id ) );
|
||||
}
|
||||
|
||||
@ -81,7 +88,12 @@ public sealed class NetworkManager : Component, Component.INetworkListener
|
||||
/// </summary>
|
||||
public void OnBecomeInactive( Connection channel )
|
||||
{
|
||||
// Optional: Handle any cleanup before player becomes fully inactive
|
||||
// Сохраняем инвентарь игрока при разрыве соединения
|
||||
var player = Dedugan.GetByID( channel.Id );
|
||||
if ( player != null )
|
||||
{
|
||||
player.SaveInventoryOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -14,6 +14,10 @@ public sealed partial class Dedugan : Component
|
||||
private bool _isShooting = false;
|
||||
private TimeSince _lastShootTime = 0f;
|
||||
|
||||
// Периодическое сохранение
|
||||
private TimeSince _lastAutoSave = 0f;
|
||||
private const float AUTO_SAVE_INTERVAL = 60f; // Сохраняем каждые 60 секунд
|
||||
|
||||
void InventoryStart()
|
||||
{
|
||||
if ( !Network.IsOwner ) return;
|
||||
@ -26,6 +30,25 @@ public sealed partial class Dedugan : Component
|
||||
Inventory.OnUnEquipped += OnItemUnEquipped;
|
||||
Inventory.OnItemAdded += OnItemAdded;
|
||||
Inventory.OnItemRemoved += OnItemRemoved;
|
||||
|
||||
// Загружаем инвентарь из сохранения при старте
|
||||
LoadInventoryFromSave();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Загружает инвентарь из сохранения
|
||||
/// </summary>
|
||||
private void LoadInventoryFromSave()
|
||||
{
|
||||
if ( Inventory.HasSaveFile() )
|
||||
{
|
||||
Log.Info( "Загружаем инвентарь из сохранения..." );
|
||||
Inventory.LoadFromSave();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info( "Файл сохранения инвентаря не найден, начинаем с пустым инвентарем" );
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemEquipped( InventoryItem item )
|
||||
@ -159,6 +182,17 @@ public sealed partial class Dedugan : Component
|
||||
{
|
||||
TryReloadWeapon();
|
||||
}
|
||||
|
||||
// Периодическое автоматическое сохранение
|
||||
if ( _lastAutoSave > AUTO_SAVE_INTERVAL )
|
||||
{
|
||||
if ( Inventory != null )
|
||||
{
|
||||
Log.Info( "Периодическое автоматическое сохранение инвентаря..." );
|
||||
Sasalka.InventorySaveSystem.SaveInventory( Inventory );
|
||||
}
|
||||
_lastAutoSave = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -116,6 +116,18 @@ public sealed partial class Dedugan : Component, IUseContext, Component.INetwork
|
||||
DrawDebugGizmos();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сохраняет инвентарь при выходе из игры
|
||||
/// </summary>
|
||||
public void SaveInventoryOnExit()
|
||||
{
|
||||
if ( Network.IsOwner && Inventory != null )
|
||||
{
|
||||
Log.Info( "Сохраняем инвентарь при выходе из игры..." );
|
||||
Sasalka.InventorySaveSystem.SaveInventory( Inventory );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Реализация интерфейса IUseContext
|
||||
/// Возвращает список используемых предметов
|
||||
@ -189,4 +201,10 @@ public sealed partial class Dedugan : Component, IUseContext, Component.INetwork
|
||||
_bodyRotationDirty = true; // Помечаем, что тело повернулось
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
// Сохраняем инвентарь при уничтожении объекта (закрытие игры)
|
||||
SaveInventoryOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
@using Sandbox
|
||||
@using Sandbox.UI
|
||||
@using Sasalka
|
||||
@inherits PanelComponent
|
||||
@namespace Sandbox
|
||||
|
||||
@ -23,6 +24,31 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Панель управления сохранением инвентаря -->
|
||||
<div class="save-status">
|
||||
<div class="save-indicator @( HasSaveFile ? "has-save" : "no-save" )">
|
||||
<div class="save-text">@( HasSaveFile ? "Сохранение есть" : "Нет сохранения" )</div>
|
||||
</div>
|
||||
|
||||
@if ( HasSaveFile )
|
||||
{
|
||||
<button class="load-button" onmousedown="LoadInventory">
|
||||
<div class="button-text">Загрузить</div>
|
||||
</button>
|
||||
}
|
||||
|
||||
<button class="save-button" onmousedown="SaveInventory">
|
||||
<div class="button-text">Сохранить</div>
|
||||
</button>
|
||||
|
||||
@if ( HasSaveFile )
|
||||
{
|
||||
<button class="clear-button" onmousedown="ClearSave">
|
||||
<div class="button-text">Очистить</div>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</root>
|
||||
|
||||
<style>
|
||||
@ -98,6 +124,95 @@
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.save-status {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 200px;
|
||||
|
||||
.save-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
|
||||
&.has-save {
|
||||
background: rgba(76, 175, 80, 0.2);
|
||||
color: #4CAF50;
|
||||
border: 1px solid #4CAF50;
|
||||
}
|
||||
|
||||
&.no-save {
|
||||
background: rgba(244, 67, 54, 0.2);
|
||||
color: #F44336;
|
||||
border: 1px solid #F44336;
|
||||
}
|
||||
|
||||
.save-text {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&.save-button {
|
||||
background: #2196F3;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: #1976D2;
|
||||
}
|
||||
}
|
||||
|
||||
&.load-button {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: #388E3C;
|
||||
}
|
||||
}
|
||||
|
||||
&.clear-button {
|
||||
background: #F44336;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: #D32F2F;
|
||||
}
|
||||
}
|
||||
|
||||
.button-text {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
@ -108,6 +223,10 @@
|
||||
private int TotalInInventory { get; set; } = 0;
|
||||
private bool HasWeapon { get; set; } = false;
|
||||
|
||||
// Переменные для системы сохранения
|
||||
private bool HasSaveFile { get; set; } = false;
|
||||
private TimeSince _lastCheck = 0f;
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if ( Dedugan.Local == null ) return;
|
||||
@ -122,6 +241,47 @@
|
||||
|
||||
// Проверяем, есть ли оружие в руках (если MaxAmmo > 0, значит есть оружие)
|
||||
HasWeapon = MaxAmmo > 0;
|
||||
|
||||
// Проверяем наличие файла сохранения каждые 2 секунды
|
||||
if ( _lastCheck > 2f )
|
||||
{
|
||||
CheckSaveFile();
|
||||
_lastCheck = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
CheckSaveFile();
|
||||
}
|
||||
|
||||
private void CheckSaveFile()
|
||||
{
|
||||
HasSaveFile = Sasalka.InventorySaveSystem.HasSaveFile();
|
||||
}
|
||||
|
||||
private void SaveInventory()
|
||||
{
|
||||
if ( Dedugan.Local?.Inventory != null )
|
||||
{
|
||||
Sasalka.InventorySaveSystem.SaveInventory( Dedugan.Local.Inventory );
|
||||
CheckSaveFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadInventory()
|
||||
{
|
||||
if ( Dedugan.Local?.Inventory != null )
|
||||
{
|
||||
Sasalka.InventorySaveSystem.LoadInventory( Dedugan.Local.Inventory );
|
||||
CheckSaveFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSave()
|
||||
{
|
||||
Sasalka.InventorySaveSystem.DeleteSaveFile();
|
||||
CheckSaveFile();
|
||||
}
|
||||
|
||||
protected override int BuildHash()
|
||||
@ -136,8 +296,8 @@
|
||||
hash.Add( IsReloading );
|
||||
hash.Add( ReloadProgress );
|
||||
hash.Add( HasWeapon );
|
||||
hash.Add( HasSaveFile );
|
||||
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user