Set up DOTS + Netcode for Entities foundation

One-time stack setup per Docs/dots-setup-task.md (Unity 6.4.7 / 6000.4.7f1).
Packages: entities 6.4.0, entities.graphics 6.4.0, netcode 1.13.2, physics 1.4.6.

- Assets/_Project asmdef split: ProjectM.Simulation/Client/Server/Authoring (root ns ProjectM)
- GameBootstrap : ClientServerBootstrap; verified separate client + server worlds in Play Mode
- Gameplay subscene wired into SampleScene as a baking target
- Heartbeat component + Burst ISystem; EditMode smoke test green (1/1)
- In-repo Obsidian vault (Docs/Vault) incl. DR-001 (plain-Entities test over internal NetCodeTestWorld)
- Portable .mcp.json (basic-memory + serena via ${CLAUDE_PROJECT_DIR}); CLAUDE.md conventions
- .gitignore for DOTS baking cache + machine-local config

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Luis Gonzalez
2026-05-29 22:06:44 -07:00
parent 25e3493e75
commit 99d8d2d2a9
74 changed files with 1609 additions and 36 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1d1aa4405eacf4870a4a196c1003df87
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
{
"name": "ProjectM.Authoring",
"rootNamespace": "ProjectM.Authoring",
"references": [
"ProjectM.Simulation",
"Unity.Entities",
"Unity.Mathematics",
"Unity.NetCode"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 58fe4442d47fb4ab1a1de5ec2fa1bc4a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ea6b9bcd5e8084ceca808056442d4634
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,22 @@
{
"name": "ProjectM.Client",
"rootNamespace": "ProjectM.Client",
"references": [
"ProjectM.Simulation",
"Unity.Entities",
"Unity.Collections",
"Unity.Mathematics",
"Unity.Burst",
"Unity.NetCode",
"Unity.Entities.Graphics"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6b021a17bba824c5799f8f2c87ada5e3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 03b6366760d1f4cbc88f29039a6e70cf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
{
"name": "ProjectM.Server",
"rootNamespace": "ProjectM.Server",
"references": [
"ProjectM.Simulation",
"Unity.Entities",
"Unity.Collections",
"Unity.Mathematics",
"Unity.Burst",
"Unity.NetCode"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 634384718530e45608c20d4952b5acb2
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 090d9f42a3883497c9be2006e4fa486f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,24 @@
using Unity.Entities;
using Unity.NetCode;
using UnityEngine.Scripting;
namespace ProjectM.Simulation
{
/// <summary>
/// Custom Netcode for Entities bootstrap. Subclassing <see cref="ClientServerBootstrap"/>
/// gives an explicit hook to customize world creation, tick rate, and auto-connect.
/// For now it reproduces the default behavior: create separate client and server worlds
/// based on the Multiplayer PlayMode Tools settings, without auto-connecting.
/// </summary>
[Preserve]
public class GameBootstrap : ClientServerBootstrap
{
public override bool Initialize(string defaultWorldName)
{
// 0 = do not auto-connect; worlds are still created. Set a port later to auto-connect.
AutoConnectPort = 0;
CreateDefaultClientServerWorlds();
return true;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9f727ee3d680248a8b0e2e55d234ab5f
@@ -0,0 +1,13 @@
using Unity.Entities;
namespace ProjectM.Simulation
{
/// <summary>
/// Trivial unmanaged component used by the setup smoke test to prove the ECS
/// compile + source-gen + tick path works. Safe to delete once real gameplay exists.
/// </summary>
public struct Heartbeat : IComponentData
{
public int Tick;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a0347bd6d99db438f85ec1985b7f81e1
@@ -0,0 +1,23 @@
using Unity.Burst;
using Unity.Entities;
namespace ProjectM.Simulation
{
/// <summary>
/// Smoke-test system: increments every <see cref="Heartbeat"/> once per tick.
/// Default (no <c>[WorldSystemFilter]</c>) so it runs in the SimulationSystemGroup of
/// every world. Burst-compiled and unmanaged (<see cref="ISystem"/>) per DOTS convention.
/// </summary>
[BurstCompile]
public partial struct HeartbeatSystem : ISystem
{
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
foreach (var heartbeat in SystemAPI.Query<RefRW<Heartbeat>>())
{
heartbeat.ValueRW.Tick++;
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 78349f49733934f348acb488689fc9ec
@@ -0,0 +1,21 @@
{
"name": "ProjectM.Simulation",
"rootNamespace": "ProjectM.Simulation",
"references": [
"Unity.Entities",
"Unity.Collections",
"Unity.Mathematics",
"Unity.Burst",
"Unity.Physics",
"Unity.NetCode"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 113bb240387ed4cd397f37597898de62
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: