using Godot; using System.Collections.Generic; using Rokojori.Extensions; namespace Rokojori; [Tool] [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")] public partial class Receptor:Action { [Export] public SceneCondition sceneCondition; [Export( PropertyHint.Range, "0.1,100")] public float receiptionTriggerCoverage = 75f; [Export( PropertyHint.Range, "10,2000")] public float receiptionWindowDurationMS = 500f; [Export( PropertyHint.Range, "10,1000")] public float tickRateMS = 100f; [Export] public Timeline timeline; int resultSize => Mathf.CeilToInt( receiptionWindowDurationMS / tickRateMS ); RingBuffer _resultsBuffer; bool _activated = false; public bool activated => _activated; bool _active = false; public bool active => _active; int _eventID = -1; public void Start() { if ( _active ) { return; } _active = true; var duration = tickRateMS / 1000f; var tle = TimelineManager.ScheduleLoopEvent( timeline, duration, 0, tle => Sample() ); _eventID = tle.id; } public void Stop() { if ( ! _active ) { return; } _active = false; TimelineManager.RemoveEvent( timeline, _eventID ); _eventID = -1; } protected override void _OnTrigger() { Sample(); } void Sample() { if ( sceneCondition == null ) { return; } if ( _resultsBuffer == null || _resultsBuffer.capacity != resultSize ) { _resultsBuffer = new RingBuffer( resultSize ); } _resultsBuffer.Add( sceneCondition.Evaluate() ); if ( _resultsBuffer.count != resultSize ) { _activated = false; return; } var numActive = _resultsBuffer.CountItems( b => b ); _activated = numActive / (float) resultSize >= receiptionTriggerCoverage / 100f; } }