Загрузка данных
Вот полная техническая выжимка с примерами исходного кода и финальными патчами для передачи разработчикам/нейросети:
---
# Техническое резюме: Система изоляции `.matrix` для TrinityCore Master (Dragonflight 12.x)
## 1. Цель
Реализовать кастомную систему сценариев (`.matrix <id>`), обеспечивающую полную взаимную изоляцию игроков, NPC и ГО по ID матрицы. Объекты с одинаковым `matrix_id` видят друг друга, с разным — нет. Матрица `0` = обычный мир. Требование: персистентность после рестарта, минимальное вторжение в ядро.
## 2. Исследованные альтернативы (отклонены)
| Вариант | Причина отказа | Источник |
|---|---|---|
| **Eluna/Lua** | Не поддерживает TC master/Dragonflight 12.x. Работает только с 3.3.5 и Cata Preservation | GitHub ElunaLuaEngine, talk.trinitycore.org |
| **SmartScripts** | Не перехватывают проверку видимости (`CanNeverSee`) | trinitycore.info/database/master/world/smart_scripts |
| **Штатная фазовая система** | `.modify phase` работает для изоляции игроков, но `.npc set phase` не функционирует для NPC в Dragonflight. Фаза NPC определяется полем `PhaseId` в таблице `creature`, а не наследуется от спавнера | trinitycore.info/database/master/world/creature, DB2Structure.h |
| **Внешний C++ модуль** | Невозможно без изменения ядра: хук `CanNeverSee()` требует модификации `WorldObject` | ScriptMgr.h, Object.h |
## 3. Ключевые структуры ядра (исходные)
### PhaseEntry (DB2Structure.h)
```cpp
struct PhaseEntry
{
uint32 ID;
int32 Flags;
EnumFlag<PhaseEntryFlags> GetFlags() const { return static_cast<PhaseEntryFlags>(Flags); }
};
```
### PhaseEntryFlags (DBCEnums.h)
```cpp
enum class PhaseEntryFlags : int32
{
ReadOnly = 0x001,
InternalPhase = 0x002,
Normal = 0x008,
Cosmetic = 0x010,
Personal = 0x020,
Expensive = 0x040,
EventsAreObservable = 0x080,
UsesPreloadConditions = 0x100,
UnshareablePersonal = 0x200,
ObjectsAreVisible = 0x400,
};
```
### InSamePhase (Object.h — ДО изменений)
```cpp
bool InSamePhase(WorldObject const* obj) const
{
return GetPhaseShift().CanSee(obj->GetPhaseShift());
}
```
### CanNeverSee (Object.cpp — ДО изменений)
```cpp
bool WorldObject::CanNeverSee(WorldObject const* obj, bool ignorePhaseShift /*= false*/) const
{
return GetMap() != obj->GetMap()
|| (!ignorePhaseShift && !InSamePhase(obj));
}
```
### Поля WorldObject (Object.h — ДО изменений)
```cpp
PhaseShift _phaseShift;
PhaseShift _suppressedPhaseShift;
int32 _dbPhase;
```
## 4. Выбранное решение: Минимальный патч ядра (3 файла)
### Изменение 1: Object.h — добавление поля и геттера/сеттера
**Было:**
```cpp
int32 GetDBPhase() const { return _dbPhase; }
void SetDBPhase(int32 p) { _dbPhase = p; }
```
**Стало:**
```cpp
int32 GetDBPhase() const { return _dbPhase; }
void SetDBPhase(int32 p) { _dbPhase = p; }
uint32 GetMatrixId() const { return _matrixId; }
void SetMatrixId(uint32 matrixId) { _matrixId = matrixId; }
```
**Поля — было:**
```cpp
PhaseShift _phaseShift;
PhaseShift _suppressedPhaseShift;
int32 _dbPhase;
```
**Поля — стало:**
```cpp
PhaseShift _phaseShift;
PhaseShift _suppressedPhaseShift;
int32 _dbPhase;
uint32 _matrixId = 0;
```
### Изменение 2: Object.h — модификация InSamePhase()
**Было:**
```cpp
bool InSamePhase(WorldObject const* obj) const
{
return GetPhaseShift().CanSee(obj->GetPhaseShift());
}
```
**Стало:**
```cpp
bool InSamePhase(WorldObject const* obj) const
{
return GetMatrixId() == obj->GetMatrixId()
&& GetPhaseShift().CanSee(obj->GetPhaseShift());
}
```
### Изменение 3: Object.cpp — модификация CanNeverSee()
**Было:**
```cpp
bool WorldObject::CanNeverSee(WorldObject const* obj, bool ignorePhaseShift /*= false*/) const
{
return GetMap() != obj->GetMap()
|| (!ignorePhaseShift && !InSamePhase(obj));
}
```
**Стало:**
```cpp
bool WorldObject::CanNeverSee(WorldObject const* obj, bool ignorePhaseShift /*= false*/) const
{
return GetMap() != obj->GetMap()
|| GetMatrixId() != obj->GetMatrixId()
|| (!ignorePhaseShift && !GetPhaseShift().CanSee(obj->GetPhaseShift()));
}
```
## 5. Архитектурные решения
- `_matrixId = 0` по умолчанию → полная обратная совместимость, сервер ведёт себя идентично стоку до внедрения команды
- Проверка matrix идёт **до** проверки PhaseShift в `InSamePhase()` → приоритет изоляции над штатными фазами
- В `CanNeverSee()` проверка `GetMatrixId() != obj->GetMatrixId()` стоит отдельным условием через `||` → если матрицы разные, объекты невидимы независимо от фаз и карт
- Персистентность планируется через отдельные таблицы БД (не реализовано на текущем этапе)
## 6. Текущий статус
- ✅ Патч ядра определён и готов к внесению (3 изменения в 2 файлах)
- ⏳ Компиляция не выполнена
- ❌ Команда `.matrix` не написана (`MatrixCommand.cpp` / `SpawndancerCommand.cpp` не создан)
- ❌ Передача MatrixId при спавне NPC/ГО не реализована (`Map::SummonCreature` не изменён)
- ❌ SQL-миграция и персистентность не реализованы
## 7. План следующего этапа
1. Внести 3 изменения в ядро → скомпилировать → убедиться что сток не сломан
2. Написать `MatrixCommand.cpp` (`.matrix <id>`, `.spawndancer <entry>`)
3. Добавить наследование MatrixId при создании NPC/ГО: `Player.MatrixId → NPC.MatrixId` в `Map::SummonCreature` / `Map::AddToMap`
4. Реализовать SQL-таблицы и загрузку/сохранение при логине/спавне
5. Тестирование изоляции в одном окне:
```
.matrix 1 → игрок в матрице 1
.spawndancer 1401 → NPC наследует матрицу 1, виден игроку
.matrix 0 → игрок возвращается в сток, NPC исчезает
.matrix 1 → NPC снова появляется
```
## 8. Среда разработки
- **Ядро:** TrinityCore master (Dragonflight 12.x)
- **Клиент:** WoW Retail 12.0.1.65867
- **ОС:** Windows 11 x64
- **IDE:** Visual Studio
- **БД:** MySQL (world, hotfixes)
- **Лаунчер:** Arctium Game Launcher / Burralis (кастомный клиент)
- **Пути:** `G:\TRIN\SERVAK_STUFF\TrinityCore\src\server\game\Entities\Object\`
## 9. Ключевые источники в коде
| Файл | Что содержит |
|---|---|
| `src/server/game/DataStores/DB2Structure.h` | `struct PhaseEntry`, все DB2-структуры |
| `src/server/game/DataStores/DBCEnums.h` | `PhaseEntryFlags`, все enum-флаги |
| `src/server/game/Entities/Object/Object.h` | `InSamePhase()`, `_phaseShift`, `_dbPhase`, поля WorldObject |
| `src/server/game/Entities/Object/Object.cpp` | `CanNeverSee()` |
| `hotfixes.phase` | Кастомные фазы (ID, Flags, VerifiedBuild) |
| `world.creature` | Поля `PhaseId`, `PhaseGroup`, `phaseUseFlags` |