From 4cd67023d9815690439b6172a22c941dc9c58ceb Mon Sep 17 00:00:00 2001 From: Minimata Date: Sat, 16 May 2026 01:29:02 +0200 Subject: [PATCH] token manager for projectile --- .../abilities/ForgeSpawnProjectileBehavior.cs | 6 +-- managers/TokenManager.cs | 49 +++++++++++++++++++ managers/TokenManager.cs.uid | 1 + maps/_templates/MainSceneTemplate.cs | 11 ++++- maps/zoos/grounded_flying_ennemies.tscn | 10 +++- scenes/enemies/Enemy.cs | 10 +++- scenes/projectile/Projectile.cs | 3 ++ 7 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 managers/TokenManager.cs create mode 100644 managers/TokenManager.cs.uid diff --git a/forge/abilities/ForgeSpawnProjectileBehavior.cs b/forge/abilities/ForgeSpawnProjectileBehavior.cs index 88fe1bcd..d51ea395 100644 --- a/forge/abilities/ForgeSpawnProjectileBehavior.cs +++ b/forge/abilities/ForgeSpawnProjectileBehavior.cs @@ -5,11 +5,12 @@ using Gamesmiths.Forge.Godot.Resources; using Gamesmiths.Forge.Godot.Resources.Abilities; using Godot; using Movementtests.interfaces; +using Movementtests.managers; using Movementtests.tools; namespace Movementtests.forge.abilities; -public record OnProjectileSpawned(Vector3 Direction, float SpeedMultiplier, Vector3? SpawnOffset = null, uint? CollisionOverride = null); +public record OnProjectileSpawned(Vector3 Direction, float SpeedMultiplier, Vector3? SpawnOffset = null, uint? CollisionOverride = null, TokenManager.Token? Token = null); public class SpawnProjectileBehavior(PackedScene projectileScene) : IAbilityBehavior { @@ -31,13 +32,12 @@ public class SpawnProjectileBehavior(PackedScene projectileScene) : IAbilityBeha var impulse = data.Direction * data.SpeedMultiplier * magnitude; var collisionOverride = data.CollisionOverride ?? projectile.CollisionMask; - GD.Print(impulse); - // Setting up projectile projectile.GlobalPosition = startPos + offset; projectile.Target = target; projectile.ImpulseDirection = impulse; projectile.CollisionMask = collisionOverride; + projectile.Token = data.Token; if (projectile is ISpawnable spawnable) spawnable.Init(); diff --git a/managers/TokenManager.cs b/managers/TokenManager.cs new file mode 100644 index 00000000..2dcf7486 --- /dev/null +++ b/managers/TokenManager.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Godot; + +namespace Movementtests.managers; + +[GlobalClass, Meta(typeof(IAutoNode))] +public partial class TokenManager : Node +{ + public override void _Notification(int what) => this.Notify(what); + + public record struct Token(ulong InstanceId, Action OnUse); + + private Dictionary Tokens { get; set; } = []; + public int TokenCount => Tokens.Count; + + private List RequestQueue { get; set; } = []; + + public int MaxTokens { get; set;} + + public void Initialize(int maxTokens) + { + MaxTokens = maxTokens; + } + + public Token? RequestToken(Node owner) + { + if (Tokens.ContainsKey(owner.GetInstanceId())) return null; // Already has a token + GD.Print(TokenCount); + if (RequestQueue.Contains(owner.GetInstanceId())) return null; // Already in queue + + RequestQueue.Add(owner.GetInstanceId()); + if (TokenCount >= MaxTokens) return null; // Max tokens reached + if (RequestQueue.First() != owner.GetInstanceId()) return null; // Next in line is not the requester + + RequestQueue.RemoveAt(0); + var token = new Token(owner.GetInstanceId(), () => UseToken(owner.GetInstanceId())); + Tokens.Add(token.InstanceId, token); + return token; + } + + public void UseToken(ulong instanceId) + { + Tokens.Remove(instanceId); + } +} \ No newline at end of file diff --git a/managers/TokenManager.cs.uid b/managers/TokenManager.cs.uid new file mode 100644 index 00000000..cdbc5f3e --- /dev/null +++ b/managers/TokenManager.cs.uid @@ -0,0 +1 @@ +uid://ckrhgyv5lv6xa diff --git a/maps/_templates/MainSceneTemplate.cs b/maps/_templates/MainSceneTemplate.cs index 224cfe42..7f7f8ab6 100644 --- a/maps/_templates/MainSceneTemplate.cs +++ b/maps/_templates/MainSceneTemplate.cs @@ -13,7 +13,7 @@ using Movementtests.systems; typeof(IAutoConnect), typeof(IProvider) )] -public partial class MainSceneTemplate : Node3D, IProvide, IProvide, IProvide +public partial class MainSceneTemplate : Node3D, IProvide, IProvide, IProvide, IProvide { public override void _Notification(int what) => this.Notify(what); @@ -31,6 +31,7 @@ public partial class MainSceneTemplate : Node3D, IProvide, IPr #region Exports [Export] public WeaponInventory? InitialWeaponInventory { get; set; } + [Export] public int MaxNumberOfProjectiles { get; set; } = 3; #endregion @@ -40,6 +41,9 @@ public partial class MainSceneTemplate : Node3D, IProvide, IPr TagsManager IProvide.Value() => ForgeManagers.Instance.TagsManager; CuesManager IProvide.Value() => ForgeManagers.Instance.CuesManager; + public required TokenManager TokenManager { get; set; } + TokenManager IProvide.Value() => TokenManager; + public void OnReady() { PlayerFellPlane.BodyEntered += StartResetPlayerAnimation; @@ -49,6 +53,11 @@ public partial class MainSceneTemplate : Node3D, IProvide, IPr if (InitialWeaponInventory != null) InventoryManager.InitializeFromResource(InitialWeaponInventory); AddChild(InventoryManager); + + TokenManager = new TokenManager(); + TokenManager.Initialize(MaxNumberOfProjectiles); + AddChild(TokenManager); + this.Provide(); } diff --git a/maps/zoos/grounded_flying_ennemies.tscn b/maps/zoos/grounded_flying_ennemies.tscn index 1bd8b362..acb69879 100644 --- a/maps/zoos/grounded_flying_ennemies.tscn +++ b/maps/zoos/grounded_flying_ennemies.tscn @@ -112,5 +112,13 @@ RMovement = SubResource("Resource_xixm3") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.0893264, -1.9073486e-06, -17.405575) Target = NodePath("../Player") -[node name="Player" parent="." index="16" unique_id=1309399929] +[node name="ProjectileEnemy2" parent="." index="15" unique_id=1908678308 node_paths=PackedStringArray("Target") instance=ExtResource("10_mm5sa")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.42922592, -3.8146973e-06, -20.257122) +Target = NodePath("../Player") + +[node name="ProjectileEnemy3" parent="." index="16" unique_id=1327447050 node_paths=PackedStringArray("Target") instance=ExtResource("10_mm5sa")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.4421315, -1.9073486e-06, -13.8114) +Target = NodePath("../Player") + +[node name="Player" parent="." index="18" unique_id=1309399929] transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 2, 1.5, 9.5) diff --git a/scenes/enemies/Enemy.cs b/scenes/enemies/Enemy.cs index bf753420..a349ba18 100644 --- a/scenes/enemies/Enemy.cs +++ b/scenes/enemies/Enemy.cs @@ -15,6 +15,7 @@ using Gamesmiths.Forge.Tags; using Godot; using Movementtests.forge.abilities; using Movementtests.interfaces; +using Movementtests.managers; using Movementtests.scenes.components.knockback; using Movementtests.systems; using Movementtests.tools; @@ -38,6 +39,8 @@ public partial class Enemy : CharacterBody3D, public TagsManager TagsManager => this.DependOn(); [Dependency] public CuesManager CuesManager => this.DependOn(); + [Dependency] + public TokenManager TokenManager => this.DependOn(); #endregion @@ -140,13 +143,16 @@ public partial class Enemy : CharacterBody3D, private void ProjectileTokenRequested(EventData obj) { if (IsStunned()) return; - // TODO: replace with token manager + + var token = TokenManager.RequestToken(this); + if (token == null) return; + Events.Raise(new EventData { EventTags = Tag.RequestTag(TagsManager, "events.enemy.launch_projectile").GetSingleTagContainer()!, Source = this, Target = Target as IForgeEntity, - Payload = new OnProjectileSpawned(Vector3.Up, 20, Vector3.Up) + Payload = new OnProjectileSpawned(Vector3.Up, 20, Vector3.Up, Token: token) }); } diff --git a/scenes/projectile/Projectile.cs b/scenes/projectile/Projectile.cs index f86a2c41..f97c34cb 100644 --- a/scenes/projectile/Projectile.cs +++ b/scenes/projectile/Projectile.cs @@ -11,6 +11,7 @@ using Gamesmiths.Forge.Godot.Resources.Abilities; using Gamesmiths.Forge.Statescript; using Gamesmiths.Forge.Tags; using Movementtests.interfaces; +using Movementtests.managers; using Movementtests.tools; using Node = Godot.Node; @@ -73,6 +74,7 @@ public partial class Projectile : RigidBody3D, IForgeEntity, ITargetable, IKilla public Node3D? Target { get; set; } public Vector3? ImpulseDirection { get; set; } + public TokenManager.Token? Token { get; set; } public void Init() { @@ -148,6 +150,7 @@ public partial class Projectile : RigidBody3D, IForgeEntity, ITargetable, IKilla public void Kill() { + Token?.OnUse.Invoke(); QueueFree(); // If thrown offmap } }