using ProjectM.Simulation; using Unity.Entities; using UnityEngine; namespace ProjectM.Authoring { /// /// Authoring for the player ghost prefab. As of M3 the numeric tunables live in data /// ( / ScriptableObjects); /// this authoring only selects which definitions the player uses and bakes the light id refs, the /// (empty) replicated modifier buffer, and the zeroed effective-stat components that /// StatRecomputeSystem fills each predicted tick. Health is seeded from the character definition's /// MaxHealth (single source). Ghost replication, GhostOwner and AutoCommandTarget come from /// the GhostAuthoringComponent on the same prefab GameObject; GetEntity(TransformUsageFlags.Dynamic) /// ensures a runtime-mutable LocalTransform exists. /// public class PlayerAuthoring : MonoBehaviour { [Tooltip("Character-stats definition (move speed, turn rate, max health). Single source of those values.")] public CharacterStatsDefinition Character; [Tooltip("Ability definition occupying the player's primary slot.")] public AbilityDefinition PrimaryAbility; [Header("Fallbacks (used only if a definition above is unassigned)")] [Min(0f)] public float FallbackMaxHealth = 100f; /// Projectile hit-test radius for the player as a damageable target, in world units. [Min(0f)] public float HitRadius = 0.6f; private class PlayerBaker : Baker { public override void Bake(PlayerAuthoring authoring) { var entity = GetEntity(authoring, TransformUsageFlags.Dynamic); // Re-bake when a referenced definition's serialized values change. if (authoring.Character != null) DependsOn(authoring.Character); if (authoring.PrimaryAbility != null) DependsOn(authoring.PrimaryAbility); byte characterId = authoring.Character != null ? (byte)authoring.Character.Id : (byte)CharacterId.Default; byte abilityId = authoring.PrimaryAbility != null ? (byte)authoring.PrimaryAbility.Id : (byte)AbilityId.Primary; float maxHealth = authoring.Character != null ? authoring.Character.MaxHealth : authoring.FallbackMaxHealth; AddComponent(entity); AddComponent(entity); AddComponent(entity); // Data-driven stat refs (replace M2's inlined PlayerMoveStats / AbilityStats values). AddComponent(entity, new CharacterStatsRef { Id = characterId }); AddComponent(entity, new AbilityRef { Id = abilityId }); // Effective stats: zeroed at bake, recomputed every predicted tick by StatRecomputeSystem. AddComponent(entity, new EffectiveAbilityStats()); AddComponent(entity, new EffectiveCharacterStats()); // Empty replicated modifier stack (grown by upgrades/pickups/debug hook, server-authoritative). AddBuffer(entity); // Combat: server-authoritative health (Current replicated for display), the player's // damageable hit radius, predicted cooldown state, and the per-tick damage inbox. AddComponent(entity, new Health { Current = maxHealth, Max = maxHealth }); AddComponent(entity, new HitRadius { Value = authoring.HitRadius }); AddComponent(entity); AddBuffer(entity); } } } }