fix: Manager OnDestroy 关闭 SQLite 连接,修复 domain reload 崩溃
- 所有 Manager 在 Awake 保存 _db 引用,OnDestroy 调用 Close() - ScenarioManager/ModelManager/ReportManager/GroupManager/SimulationRunner 全部修复 - 崩溃原因:domain reload 时 GC finalizer 线程清理 prepared statements,DB 未关闭导致 sqlite3_finalize 竞态
This commit is contained in:
parent
b957a5e2b4
commit
2bb8ba2e1e
17
AGENTS.md
17
AGENTS.md
@ -76,19 +76,22 @@ pwsh scripts/check_unity_build.ps1
|
|||||||
|
|
||||||
This automatically rebuilds Core.dll, copies it to Unity Plugins, and compiles Unity scripts. Exits 0 if all pass.
|
This automatically rebuilds Core.dll, copies it to Unity Plugins, and compiles Unity scripts. Exits 0 if all pass.
|
||||||
|
|
||||||
## 7. Run Targeted Tests, Not Full Suite
|
## 7. Run Targeted Tests First
|
||||||
|
|
||||||
**Never run all tests unless explicitly asked.** Always use `--filter` to run only the tests relevant to what you changed.
|
**Always run the narrowest relevant test first.** If you just changed `DefensePlannerTests`, run `--filter 'FullyQualifiedName~DefensePlannerTests'`. If you changed `FullPipelineTests`, run that filter. Don't start with `dotnet test` on the whole project — it wastes time and buries the failures you're looking for.
|
||||||
|
|
||||||
|
Run full suite only after the targeted tests pass, to verify nothing else broke.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run a single test:
|
|
||||||
pwsh -Command "dotnet test test/unit/CounterDrone.Core.Tests/ --filter 'FullyQualifiedName~TestName'"
|
|
||||||
|
|
||||||
# Run a test class:
|
# Run a test class:
|
||||||
pwsh -Command "dotnet test test/unit/CounterDrone.Core.Tests/ --filter 'FullyQualifiedName~DefensePlannerTests'"
|
pwsh -Command "dotnet test test/unit/CounterDrone.Core.Tests/ --filter 'FullyQualifiedName~DefensePlannerTests'"
|
||||||
```
|
|
||||||
|
|
||||||
Running all 125+ tests wastes ~30 seconds every time and buries the failures you actually care about.
|
# Run a single test:
|
||||||
|
pwsh -Command "dotnet test test/unit/CounterDrone.Core.Tests/ --filter 'FullyQualifiedName~Scenario_AirBased'"
|
||||||
|
|
||||||
|
# Run full suite (only after targeted passes):
|
||||||
|
pwsh -Command "dotnet test test/unit/CounterDrone.Core.Tests/"
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -11,16 +11,19 @@ namespace CounterDrone.Unity
|
|||||||
public class GroupManager : MonoBehaviour
|
public class GroupManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
private IGroupService _service;
|
private IGroupService _service;
|
||||||
|
private SQLite.SQLiteConnection _db;
|
||||||
|
|
||||||
public IGroupService Service => _service;
|
public IGroupService Service => _service;
|
||||||
|
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
var paths = new UnityPathProvider();
|
var paths = new UnityPathProvider();
|
||||||
var db = new DatabaseManager(paths).OpenMainDb();
|
_db = new DatabaseManager(paths).OpenMainDb();
|
||||||
_service = new GroupService(new GroupRepository(db));
|
_service = new GroupService(new GroupRepository(_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnDestroy() => _db?.Close();
|
||||||
|
|
||||||
public Group Create(string name, GroupType type, string desc = "")
|
public Group Create(string name, GroupType type, string desc = "")
|
||||||
=> _service.CreateGroup(name, type, desc);
|
=> _service.CreateGroup(name, type, desc);
|
||||||
|
|
||||||
|
|||||||
@ -13,16 +13,19 @@ namespace CounterDrone.Unity
|
|||||||
{
|
{
|
||||||
private IModelService _service;
|
private IModelService _service;
|
||||||
private IPathProvider _paths;
|
private IPathProvider _paths;
|
||||||
|
private SQLite.SQLiteConnection _db;
|
||||||
|
|
||||||
public IModelService Service => _service;
|
public IModelService Service => _service;
|
||||||
|
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
_paths = new UnityPathProvider();
|
_paths = new UnityPathProvider();
|
||||||
var db = new DatabaseManager(_paths).OpenMainDb();
|
_db = new DatabaseManager(_paths).OpenMainDb();
|
||||||
_service = new ModelService(new ModelRepository(db), _paths);
|
_service = new ModelService(new ModelRepository(_db), _paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnDestroy() => _db?.Close();
|
||||||
|
|
||||||
public ModelInfo Import(string filePath, string name) => _service.ImportModel(filePath, name);
|
public ModelInfo Import(string filePath, string name) => _service.ImportModel(filePath, name);
|
||||||
public void Delete(string id) => _service.DeleteModel(id);
|
public void Delete(string id) => _service.DeleteModel(id);
|
||||||
public List<ModelInfo> GetAll() => _service.GetAllModels();
|
public List<ModelInfo> GetAll() => _service.GetAllModels();
|
||||||
|
|||||||
@ -11,16 +11,19 @@ namespace CounterDrone.Unity
|
|||||||
{
|
{
|
||||||
private IReportService _service;
|
private IReportService _service;
|
||||||
private IPathProvider _paths;
|
private IPathProvider _paths;
|
||||||
|
private SQLite.SQLiteConnection _db;
|
||||||
|
|
||||||
public IReportService Service => _service;
|
public IReportService Service => _service;
|
||||||
|
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
_paths = new UnityPathProvider();
|
_paths = new UnityPathProvider();
|
||||||
var db = new DatabaseManager(_paths).OpenMainDb();
|
_db = new DatabaseManager(_paths).OpenMainDb();
|
||||||
_service = new ReportService(db, _paths);
|
_service = new ReportService(_db, _paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnDestroy() => _db?.Close();
|
||||||
|
|
||||||
public SimulationReport Generate(string taskId, TaskFullConfig cfg, List<SimEvent> events, string status, float duration)
|
public SimulationReport Generate(string taskId, TaskFullConfig cfg, List<SimEvent> events, string status, float duration)
|
||||||
=> _service.Generate(taskId, cfg, events, status, duration);
|
=> _service.Generate(taskId, cfg, events, status, duration);
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ namespace CounterDrone.Unity
|
|||||||
public class ScenarioManager : MonoBehaviour
|
public class ScenarioManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
private IScenarioService _service;
|
private IScenarioService _service;
|
||||||
|
private SQLite.SQLiteConnection _db;
|
||||||
|
|
||||||
public IScenarioService Service => _service;
|
public IScenarioService Service => _service;
|
||||||
|
|
||||||
@ -20,12 +21,12 @@ namespace CounterDrone.Unity
|
|||||||
{
|
{
|
||||||
var paths = new UnityPathProvider();
|
var paths = new UnityPathProvider();
|
||||||
Debug.Log($"ScenarioManager.Awake: dbPath={paths.GetMainDbPath()}");
|
Debug.Log($"ScenarioManager.Awake: dbPath={paths.GetMainDbPath()}");
|
||||||
var db = new DatabaseManager(paths).OpenMainDb();
|
_db = new DatabaseManager(paths).OpenMainDb();
|
||||||
_service = new ScenarioService(
|
_service = new ScenarioService(
|
||||||
new SimTaskRepository(db), new CombatSceneRepository(db),
|
new SimTaskRepository(_db), new CombatSceneRepository(_db),
|
||||||
new ControlZoneRepository(db), new TargetConfigRepository(db),
|
new ControlZoneRepository(_db), new TargetConfigRepository(_db),
|
||||||
new EquipmentDeploymentRepository(db), new CloudDispersalRepository(db),
|
new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db),
|
||||||
new RoutePlanRepository(db), new WaypointRepository(db));
|
new RoutePlanRepository(_db), new WaypointRepository(_db));
|
||||||
Debug.Log("ScenarioManager.Awake: OK");
|
Debug.Log("ScenarioManager.Awake: OK");
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
@ -34,6 +35,8 @@ namespace CounterDrone.Unity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnDestroy() => _db?.Close();
|
||||||
|
|
||||||
public SimTask CreateTask(string name, string number) => _service.CreateTask(name, number);
|
public SimTask CreateTask(string name, string number) => _service.CreateTask(name, number);
|
||||||
public void DeleteTask(string id) => _service.DeleteTask(id);
|
public void DeleteTask(string id) => _service.DeleteTask(id);
|
||||||
public TaskFullConfig GetDetail(string id) => _service.GetTaskDetail(id);
|
public TaskFullConfig GetDetail(string id) => _service.GetTaskDetail(id);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ namespace CounterDrone.Unity
|
|||||||
private IScenarioService _scenario;
|
private IScenarioService _scenario;
|
||||||
private IPathProvider _paths;
|
private IPathProvider _paths;
|
||||||
private string _taskId;
|
private string _taskId;
|
||||||
|
private SQLite.SQLiteConnection _db;
|
||||||
|
|
||||||
private readonly Dictionary<string, GameObject> _entityVisuals = new();
|
private readonly Dictionary<string, GameObject> _entityVisuals = new();
|
||||||
private readonly Dictionary<string, GameObject> _clouds = new();
|
private readonly Dictionary<string, GameObject> _clouds = new();
|
||||||
@ -37,13 +38,13 @@ namespace CounterDrone.Unity
|
|||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
_paths = new UnityPathProvider();
|
_paths = new UnityPathProvider();
|
||||||
var db = new DatabaseManager(_paths).OpenMainDb();
|
_db = new DatabaseManager(_paths).OpenMainDb();
|
||||||
|
|
||||||
_scenario = new ScenarioService(
|
_scenario = new ScenarioService(
|
||||||
new SimTaskRepository(db), new CombatSceneRepository(db),
|
new SimTaskRepository(_db), new CombatSceneRepository(_db),
|
||||||
new ControlZoneRepository(db), new TargetConfigRepository(db),
|
new ControlZoneRepository(_db), new TargetConfigRepository(_db),
|
||||||
new EquipmentDeploymentRepository(db), new CloudDispersalRepository(db),
|
new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db),
|
||||||
new RoutePlanRepository(db), new WaypointRepository(db));
|
new RoutePlanRepository(_db), new WaypointRepository(_db));
|
||||||
|
|
||||||
_frameStore = new FrameDataStore(_paths);
|
_frameStore = new FrameDataStore(_paths);
|
||||||
_engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths);
|
_engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths);
|
||||||
@ -148,7 +149,7 @@ namespace CounterDrone.Unity
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Stop() => _engine?.Stop();
|
public void Stop() => _engine?.Stop();
|
||||||
void OnDestroy() => Stop();
|
void OnDestroy() { Stop(); _db?.Close(); }
|
||||||
|
|
||||||
private void SpawnDroneVisual(DroneEntity drone)
|
private void SpawnDroneVisual(DroneEntity drone)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user