using Godot; using System.Collections.Generic; using System; namespace Rokojori { [Tool] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/SensorManager.svg")] public partial class SensorManager: Node { [Export] public bool initializeOnReady = true; [Export] public Sensor[] sensors = new Sensor[ 0 ]; [Export] public SensorGroup[] sensorGroups = new SensorGroup[ 0 ]; [Export] public bool processSensors = false; [Export] public Node[] autoScanForSensors = new Node[ 0 ]; [Export] public bool separateMouseAndKeyboardTracking = false; [Export] public Action onActiveDeviceChange; public readonly EventSlot _onActiveDeviceChange = new EventSlot(); [ExportGroup("Read Only")] [Export] public SensorDevice[] deviceList = new SensorDevice[]{}; [Export] public float[] deviceLastInputTimeStamp = new float[]{}; [ExportGroup("Testing")] [Export] public SensorDevice testingLastActiveDevice; List runners = new List(); List inputers = new List(); Dictionary sensorToRunner = new Dictionary(); KeyboardDevice keyboardDevice = new KeyboardDevice(); MouseDevice mouseDevice = new MouseDevice(); GamePadDevice gamePadDevice = new GamePadDevice(); MultiSensorDevice mouseKeyboardDevice = new MultiSensorDevice(); DateTime _startTime; public SensorDevice lastActiveDevice { get { if ( testingLastActiveDevice != null ) { return testingLastActiveDevice; } var highest = Lists.IndexOfHighestValue( Lists.From( deviceLastInputTimeStamp ), t => t ); if ( highest == -1 ) { return null; } return deviceList[ highest ]; } } void UpdateDevice( SensorDevice d ) { var lastActive = lastActiveDevice; var index = Arrays.IndexOf( deviceList, d ); if ( index == -1 ) { deviceList = Arrays.Add( deviceList, d ); index = deviceList.Length - 1; deviceLastInputTimeStamp = Arrays.Add( deviceLastInputTimeStamp, 0 ); } deviceLastInputTimeStamp[ index ] = (float) ( DateTime.Now - _startTime ).TotalSeconds; if ( lastActive == lastActiveDevice ) { return; } Action.Trigger( onActiveDeviceChange ); _onActiveDeviceChange.DispatchEvent( null ); } public void UpdateLastActiveDevice( Sensor sensor, int index ) { if ( keyboardDevice.ContainsSensor( sensor ) ) { UpdateDevice( separateMouseAndKeyboardTracking ? keyboardDevice : mouseKeyboardDevice ); return; } if ( mouseDevice.ContainsSensor( sensor ) ) { UpdateDevice( separateMouseAndKeyboardTracking ? mouseDevice : mouseKeyboardDevice ); return; } if ( gamePadDevice.ContainsSensor( sensor ) ) { var device = Arrays.Find( deviceList, d => d is GamePadDevice gpd && gpd.deviceIndex == index ); if ( device == null ) { var gpd = new GamePadDevice(); gpd.deviceIndex = index; gpd.deviceName = Input.GetJoyName( index ); device = gpd; } UpdateDevice( device ); } } public override void _Ready() { _startTime = DateTime.Now; mouseKeyboardDevice.devices = new SensorDevice[]{ mouseDevice, keyboardDevice }; if ( ! initializeOnReady ) { return; } CreateRunners(); } public override void _Input( InputEvent ev ) { inputers.ForEach( ( inp )=> { inp._Input( ev ); } ); } public override void _Process( double delta ) { if ( Engine.IsEditorHint() || ! processSensors ) { return; } runners.ForEach( r => r.Update( (float) delta ) ); } public void Register( Sensor s, SensorInputHandler sih ) { var sensorRunner = sensorToRunner[ s ]; if ( sensorRunner.listeners.Contains( sih ) ) { return; } sensorRunner.listeners.Add( sih ); } public void Unregister( Sensor s, SensorInputHandler sih ) { var sensorRunner = sensorToRunner[ s ]; sensorRunner.listeners.Remove( sih ); } public static void Register( SensorInputHandler handler, params Sensor[] sensors ) { var sm = Unique.Get(); foreach ( var s in sensors ) { if ( s == null ) { continue; } ( handler as Node ).LogInfo( "Registrating", HierarchyName.Of( (Node)handler) ); sm.Register( s, handler ); } } public static void Unregister( SensorInputHandler handler, params Sensor[] sensors ) { var sm = Unique.Get(); foreach ( var s in sensors ) { if ( s == null ) { continue; } ( handler as Node ).LogInfo( "Unregistrating" ); sm.Unregister( s, handler ); } } HashSet sensorsSet = new HashSet(); void AddSensor( Sensor s ) { if ( s == null || sensorsSet.Contains( s ) ) { // this.LogInfo( "Not including:", HierarchyName.Of( s ) ); return; } this.LogInfo( "Including:", HierarchyName.Of( s ) ); AddSensorsFrom( s ); sensorsSet.Add( s ); runners.Add( new SensorRunner( s ) ); } HashSet objects = new HashSet(); void AddSensorsFrom( object obj ) { if ( obj == null || objects.Contains( obj ) ) { return; } objects.Add( obj ); var sensors = ReflectionHelper.GetDataMemberValues( obj ); sensors.ForEach( s => { AddSensor( s ); } ); var sensorArrays = ReflectionHelper.GetDataMemberValues( obj ); sensorArrays.ForEach( s => { for ( int i = 0; i < s.Length; i++ ) { AddSensor( s[ i ] ); } } ); var resources = ReflectionHelper.GetDataMemberValues( obj ); resources.ForEach( r => AddSensorsFrom( r ) ); } void CreateRunners() { if ( sensors == null ) { sensors = new Sensor[]{}; } if ( sensorGroups == null ) { sensorGroups = new SensorGroup[]{}; } foreach ( var s in sensors ) { AddSensor( s ); } foreach ( var g in sensorGroups ) { foreach ( var s in g.sensors ) { AddSensor( s ); } } foreach ( var n in autoScanForSensors ) { Nodes.ForEach( n, cn=> AddSensorsFrom( cn ) ); } runners.ForEach( r => { sensorToRunner[ r.sensor ] = r; if ( r.sensor is iOnInputSensor oi ) { inputers.Add( oi ); } } ); this.LogInfo( "Created runners:", runners.Count ); } } }