# Sasalka Game Project ## Последние обновления ### 🔧 Оптимизации производительности - **Кэширование Network.IsOwner** - убраны повторные проверки в OnUpdate() - **Оптимизация UpdateBodyRotation** - добавлена проверка изменений углов перед вычислениями - **Кэширование предметов в инвентаре** - замена LINQ FirstOrDefault на Dictionary для O(1) поиска - **Уменьшение частоты обновления эффектов** - эффекты оружия обновляются каждые 100мс вместо каждого кадра - **Кэширование компонентов** - Rigidbody и PickupItem получаются один раз и кэшируются ### 👕 Исправление проблемы с волосами - **Защита волос при снятии одежды** - волосы больше не удаляются при снятии одежды с головы - Добавлена проверка категорий волос в методе `StripByName()` - Защищены категории: Hair, HairShort, HairMedium, HairLong, HairUpdo, HairSpecial ### 📦 Система стакания предметов - **Поддержка стакания** - предметы с флагом `IsStackable = true` теперь автоматически стакаются - **Автоматическое объединение стаков** - стаки объединяются при добавлении/удалении предметов - **Оптимизация инвентаря** - метод `ConsolidateStacks()` для ручного объединения стаков - **Патроны по умолчанию стакаемые** - AmmoItemDefinition теперь имеет IsStackable = true и MaxCount = 100 ### 🎯 Как использовать стакание 1. В определении предмета установите `IsStackable = true` 2. Установите `MaxCount` - максимальное количество предметов в стаке 3. Система автоматически будет стакать предметы при добавлении в инвентарь ### 📈 Ожидаемые улучшения производительности - Снижение нагрузки CPU на 15-25% - Ускорение поиска предметов в инвентаре с O(n) до O(1) - Меньше обращений к компонентам - Оптимизация рендеринга эффектов ## Система оружия ### Основные компоненты - `BaseWeapon` - базовый класс для всех видов оружия - `WeaponItemDefinition` - определение оружия с параметрами - `AmmoItemDefinition` - определение патронов (стакаемые по умолчанию) ### Функции оружия - Автоматическая и одиночная стрельба - Система патронов с магазином и инвентарем - Перезарядка с анимацией - Эффекты выстрела и попадания - Синхронизация по сети ### Система инвентаря - Поддержка стакания предметов - Автоматическое объединение стаков - Кэширование для производительности - События для UI обновлений ## Система камеры ### Орбитальное движение - Камера вращается вокруг пивота при движении мыши - Компенсация поворота тела - Плавная интерполяция позиции пивота - Поддержка ADS режима ### Управление - Горизонтальное движение мыши - вращение по орбите - Вертикальное движение мыши - наклон камеры - Плавное следование за позицией глаз игрока ## Сетевая синхронизация ### Синхронизируемые данные - Позиция и поворот игрока - Состояние оружия (перезарядка, патроны) - Экипированные предметы - Анимации персонажа ### Оптимизации сети - Кэширование проверок владельца - Уменьшение частоты обновлений - Эффективная синхронизация состояний ## Система выбрасывания предметов при смерти ### Автоматическое выбрасывание при смерти При смерти игрока (когда здоровье достигает 0) автоматически выбрасываются все предметы из инвентаря: - **Все экипированные предметы** автоматически снимаются - **Все предметы в инвентаре** выбрасываются на землю рядом с игроком - **Предметы разбрасываются** в радиусе 50 единиц от позиции игрока - **Логирование** процесса выбрасывания в консоль ### Специальная обработка одежды Одежда обрабатывается особым образом при выбрасывании: - **Создание физического объекта** - для одежды создается специальный физический объект - **Fallback система** - если префаб не найден, создается простой объект с коллайдером - **Правильная метка** - отображается название одежды и слот (например, "Куртка (Тело)") - **Поддержка подбора** - выброшенная одежда может быть подобрана обратно ### Методы для выбрасывания предметов #### `DropAllItemsOnDeath()` (приватный) Автоматически вызывается при смерти игрока: ```csharp private void DropAllItemsOnDeath() { if ( Inventory == null || !Network.IsOwner ) return; int droppedCount = Inventory.DropAllItems( WorldPosition, 50f ); Log.Info( $"Выброшено {droppedCount} предметов при смерти игрока {Name}" ); } ``` #### `ForceDropAllItems()` (публичный) Можно вызывать принудительно из других мест: ```csharp public void ForceDropAllItems( Vector3? dropPosition = null, float scatterRadius = 50f ) { if ( Inventory == null || !Network.IsOwner ) return; var finalDropPosition = dropPosition ?? WorldPosition; int droppedCount = Inventory.DropAllItems( finalDropPosition, scatterRadius ); } ``` #### `Inventory.DropAllItems()` (публичный) Метод в классе инвентаря для массового выбрасывания: ```csharp public int DropAllItems( Vector3 dropPosition, float scatterRadius = 50f ) { // Снимает все экипированные предметы // Выбрасывает все предметы в указанной позиции с разбросом // Возвращает количество выброшенных предметов } ``` #### `DropClothingItem()` (приватный) Специальный метод для выбрасывания одежды: ```csharp private void DropClothingItem( InventoryItem item, Vector3 position, ClothingItemDefinition clothingDef ) { // Создает физический объект для одежды // Добавляет правильную метку и компоненты // Поддерживает fallback если префаб не найден } ``` ### UI для тестирования В интерфейсе добавлена кнопка "📦 Выбросить все" для тестирования системы выбрасывания предметов. ### Особенности реализации 1. **Безопасная итерация** - создаются копии списков предметов для избежания ошибок при изменении коллекций 2. **Сетевая синхронизация** - выбрасывание происходит только на владельце объекта 3. **Снятие экипировки** - все экипированные предметы сначала снимаются, затем выбрасываются 4. **Случайный разброс** - предметы разбрасываются случайным образом в указанном радиусе 5. **Специальная обработка одежды** - одежда создает физические объекты с правильными метками 6. **Fallback система** - если префаб не найден, создается простой объект с базовыми компонентами 7. **Логирование** - все действия логируются для отладки ### Использование ```csharp // Принудительно выбросить все предметы игрока Dedugan.Local.ForceDropAllItems(); // Выбросить предметы в определенной позиции Dedugan.Local.ForceDropAllItems( new Vector3(100, 0, 100), 30f ); // Выбросить все предметы из инвентаря напрямую player.Inventory.DropAllItems( player.WorldPosition, 25f ); ```