diff --git a/Icons/UIRule.svg b/Icons/UIRule.svg new file mode 100644 index 0000000..2572058 --- /dev/null +++ b/Icons/UIRule.svg @@ -0,0 +1,201 @@ + + diff --git a/Icons/UIRule.svg.import b/Icons/UIRule.svg.import new file mode 100644 index 0000000..bb3a487 --- /dev/null +++ b/Icons/UIRule.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b53un3tjulppj" +path="res://.godot/imported/UIRule.svg-dd35f8a9b19c4e01c4e95c28eb989981.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/rokojori_action_library/Icons/UIRule.svg" +dest_files=["res://.godot/imported/UIRule.svg-dd35f8a9b19c4e01c4e95c28eb989981.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/Icons/UIRuleSet.svg b/Icons/UIRuleSet.svg new file mode 100644 index 0000000..b12124d --- /dev/null +++ b/Icons/UIRuleSet.svg @@ -0,0 +1,414 @@ + + diff --git a/Icons/UIRuleSet.svg.import b/Icons/UIRuleSet.svg.import new file mode 100644 index 0000000..1e1afc7 --- /dev/null +++ b/Icons/UIRuleSet.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqo22c1m73dyu" +path="res://.godot/imported/UIRuleSet.svg-421bda2d7476eddcafe1e07da9c0badf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/rokojori_action_library/Icons/UIRuleSet.svg" +dest_files=["res://.godot/imported/UIRuleSet.svg-421bda2d7476eddcafe1e07da9c0badf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/Icons/UISelector.svg b/Icons/UISelector.svg new file mode 100644 index 0000000..bb08e74 --- /dev/null +++ b/Icons/UISelector.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Icons/UISelector.svg.import b/Icons/UISelector.svg.import new file mode 100644 index 0000000..91d2b89 --- /dev/null +++ b/Icons/UISelector.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6rml2liif4ns" +path="res://.godot/imported/UISelector.svg-1da3b1c2f5d0e50773a94b5a365f6476.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/rokojori_action_library/Icons/UISelector.svg" +dest_files=["res://.godot/imported/UISelector.svg-1da3b1c2f5d0e50773a94b5a365f6476.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/Runtime/Actions/Action.cs b/Runtime/Actions/Action.cs index 676a827..56d1fb8 100644 --- a/Runtime/Actions/Action.cs +++ b/Runtime/Actions/Action.cs @@ -3,208 +3,225 @@ using Godot; using System.Collections.Generic; -namespace Rokojori -{ - [Tool] - [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")] - public partial class Action : NetworkNode +namespace Rokojori; + +[Tool] +[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")] +public partial class Action : NetworkNode +{ + public enum ActionTriggerMode { - public enum ActionTriggerMode + Only_When_Processing_In_Hierarchy, + Always + } + + [Export] + public ActionTriggerMode triggerMode = ActionTriggerMode.Always; + + #if !GD_SCRIPT_TRANSPILING + + [ExportToolButton( "(?) Help", Icon = "Help") ] + public Callable openHelpButton => Callable.From( ()=> + { + #if TOOLS + Rokojori.Tools.OnlineDocs.Open( GetType() ); + #endif + } + ); + + #endif + + [ExportToolButton( "Trigger Action in Editor")] + public Callable TriggerActionButton => Callable.From( ()=> Trigger() ); + + #if !GD_SCRIPT_TRANSPILING + + public static bool IsAction( Node n ) + { + if ( n == null ) { - Only_When_Processing_In_Hierarchy, - Always + return false; } - [Export] - public ActionTriggerMode triggerMode = ActionTriggerMode.Only_When_Processing_In_Hierarchy; - - [ExportToolButton( "(?) Help", Icon = "Help") ] - public Callable openHelpButton => Callable.From( ()=> - { - #if TOOLS - Rokojori.Tools.OnlineDocs.Open( GetType() ); - #endif - } - ); - - [ExportToolButton( "Trigger Action in Editor")] - public Callable TriggerActionButton => Callable.From( ()=> Trigger() ); - - NetworkNodeSlot _seedSlot = new NetworkNodeSlot(); - NetworkNodeSlot _dataSlot = new NetworkNodeSlot(); - NetworkNodeSlot _seedAndDataSlot = new NetworkNodeSlot(); - - public static bool IsAction( Node n ) - { - if ( n == null ) - { - return false; - } - - return n is Action || GDScriptAction.IsRJAction( n ); - } - - public void LogInfoFor( Node n, string message ) - { - var className = GDScriptNames.ExtractClassName( n ); - RJLog.GDLog( $"{className}._onTrigger()", n, message ); - } - - - protected override List CreateNetworkNodeMembers() - { - return new List() - { - _networkNodeSlot, - _seedSlot, - _dataSlot, - _seedAndDataSlot - }; - } - - public Action() - { - - } - - public void Trigger() - { - if ( ! IsInstanceValid( this ) ) - { - return; - } - - if ( triggerMode == ActionTriggerMode.Only_When_Processing_In_Hierarchy && ! this.IsProcessingInHierarchy() ) - { - return; - } - - _isNetworkedTrigger = false; - _sendsSeed = false; - _sendsData = false; - _OnTrigger(); - - SendOverNetwork(); - - } - - protected void SendOverNetwork() - { - // check which type - // 0 0 => vanilla - // 1 0 => with seed - // 0 1 => with data - // 1 1 => with seed + data - } - - protected void _OnNetworkTrigger( int seed, BitView data ) - { - _isNetworkedTrigger = true; - _receivedNetworkSeed = seed; - _receivedNetworkData = data; - - _OnTrigger(); - - _isNetworkedTrigger = false; - } - - bool _isNetworkedTrigger = false; - int _receivedNetworkSeed = -1; - int _sendingNetworkSeed = -1; - - bool _sendsSeed = false; - bool _sendsData = false; - - BitView _sendingNetworkData; - BitView _receivedNetworkData; - - public bool isNetworkedTrigger => _isNetworkedTrigger; - - static readonly int maxNetworkSeed = Mathf.RoundToInt( Mathf.Pow( 2, 30 ) ); - - protected int networkSeed - { - get - { - if ( _isNetworkedTrigger ) - { - return _receivedNetworkSeed; - } - - if ( _sendsSeed ) - { - return _sendingNetworkSeed; - } - - _sendingNetworkSeed = GodotRandom.Get().IntegerExclusive( 0, maxNetworkSeed ); - _sendsSeed = true; - - return _sendingNetworkSeed; - } - } - - protected BitView GetNetworkData( BitView view ) - { - if ( _isNetworkedTrigger ) - { - return _receivedNetworkData; - } - - _sendingNetworkData = view; - _sendsData = true; - return _sendingNetworkData; - } - - protected virtual void _OnTrigger() - { - - } + return n is Action || GDScriptAction.IsRJAction( n ); + } - public static void Trigger( Action action ) + public void LogInfoFor( Node n, string message ) + { + var className = GDScriptNames.ExtractClassName( n ); + RJLog.GDLog( $"{className}._onTrigger()", n, message ); + } + + #endif + + public void Trigger() + { + if ( ! IsInstanceValid( this ) ) { - if ( action == null ) - { - return; - } - - action.Trigger(); + return; } - public static void TriggerAll( Action[] actions, Node target, bool triggerDirectChildren, Action caller = null ) + if ( triggerMode == ActionTriggerMode.Only_When_Processing_In_Hierarchy && ! this.IsProcessingInHierarchy() ) { - if ( actions != null ) - { - for ( int i = 0; i < actions.Length; i++ ) - { - Action.Trigger( actions[ i ] ); - } - } - - if ( ! triggerDirectChildren ) - { - return; - } - - Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) ); + return; } - public static void TriggerAll( Action action, Node target, bool triggerDirectChildren ) + #if !GD_SCRIPT_TRANSPILING + + _isNetworkedTrigger = false; + _sendsSeed = false; + _sendsData = false; + + #endif + + _OnTrigger(); + + #if !GD_SCRIPT_TRANSPILING + + SendOverNetwork(); + + #endif + + } + + protected virtual void _OnTrigger() + { + + } + + #if !GD_SCRIPT_TRANSPILING + + NetworkNodeSlot _seedSlot = new NetworkNodeSlot(); + NetworkNodeSlot _dataSlot = new NetworkNodeSlot(); + NetworkNodeSlot _seedAndDataSlot = new NetworkNodeSlot(); + + protected void SendOverNetwork() + { + // check which type + // seed data => type + // 0 0 => vanilla + // 1 0 => with seed + // 0 1 => with data + // 1 1 => with seed + data + } + + protected override List CreateNetworkNodeMembers() + { + return new List() { - if ( action != null ) + _networkNodeSlot, + _seedSlot, + _dataSlot, + _seedAndDataSlot + }; + } + + protected void _OnNetworkTrigger( int seed, BitView data ) + { + _isNetworkedTrigger = true; + _receivedNetworkSeed = seed; + _receivedNetworkData = data; + + _OnTrigger(); + + _isNetworkedTrigger = false; + } + + bool _isNetworkedTrigger = false; + int _receivedNetworkSeed = -1; + int _sendingNetworkSeed = -1; + + bool _sendsSeed = false; + bool _sendsData = false; + + BitView _sendingNetworkData; + BitView _receivedNetworkData; + + public bool isNetworkedTrigger => _isNetworkedTrigger; + + static readonly int maxNetworkSeed = Mathf.RoundToInt( Mathf.Pow( 2, 30 ) ); + + protected int networkSeed + { + get + { + if ( _isNetworkedTrigger ) { - Action.Trigger( action ); - + return _receivedNetworkSeed; + } + + if ( _sendsSeed ) + { + return _sendingNetworkSeed; } - if ( ! triggerDirectChildren ) - { - return; - } + _sendingNetworkSeed = GodotRandom.Get().IntegerExclusive( 0, maxNetworkSeed ); + _sendsSeed = true; - Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) ); + return _sendingNetworkSeed; } } -} \ No newline at end of file + protected BitView GetNetworkData( BitView view ) + { + if ( _isNetworkedTrigger ) + { + return _receivedNetworkData; + } + + _sendingNetworkData = view; + _sendsData = true; + return _sendingNetworkData; + } + + + + public static void Trigger( Action action ) + { + if ( action == null ) + { + return; + } + + action.Trigger(); + } + + public static void TriggerAll( Action[] actions, Node target, bool triggerDirectChildren, Action caller = null ) + { + if ( actions != null ) + { + for ( int i = 0; i < actions.Length; i++ ) + { + Action.Trigger( actions[ i ] ); + } + } + + if ( ! triggerDirectChildren ) + { + return; + } + + Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) ); + } + + public static void TriggerAll( Action action, Node target, bool triggerDirectChildren ) + { + if ( action != null ) + { + Action.Trigger( action ); + + } + + if ( ! triggerDirectChildren ) + { + return; + } + + Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) ); + } + + #endif +} + diff --git a/Runtime/Actions/Audio/MusicChannel.cs b/Runtime/Actions/Audio/MusicChannel.cs new file mode 100644 index 0000000..3ab0cd8 --- /dev/null +++ b/Runtime/Actions/Audio/MusicChannel.cs @@ -0,0 +1,17 @@ + +using Godot; + +namespace Rokojori; + +[Tool] +[GlobalClass] +public partial class MusicChannel:Resource +{ + [Export] + public string playerName = ""; + + [Export] + public StringName audioBus = ""; + +} + diff --git a/Runtime/Actions/Audio/MusicChannel.cs.uid b/Runtime/Actions/Audio/MusicChannel.cs.uid new file mode 100644 index 0000000..8b98c4a --- /dev/null +++ b/Runtime/Actions/Audio/MusicChannel.cs.uid @@ -0,0 +1 @@ +uid://cs3ypfgd1r603 diff --git a/Runtime/Actions/Audio/MusicChannelPlayer.cs b/Runtime/Actions/Audio/MusicChannelPlayer.cs new file mode 100644 index 0000000..0693e0c --- /dev/null +++ b/Runtime/Actions/Audio/MusicChannelPlayer.cs @@ -0,0 +1,89 @@ + +using Godot; + +namespace Rokojori; + +[Tool] +[GlobalClass] +public partial class MusicChannelPlayer:Node +{ + [Export] + public MusicChannel channel; + + [Export] + public MusicData currentMusic; + + [Export] + public AudioStreamPlayer currentPlayer; + + + public void TweenVolume( AudioStreamPlayer target, float duration, float toVolume, bool clear, System.Action onReady = null ) + { + var tl = TimeLineManager.Ensure( null ); + var start = tl.position; + var fromVolume = target.VolumeLinear; + + TimeLineManager.ScheduleSpanIn( tl, 0, duration, + ( span, type )=> + { + if ( ! GodotObject.IsInstanceValid( target ) ) + { + return; + } + + var lerpedVolume = Mathf.Lerp( fromVolume, toVolume, span.phase ); + target.VolumeLinear = lerpedVolume; + + if ( type == TimeLineSpanUpdateType.End && clear ) + { + if ( clear ) + { + ClearAudioPlayer( target ); + } + + if ( onReady != null ) + { + onReady(); + } + + } + + }, + this + ); + } + + async void ClearAudioPlayer( AudioStreamPlayer target ) + { + await this.RequestNextFrame(); + target.DeleteSelf(); + } + + public void SchedulePlayer( MusicData nextMusic, float duration, System.Action onReady ) + { + if ( currentMusic != null ) + { + this.LogInfo( "Muting:", currentMusic ); + TweenVolume( currentPlayer, duration, 0f, true ); + currentMusic = null; + currentPlayer = null; + } + + this.LogInfo( "Playing:", nextMusic ); + + var name = FilePath.Absolute( nextMusic.audio.ResourcePath ).fileName; + var nextPlayer = this.CreateChild( "Player " + name ); + nextPlayer.VolumeLinear = 0f; + nextPlayer.Stream = nextMusic.audio; + nextPlayer.PitchScale = MathAudio.SemitonesToFrequencyScaler( nextMusic.pitchSemitonesOffset ); + nextPlayer.Bus = channel.audioBus; + + currentMusic = nextMusic; + currentPlayer = nextPlayer; + TweenVolume( nextPlayer, duration, nextMusic.volume, false, onReady ); + + nextPlayer.Play(); + } + +} + diff --git a/Runtime/Actions/Audio/MusicChannelPlayer.cs.uid b/Runtime/Actions/Audio/MusicChannelPlayer.cs.uid new file mode 100644 index 0000000..19ee9e4 --- /dev/null +++ b/Runtime/Actions/Audio/MusicChannelPlayer.cs.uid @@ -0,0 +1 @@ +uid://nwt0qlwimulf diff --git a/Runtime/Actions/Audio/MusicData.cs b/Runtime/Actions/Audio/MusicData.cs new file mode 100644 index 0000000..f23b550 --- /dev/null +++ b/Runtime/Actions/Audio/MusicData.cs @@ -0,0 +1,26 @@ + +using Godot; + +namespace Rokojori; + +[Tool] +[GlobalClass] +public partial class MusicData: Resource +{ + [Export] + public Godot.AudioStream audio; + + [Export( PropertyHint.Range, "0,1")] + public float volume = 1f; + + [Export( PropertyHint.Range, "-36,36")] + public float pitchSemitonesOffset = 0f; + + public override string ToString() + { + var prefix = pitchSemitonesOffset == 0 ? "+/-" : pitchSemitonesOffset > 0 ? "+" : ""; + return "MusicData: " + (100 * volume)._FF() + "% (" + prefix + pitchSemitonesOffset + " st) " + audio.ResourcePath; + } + +} + diff --git a/Runtime/Actions/Audio/MusicData.cs.uid b/Runtime/Actions/Audio/MusicData.cs.uid new file mode 100644 index 0000000..0b9cc40 --- /dev/null +++ b/Runtime/Actions/Audio/MusicData.cs.uid @@ -0,0 +1 @@ +uid://b5443aoeefkin diff --git a/Runtime/Actions/Audio/ScheduleMusic.cs b/Runtime/Actions/Audio/ScheduleMusic.cs new file mode 100644 index 0000000..e726bad --- /dev/null +++ b/Runtime/Actions/Audio/ScheduleMusic.cs @@ -0,0 +1,42 @@ + +using System; +using Godot; + + +namespace Rokojori; + +[Tool] +[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Tween.svg")] +public partial class ScheduleMusic:SequenceAction +{ + [Export] + public float duration = 0; + + [Export] + public MusicData musicData; + + [Export] + public MusicChannel channel; + + + protected override void _OnTrigger() + { + this.LogInfo( "Scheduling:", musicData ); + var id = DispatchStart(); + + var audioManager = Unique.Get(); + var player = audioManager.GetPlayer( channel ); + + player.SchedulePlayer( + musicData, Mathf.Max( 0.0f, duration), ()=> + { + DispatchEnd( id ); + } + ); + + } + + + + +} diff --git a/Runtime/Actions/Audio/ScheduleMusic.cs.uid b/Runtime/Actions/Audio/ScheduleMusic.cs.uid new file mode 100644 index 0000000..2475fd5 --- /dev/null +++ b/Runtime/Actions/Audio/ScheduleMusic.cs.uid @@ -0,0 +1 @@ +uid://tnm5c1nt0plk diff --git a/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs new file mode 100644 index 0000000..3965ed6 --- /dev/null +++ b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs @@ -0,0 +1,55 @@ + +using Godot; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class CompositorEffectSetting:NumberAppSetting + { + [Export] + public float userRangeToEffectRange = 1f/100f; + + [Export] + public CompositorEffect compositorEffect; + + [Export] + public string effectSettingName = ""; + + public enum TargetType + { + Float, + Int, + Bool + } + + [Export] + public TargetType targetType = TargetType.Float; + + public override void ApplyValue( App app ) + { + var stringValue = app.GetSetting( id ); + var floatValue = RegexUtility.ParseFloat( stringValue ); + + var effectValue = floatValue * userRangeToEffectRange; + + var member = effectSettingName; + + if ( TargetType.Float == targetType ) + { + ReflectionHelper.SetValue( compositorEffect, member, effectValue ); + } + else if ( TargetType.Int == targetType ) + { + ReflectionHelper.SetValue( compositorEffect, member, (int)effectValue ); + } + else if ( TargetType.Bool == targetType ) + { + ReflectionHelper.SetValue( compositorEffect, member, effectValue > 0 ); + } + } + + + } +} \ No newline at end of file diff --git a/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs.uid b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs.uid new file mode 100644 index 0000000..8e8611a --- /dev/null +++ b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs.uid @@ -0,0 +1 @@ +uid://fvqabvh4as0i diff --git a/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres b/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres index a79fd9b..567356f 100644 --- a/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres +++ b/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres @@ -1,13 +1,46 @@ -[gd_resource type="Resource" script_class="AppSettingsCategory" load_steps=5 format=3 uid="uid://4iqfk01k81nc"] +[gd_resource type="Resource" script_class="AppSettingsCategory" load_steps=13 format=3 uid="uid://4iqfk01k81nc"] [ext_resource type="Script" uid="uid://b3kfbhiwqt26o" path="res://addons/rokojori_action_library/Runtime/App/Settings/AppSettingsCategory.cs" id="1_g7ii0"] [ext_resource type="Resource" uid="uid://0itt52s066qp" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/UI Scale Setting.tres" id="2_xi6qd"] [ext_resource type="Resource" uid="uid://bpfrw7y8jx2wp" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/Graphics Label.tres" id="3_g7ii0"] [ext_resource type="Resource" uid="uid://cec7500hcn1e0" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/Resolution Scale Setting.tres" id="3_xi6qd"] +[ext_resource type="Resource" uid="uid://bd8cja8453an4" path="res://Rendering/FX-Anti-Aliasing.tres" id="4_27xtl"] +[ext_resource type="Script" uid="uid://bgw3wuqxbwrb0" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/AntiAliasing/FXAA/FXAAEffect.cs" id="5_fe0r4"] +[ext_resource type="Script" uid="uid://fvqabvh4as0i" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs" id="6_ajjd7"] +[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="7_4upb4"] +[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="8_pdrnl"] + +[sub_resource type="CompositorEffect" id="CompositorEffect_b71pn"] +resource_local_to_scene = false +resource_name = "" +enabled = true +effect_callback_type = 4 +needs_motion_vectors = false +needs_normal_roughness = false +script = ExtResource("5_fe0r4") +amount = 4.0 +compositorEffectID = ExtResource("4_27xtl") +metadata/_custom_type_script = "uid://bgw3wuqxbwrb0" + +[sub_resource type="Resource" id="Resource_nhpaj"] +script = ExtResource("8_pdrnl") +en = "FX Anti-Aliasing" +metadata/_custom_type_script = "uid://bvj322mokkq63" + +[sub_resource type="Resource" id="Resource_6o5ni"] +script = ExtResource("6_ajjd7") +compositorEffect = SubResource("CompositorEffect_b71pn") +effectSettingName = "amount" +max = 400.0 +defaultValue = 100.0 +stepSize = 10.0 +suffix = ExtResource("7_4upb4") +title = SubResource("Resource_nhpaj") +metadata/_custom_type_script = "uid://fvqabvh4as0i" [resource] script = ExtResource("1_g7ii0") title = ExtResource("3_g7ii0") id = "graphics" -settings = [ExtResource("3_xi6qd"), ExtResource("2_xi6qd")] +settings = [ExtResource("2_xi6qd"), ExtResource("3_xi6qd"), SubResource("Resource_6o5ni")] metadata/_custom_type_script = "uid://b3kfbhiwqt26o" diff --git a/Runtime/Audio/AudioManager/AudioManager.cs b/Runtime/Audio/AudioManager/AudioManager.cs index 4c62ff0..2d1110d 100644 --- a/Runtime/Audio/AudioManager/AudioManager.cs +++ b/Runtime/Audio/AudioManager/AudioManager.cs @@ -12,6 +12,24 @@ namespace Rokojori Dictionary _lastPlayTime = new Dictionary(); + [Export] + public MusicChannelPlayer[] players = []; + + public MusicChannelPlayer GetPlayer( MusicChannel channel ) + { + var player = players.Find( p => p.channel == channel ); + + if ( player == null ) + { + player = this.CreateChild( channel.playerName ); + player.channel = channel; + + players = players.Add( player ); + } + + return player; + } + public float GetLastPlayed( AudioFlag selectorFlag ) { if ( ! _lastPlayTime.ContainsKey( selectorFlag ) ) diff --git a/Runtime/Cameras/PostProcess/PostProcessVolume.cs b/Runtime/Cameras/PostProcess/PostProcessVolume.cs index 95ea673..26967b5 100644 --- a/Runtime/Cameras/PostProcess/PostProcessVolume.cs +++ b/Runtime/Cameras/PostProcess/PostProcessVolume.cs @@ -20,6 +20,8 @@ namespace Rokojori [Export] public int priority = 0; + public int combinedPriority => ! enabled ? -1 : priority; + [Export] public PostProcessVolumeEffect[] effects; diff --git a/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs b/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs index 5c085bc..c7e61cc 100644 --- a/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs +++ b/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs @@ -90,18 +90,18 @@ namespace Rokojori continue; } - if ( volumes[ i ].priority < priorities[ j ] ) + if ( volumes[ i ].combinedPriority < priorities[ j ] ) { continue; } - if ( priorities[ j ] < volumes[ i ].priority ) + if ( priorities[ j ] < volumes[ i ].combinedPriority ) { valueWeights[ j ] = 0f; floatValues[ j ].SetFloatValue( 0f ); } - priorities[ j ] = volumes[ i ].priority; + priorities[ j ] = volumes[ i ].combinedPriority; var value = floatValues[ j ].GetFloatValue(); @@ -200,18 +200,18 @@ namespace Rokojori continue; } - if ( volumes[ i ].priority < priorities[ j ] ) + if ( volumes[ i ].combinedPriority < priorities[ j ] ) { continue; } - if ( priorities[ j ] < volumes[ i ].priority ) + if ( priorities[ j ] < volumes[ i ].combinedPriority ) { valueWeights[ j ] = 0f; colorValues[ j ].value = new Color( 0, 0, 0, 0 ); } - priorities[ j ] = volumes[ i ].priority; + priorities[ j ] = volumes[ i ].combinedPriority; var weight = volumes[ i ].combinedWeight; diff --git a/Runtime/Files/FilePath.cs b/Runtime/Files/FilePath.cs index 3ea41ed..4bd760b 100644 --- a/Runtime/Files/FilePath.cs +++ b/Runtime/Files/FilePath.cs @@ -45,7 +45,7 @@ namespace Rokojori { get { - if ( _fileName == null) + if ( _fileName == null ) { _fileName = Path.GetFileNameWithoutExtension( path ); } diff --git a/Runtime/Godot/Extensions/ControlExtensions.cs b/Runtime/Godot/Extensions/ControlExtensions.cs new file mode 100644 index 0000000..b12664d --- /dev/null +++ b/Runtime/Godot/Extensions/ControlExtensions.cs @@ -0,0 +1,18 @@ +using Godot; + +using System.Collections.Generic; +using System; +using System.Threading.Tasks; +using System.Reflection; + +namespace Rokojori +{ + public static class ControlExtensions + { + public static Vector2 GetCenter( this Control control ) + { + return control.Position + control.Size * 0.5f; + } + + } +} \ No newline at end of file diff --git a/Runtime/Godot/Extensions/ControlExtensions.cs.uid b/Runtime/Godot/Extensions/ControlExtensions.cs.uid new file mode 100644 index 0000000..ab26833 --- /dev/null +++ b/Runtime/Godot/Extensions/ControlExtensions.cs.uid @@ -0,0 +1 @@ +uid://b1efhjod1yomf diff --git a/Runtime/Graphs/Trees/TreeWalker.cs b/Runtime/Graphs/Trees/TreeWalker.cs index 1d641bc..5a61af4 100644 --- a/Runtime/Graphs/Trees/TreeWalker.cs +++ b/Runtime/Graphs/Trees/TreeWalker.cs @@ -470,6 +470,23 @@ namespace Rokojori return null; } + public T GetParentWithType( N node ) + { + var p = Parent( node ); + + while ( p != null ) + { + if ( p is T t ) + { + return t; + } + + p = Parent( p ); + } + + return default(T); + } + public int GetAncestorDistance( N child, N ancestor ) { if ( ancestor == null ) diff --git a/Runtime/Math/Math3D.cs b/Runtime/Math/Math3D.cs index f68cf2c..3046c94 100644 --- a/Runtime/Math/Math3D.cs +++ b/Runtime/Math/Math3D.cs @@ -12,7 +12,36 @@ namespace Rokojori { X, Y, Z } - + + + public static float ComputeLineDistance( IEnumerable points ) + { + return ComputeLineDistance( points, ( p ) => p ); + } + + public static float ComputeLineDistance( IEnumerable points, System.Func getPosition ) + { + var distance = 0f; + + Vector3? before = null; + + foreach ( var p in points ) + { + if ( before == null ) + { + before = getPosition( p ); + continue; + } + + var b = (Vector3)before; + var position = getPosition( p ); + distance += ( b - position ).Length(); + before = position; + } + + return distance; + } + public static float LookingAtEachOtherAngle( Vector3 lookDirectionA, Vector3 lookDirectionB ) { return Dot( lookDirectionA, lookDirectionB ); diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs new file mode 100644 index 0000000..131d252 --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs @@ -0,0 +1,62 @@ + +using Godot; +using Rokojori; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool, GlobalClass] + public partial class AltByAngle_SplineUpGen:SplineUpGeneratorStrategy + { + [Export] + public Vector3 alternativeUp; + + [Export( PropertyHint.Range, "0,90")] + public float angleThresholdDegrees = 5f; + + [Export] + public bool forceFromPositions = false; + + public override Vector3 ComputeUp( + int numReferences, + System.Func getPosition, + System.Func getForward, + System.Func getUp + ) + { + var usePositions = forceFromPositions || getForward == null; + + if ( numReferences <= 0 || usePositions && numReferences == 1 ) + { + return Vector3.Up; + } + + var forward = usePositions ? ( getPosition( 1 ) - getPosition( 0 ) ) : getForward( 0 ); + + var forwardNormalized = forward.Normalized(); + + var xzLength = forwardNormalized.XZ().Length(); + + if ( xzLength == 0 ) + { + return alternativeUp; + } + + var yawDir = new Vector2( xzLength, Mathf.Abs( forwardNormalized.Y ) ); + var angle = yawDir.Angle(); + + if ( angle > angleThresholdDegrees ) + { + return Vector3.Up; + } + + var amount = 1f - ( angle / angleThresholdDegrees ); + + var slerped = Vector3.Up.Slerp( alternativeUp, amount ); + + return slerped; + + } + + } +} diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs.uid new file mode 100644 index 0000000..cc389af --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs.uid @@ -0,0 +1 @@ +uid://d0yj01q8hppot diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs new file mode 100644 index 0000000..6b7660d --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs @@ -0,0 +1,24 @@ + +using Godot; +using Rokojori; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool, GlobalClass] + public partial class Constant_SplineUpGen:SplineUpGeneratorStrategy + { + [Export] + public Vector3 constantUp; + public override Vector3 ComputeUp( + int getNumReferences, + System.Func getPosition, + System.Func getForward, + System.Func getUp + ) + { + return constantUp; + } + + } +} diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs.uid new file mode 100644 index 0000000..3f28b3c --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs.uid @@ -0,0 +1 @@ +uid://c257amlha7moj diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs new file mode 100644 index 0000000..bb13fce --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs @@ -0,0 +1,19 @@ + +using Godot; +using Rokojori; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool, GlobalClass] + public abstract partial class SplineUpGeneratorStrategy:Resource + { + public abstract Vector3 ComputeUp( + int getNumReferences, + System.Func getPosition, + System.Func getForward, + System.Func getUp + ); + + } +} diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs.uid new file mode 100644 index 0000000..54f4249 --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs.uid @@ -0,0 +1 @@ +uid://vl5tkdm7lnc0 diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs new file mode 100644 index 0000000..40e2a13 --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs @@ -0,0 +1,24 @@ + +using Godot; +using Rokojori; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool, GlobalClass] + public partial class WorldUp_SplineUpGen:SplineUpGeneratorStrategy + { + public static readonly WorldUp_SplineUpGen instance = new WorldUp_SplineUpGen(); + + public override Vector3 ComputeUp( + int getNumReferences, + System.Func getPosition, + System.Func getForward, + System.Func getUp + ) + { + return Vector3.Up; + } + + } +} diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs.uid new file mode 100644 index 0000000..b1ebb00 --- /dev/null +++ b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs.uid @@ -0,0 +1 @@ +uid://d3x1tsjce28xe diff --git a/Runtime/Random/RandomEngine.cs b/Runtime/Random/RandomEngine.cs index fea771b..425265c 100644 --- a/Runtime/Random/RandomEngine.cs +++ b/Runtime/Random/RandomEngine.cs @@ -375,6 +375,20 @@ namespace Rokojori return selection; } + public T FromWeightedElements( IList elements, Func getWeight ) + { + var weights = new List( elements.Count ); + + foreach ( var e in elements ) + { + weights.Add( getWeight( e ) ); + } + + var index = IndexFromUnnormalizedWeights( weights ); + + return elements[ index ]; + } + public int IndexFromUnnormalizedWeights( List weights, float sumWeights = 0 ) { if ( sumWeights <= 0 ) diff --git a/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs b/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs index a13d6f8..a18878c 100644 --- a/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs +++ b/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs @@ -53,6 +53,12 @@ namespace Rokojori [Export( PropertyHint.Range, "0,1") ] public float normalEdgeAmountMax = 0.15f; + [Export( PropertyHint.Range, "0,1") ] + public float normalZFilterWeight = 1f; + + [Export] + public float normalZDiffWeight = 1.0f; + [Export] public float zTreshold = 0.1f; @@ -77,6 +83,9 @@ namespace Rokojori [Export ] public Vector2 zOutput = new Vector2( 0f, 1f ); + [Export( PropertyHint.Range, "0,1") ] + public float debugViewZ = 0; + RG_ScreenColorTexure screenColorTexture; RG_ScreenDepthTexture screenDepthTexture; @@ -186,7 +195,12 @@ namespace Rokojori rimContrast, rimStrength, Mathf.Pow( 10f, outlineWidth ), - edgeDistanceFade + edgeDistanceFade, + + debugViewZ, + normalZFilterWeight, + normalZDiffWeight, + 0f ); diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png new file mode 100644 index 0000000..91c06a1 Binary files /dev/null and b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png differ diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png.import b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png.import new file mode 100644 index 0000000..bd8d87b --- /dev/null +++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpagciclpro4l" +path="res://.godot/imported/good-graphics.png-71a1fa2dc0da1570f69568e7db0767eb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png" +dest_files=["res://.godot/imported/good-graphics.png-71a1fa2dc0da1570f69568e7db0767eb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png new file mode 100644 index 0000000..4730607 Binary files /dev/null and b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png differ diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png.import b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png.import new file mode 100644 index 0000000..3ba349e --- /dev/null +++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drfvhbwh15gkg" +path="res://.godot/imported/star-glow-blur.png-142c3c2b394a06f53c56fa99ae68e47e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png" +dest_files=["res://.godot/imported/star-glow-blur.png-142c3c2b394a06f53c56fa99ae68e47e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png new file mode 100644 index 0000000..8aa4fb4 Binary files /dev/null and b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png differ diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png.import b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png.import new file mode 100644 index 0000000..7a8ec14 --- /dev/null +++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cb7n8cuuqqgn1" +path="res://.godot/imported/star-glow.png-183351a5bd2df4d5391efd4f3d4d6420.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png" +dest_files=["res://.godot/imported/star-glow.png-183351a5bd2df4d5391efd4f3d4d6420.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres index 636c1fc..f636fde 100644 --- a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres +++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres @@ -4,8 +4,9 @@ [ext_resource type="Script" uid="uid://cx5qcow1mmd11" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/CompositorEffectOwner.cs" id="2_bfksq"] [ext_resource type="Script" uid="uid://comuvej4dr22k" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/RokojoriCompositorEffectID.cs" id="3_eyvih"] [ext_resource type="Script" uid="uid://t5g1g1uv5yrj" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Overlay/TextureOverlay/TextureOverlayEffect.cs" id="4_chktd"] -[ext_resource type="Texture2D" uid="uid://cqaqvhmyuo56d" path="res://VFX/Compositor Effects/Star Glow/star-glow-blur.png" id="5_1gqhf"] +[ext_resource type="Texture2D" uid="uid://cb7n8cuuqqgn1" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png" id="5_chktd"] [ext_resource type="Script" uid="uid://cqkrgyuerq50a" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Distortion/EllispeDistortion/EllipseDistortionEffect.cs" id="6_t8xaw"] +[ext_resource type="Texture2D" uid="uid://drfvhbwh15gkg" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png" id="7_1gqhf"] [ext_resource type="Script" uid="uid://6jkixa201wux" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Glow/ChromaticBloom/ChromaticBloomEffect.cs" id="7_g2w8j"] [ext_resource type="Script" uid="uid://pevgspwywsxi" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Color/HSLAdjustment/HSLAdjustmentEffect.cs" id="8_bfeok"] [ext_resource type="Script" uid="uid://ckixweetchlo0" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/CompositorVFXPreset.cs" id="9_fgrt2"] @@ -27,16 +28,15 @@ script = ExtResource("1_e74ec") member = "opacity" curve = SubResource("Curve_xhmdb") -[sub_resource type="Resource" id="Resource_1ntwo"] +[sub_resource type="Resource" id="Resource_mdsx3"] script = ExtResource("2_bfksq") [sub_resource type="Resource" id="Resource_5jnfl"] script = ExtResource("3_eyvih") -owner = SubResource("Resource_1ntwo") +owner = SubResource("Resource_mdsx3") [sub_resource type="Gradient" id="Gradient_qf8q3"] -offsets = PackedFloat32Array(0.34812286, 0.70307165, 0.8988327) -colors = PackedColorArray(0, 0, 0, 1, 1, 1, 1, 1, 16.420414, 16.420414, 16.420414, 1) +offsets = PackedFloat32Array(0.60144925, 1) [sub_resource type="GradientTexture2D" id="GradientTexture2D_cqn6v"] gradient = SubResource("Gradient_qf8q3") @@ -44,10 +44,7 @@ use_hdr = true fill = 1 fill_from = Vector2(0.5, 0.50427353) -[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_g6idi"] -load_path = "res://.godot/imported/star-glow.png-61f0458024aeba1668f3516b3db84782.ctex" - -[sub_resource type="CompositorEffect" id="CompositorEffect_e74ec"] +[sub_resource type="CompositorEffect" id="CompositorEffect_wpvj8"] resource_local_to_scene = false resource_name = "" enabled = true @@ -55,10 +52,10 @@ effect_callback_type = 4 needs_motion_vectors = false needs_normal_roughness = false script = ExtResource("4_chktd") -opacity = 0.0 +opacity = 0.5578947 blendMode = 1 -overlayTexture = SubResource("CompressedTexture2D_g6idi") -overlayTint = Color(1, 1, 1, 0.050980393) +overlayTexture = ExtResource("5_chktd") +overlayTint = Color(1, 1, 1, 0.33333334) tiling = Vector2(9, 5.0625) scrolling = Vector2(0.22, 0.012) maskTexture = SubResource("GradientTexture2D_cqn6v") @@ -82,7 +79,7 @@ curve = SubResource("Curve_xhmdb") [sub_resource type="Resource" id="Resource_qf8q3"] script = ExtResource("3_eyvih") -owner = SubResource("Resource_1ntwo") +owner = SubResource("Resource_mdsx3") [sub_resource type="Gradient" id="Gradient_7ucn0"] offsets = PackedFloat32Array(0.08171206, 0.57587546, 1) @@ -94,7 +91,7 @@ use_hdr = true fill = 1 fill_from = Vector2(0.5, 0.50427353) -[sub_resource type="CompositorEffect" id="CompositorEffect_bfksq"] +[sub_resource type="CompositorEffect" id="CompositorEffect_ysmsc"] resource_local_to_scene = false resource_name = "" enabled = true @@ -102,10 +99,10 @@ effect_callback_type = 4 needs_motion_vectors = false needs_normal_roughness = false script = ExtResource("4_chktd") -opacity = 0.0 +opacity = 0.5578947 blendMode = 1 -overlayTexture = ExtResource("5_1gqhf") -overlayTint = Color(1, 1, 1, 0.21568628) +overlayTexture = ExtResource("7_1gqhf") +overlayTint = Color(1, 1, 1, 0) tiling = Vector2(1, 0.5625) scrolling = Vector2(-0.1, -0.01) maskTexture = SubResource("GradientTexture2D_su8gi") @@ -126,9 +123,9 @@ curve = SubResource("Curve_nxurn") [sub_resource type="Resource" id="Resource_slvrs"] script = ExtResource("3_eyvih") -owner = SubResource("Resource_1ntwo") +owner = SubResource("Resource_mdsx3") -[sub_resource type="CompositorEffect" id="CompositorEffect_eyvih"] +[sub_resource type="CompositorEffect" id="CompositorEffect_t5au6"] resource_local_to_scene = false resource_name = "" enabled = true @@ -136,7 +133,7 @@ effect_callback_type = 4 needs_motion_vectors = false needs_normal_roughness = false script = ExtResource("6_t8xaw") -distortionAmount = 0.0 +distortionAmount = 0.12 ellipseScale = 1.138 ringsDistribution = 0.7727 animationTargets = [SubResource("Resource_35pef")] @@ -151,12 +148,13 @@ point_count = 3 script = ExtResource("1_e74ec") member = "amount" curve = SubResource("Curve_71075") +curveScale = 0.2 [sub_resource type="Resource" id="Resource_bhyc7"] script = ExtResource("3_eyvih") -owner = SubResource("Resource_1ntwo") +owner = SubResource("Resource_mdsx3") -[sub_resource type="CompositorEffect" id="CompositorEffect_chktd"] +[sub_resource type="CompositorEffect" id="CompositorEffect_ixqtu"] resource_local_to_scene = false resource_name = "" enabled = true @@ -164,11 +162,11 @@ effect_callback_type = 4 needs_motion_vectors = false needs_normal_roughness = false script = ExtResource("7_g2w8j") -amount = 0.0 +amount = 0.1691 num = 3 distortionAmount = 0.4369 distortionAngle = 168.8496 -distortionAngleSpeed = 10.0 +distortionAngleSpeed = 40.0 smearingSteps = 24 smearing = 1.2171 redShift = 0.2239 @@ -196,9 +194,9 @@ curve = SubResource("Curve_su8gi") [sub_resource type="Resource" id="Resource_7jt2s"] script = ExtResource("3_eyvih") -owner = SubResource("Resource_1ntwo") +owner = SubResource("Resource_mdsx3") -[sub_resource type="CompositorEffect" id="CompositorEffect_1gqhf"] +[sub_resource type="CompositorEffect" id="CompositorEffect_m7r8b"] resource_local_to_scene = false resource_name = "" enabled = true @@ -206,7 +204,7 @@ effect_callback_type = 4 needs_motion_vectors = false needs_normal_roughness = false script = ExtResource("8_bfeok") -amount = 0.0 +amount = 1.0 saturationOffset = 30.0 saturationGamma = 37.9747 lightnessOffset = 2.0 @@ -217,5 +215,5 @@ metadata/_custom_type_script = "uid://pevgspwywsxi" [resource] script = ExtResource("9_fgrt2") -effects = [SubResource("CompositorEffect_e74ec"), SubResource("CompositorEffect_bfksq"), SubResource("CompositorEffect_eyvih"), SubResource("CompositorEffect_chktd"), SubResource("CompositorEffect_1gqhf")] +effects = [SubResource("CompositorEffect_wpvj8"), SubResource("CompositorEffect_ysmsc"), SubResource("CompositorEffect_t5au6"), SubResource("CompositorEffect_ixqtu"), SubResource("CompositorEffect_m7r8b")] metadata/_custom_type_script = "uid://ckixweetchlo0" diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres b/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres index 853563b..4b98dad 100644 --- a/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres +++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres @@ -1,8 +1,7 @@ -[gd_resource type="Resource" script_class="CompositorVFXPreset" load_steps=36 format=3 uid="uid://0blw3yhjw7y0"] +[gd_resource type="Resource" script_class="CompositorVFXPreset" load_steps=35 format=3 uid="uid://0blw3yhjw7y0"] [ext_resource type="Script" uid="uid://cx5qcow1mmd11" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/CompositorEffectOwner.cs" id="1_0ail8"] [ext_resource type="Script" uid="uid://dvvfvlutisecy" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/AnimationTargets/CompFXMemberCurveTarget.cs" id="1_4xviq"] -[ext_resource type="Resource" uid="uid://bwhnq7w0tpgv" path="res://VFX/Action FX Compositor Effect Layer.tres" id="2_4xviq"] [ext_resource type="Script" uid="uid://comuvej4dr22k" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/RokojoriCompositorEffectID.cs" id="2_tc21q"] [ext_resource type="Script" uid="uid://bx4j8ic80vl7f" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs" id="3_dryyw"] [ext_resource type="Texture2D" uid="uid://c30nul6romace" path="res://addons/rokojori_action_library/Runtime/Procedural/Noise/RGB 3D Noise.png" id="5_orb2s"] @@ -26,7 +25,6 @@ script = ExtResource("1_0ail8") [sub_resource type="Resource" id="Resource_p64cs"] script = ExtResource("2_tc21q") owner = SubResource("Resource_4xviq") -layer = ExtResource("2_4xviq") [sub_resource type="Curve" id="Curve_7axlu"] _data = [Vector2(0, 1), 0.0, -18.573792, 0, 0, Vector2(0.07774799, 0.15679264), -0.687919, -0.687919, 0, 0, Vector2(1, 0), -0.069252, 0.0, 0, 0] @@ -91,7 +89,6 @@ metadata/_custom_type_script = "uid://dvvfvlutisecy" [sub_resource type="Resource" id="Resource_hpfyh"] script = ExtResource("2_tc21q") owner = SubResource("Resource_4xviq") -layer = ExtResource("2_4xviq") [sub_resource type="Gradient" id="Gradient_frwbc"] offsets = PackedFloat32Array(1) @@ -135,7 +132,6 @@ metadata/_custom_type_script = "uid://dvvfvlutisecy" [sub_resource type="Resource" id="Resource_gxlxg"] script = ExtResource("2_tc21q") owner = SubResource("Resource_4xviq") -layer = ExtResource("2_4xviq") [sub_resource type="CompressedTexture2D" id="CompressedTexture2D_4n83u"] load_path = "res://.godot/imported/RGB 3D Noise.png-daebfe00d2f3fcd5d3bc528f8a3972e1.ctex" @@ -172,7 +168,6 @@ metadata/_custom_type_script = "uid://balixgskgouhm" [sub_resource type="Resource" id="Resource_3tnad"] script = ExtResource("2_tc21q") owner = SubResource("Resource_4xviq") -layer = ExtResource("2_4xviq") [sub_resource type="CompositorEffect" id="CompositorEffect_hdnet"] resource_local_to_scene = false diff --git a/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl b/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl index 5d53adf..6828d40 100644 --- a/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl +++ b/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl @@ -57,6 +57,11 @@ uniform Parameters float outlineWidth; float edgeDistanceFade; + float debugViewZ; + float normalFilterWeight; + float normalZDiffWeight; + float pad3; + } parameters; @@ -144,6 +149,28 @@ float mapClamped( float value, float inMin, float inMax, float outMin, float out return mix( outMin, outMax, normalizeToRange01( value, inMin, inMax ) ); } +float edgeFilter( vec3 nA, vec3 nB, float zA, float zB, float zScale ) +{ + float dotValue = dot( nA, nB ); + float angleAmount = max( 0.0, 1.0 - dotValue ); + angleAmount = smoothstep( parameters.normalEdgeZMin, parameters.normalEdgeZMax, angleAmount ); + + // Same direction => ( 1 - 0 ) => 1, edge + // Not same direction => ( 1 - 1 ) => 0, no edge + + float normalizedZDiff = abs( zA - zB ) * parameters.normalZDiffWeight * zScale; + // 1 => big z distance + // 0 => close z + + float zDiffAmount = clamp( normalizedZDiff, 0.0, 1.0 ); + // 0 distance => close => edge + // 1 distance => far => no edge + + float invZDIff = 1.0 - zDiffAmount; + + return clamp( angleAmount + invZDIff, 0.0, 1.0 ); +} + void main( ) { ivec2 size = imageSize( outputImage ); @@ -220,12 +247,35 @@ void main( ) float normalEdge = 0.0; - normalEdge = max( normalEdge, 1.0 - dot( n11, n01 ) ); - normalEdge = max( normalEdge, 1.0 - dot( n11, n21 ) ); - normalEdge = max( normalEdge, 1.0 - dot( n11, n10 ) ); - normalEdge = max( normalEdge, 1.0 - dot( n11, n12 ) ); + // float zDiffNormalizer = parameters.normalZDiffWeight; - float edgeWeight = smoothstep( parameters.normalEdgeZMin, parameters.normalEdgeZMax, normalEdge ); + // float zDiffAmount01 = max( 0.0, 1.0 - abs( z11 - z01 ) * zDiffNormalizer ); + // float zDiffAmount21 = max( 0.0, 1.0 - abs( z11 - z21 ) * zDiffNormalizer ); + // float zDiffAmount10 = max( 0.0, 1.0 - abs( z11 - z10 ) * zDiffNormalizer ); + // float zDiffAmount12 = max( 0.0, 1.0 - abs( z11 - z12 ) * zDiffNormalizer ); + + // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n01 ) * zDiffAmount01 ) ); + // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n21 ) * zDiffAmount21 ) ); + // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n10 ) * zDiffAmount10 ) ); + // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n12 ) * zDiffAmount12 ) ); + + // normalEdge = max( normalEdge, edgeFilter( n11, n01, z11, z01, adaptiveScale ) ); + // normalEdge = max( normalEdge, edgeFilter( n11, n21, z11, z21, adaptiveScale ) ); + // normalEdge = max( normalEdge, edgeFilter( n11, n10, z11, z10, adaptiveScale ) ); + // normalEdge = max( normalEdge, edgeFilter( n11, n12, z11, z12, adaptiveScale ) ); + + + normalEdge += edgeFilter( n11, n01, z11, z01, adaptiveScale ); + normalEdge += edgeFilter( n11, n21, z11, z21, adaptiveScale ); + normalEdge += edgeFilter( n11, n10, z11, z10, adaptiveScale ); + normalEdge += edgeFilter( n11, n12, z11, z12, adaptiveScale ); + + normalEdge /= 4.0; + + // float edgeWeight = smoothstep( parameters.normalEdgeZMin, parameters.normalEdgeZMax, normalEdge ); + float edgeWeight = normalEdge; + + edgeWeight = mix( 1.0, edgeWeight, parameters.normalFilterWeight ); float edge = max( normalEdge * parameters.normalEdgeAmount, zEdge * parameters.zEdgeAmount * edgeWeight ); edge = clamp01( edge ); @@ -240,7 +290,11 @@ void main( ) vec4 edgeColor = SRGBtoLINEAR( vec4( parameters.edgeR, parameters.edgeG, parameters.edgeB, 1.0 ) ); // originalColor.rgb = mix( originalColor.rgb, vec3( 0.0, 0.0, 0.0 ), shadowAmount ); vec4 mixedColor = mix( originalColor, edgeColor, parameters.amount * edge ); - + + if ( parameters.debugViewZ > 0.0 ) + { + mixedColor.rgb = mix( mixedColor.rgb, vec3( normalEdge * 1.0 ), parameters.debugViewZ ); + } imageStore( outputImage, xy, mixedColor ); } \ No newline at end of file diff --git a/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres b/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres index 52c7bef..2e682b6 100644 --- a/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres +++ b/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres @@ -192,7 +192,7 @@ directionUpTexture = ExtResource("6_0hfff") [sub_resource type="Resource" id="Resource_40bf3"] script = ExtResource("2_4sutq") -value = 0.7 +value = 1.5 unit = "em" [sub_resource type="Resource" id="Resource_xrtll"] @@ -274,7 +274,7 @@ backgroundTexture = ExtResource("21_hcyk3") [resource] script = ExtResource("1_urlfx") fontSize = SubResource("Resource_40bf3") -iconHeightInEm = 1.5 +iconHeightInEm = 3.0 mouseInputIcon = SubResource("Resource_34cgw") keyboardKeys = SubResource("Resource_nkgsq") keyboardModifiers = SubResource("Resource_wrdp7") diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres index 50899c0..3bdfdf8 100644 --- a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres +++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres @@ -1,11 +1,18 @@ -[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://cqatyb80rpor0"] +[gd_resource type="Resource" script_class="CombineSensor" load_steps=6 format=3 uid="uid://cqatyb80rpor0"] [ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_u5wou"] [ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_ibucs"] +[ext_resource type="Script" uid="uid://cc8g4jmyrpehg" path="res://addons/rokojori_action_library/Runtime/Sensors/InputIcons/Types/GamePadAxisIcon.cs" id="2_n3xai"] + +[sub_resource type="Resource" id="Resource_yth0n"] +script = ExtResource("2_n3xai") +type = 1 +metadata/_custom_type_script = "uid://cc8g4jmyrpehg" [sub_resource type="Resource" id="Resource_n3xai"] script = ExtResource("2_ibucs") inputActionName = "ui_left" +inputIcons = [SubResource("Resource_yth0n")] metadata/_custom_type_script = "uid://e7fduwypgvwr" [resource] diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres index d9fd33f..d4ea6e2 100644 --- a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres +++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres @@ -1,11 +1,17 @@ -[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://dafu3alp6wr25"] +[gd_resource type="Resource" script_class="CombineSensor" load_steps=6 format=3 uid="uid://dafu3alp6wr25"] [ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_rqdfo"] [ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_oj4wy"] +[ext_resource type="Script" uid="uid://cc8g4jmyrpehg" path="res://addons/rokojori_action_library/Runtime/Sensors/InputIcons/Types/GamePadAxisIcon.cs" id="2_tuqbj"] + +[sub_resource type="Resource" id="Resource_i2j76"] +script = ExtResource("2_tuqbj") +metadata/_custom_type_script = "uid://cc8g4jmyrpehg" [sub_resource type="Resource" id="Resource_tuqbj"] script = ExtResource("2_oj4wy") inputActionName = "ui_right" +inputIcons = [SubResource("Resource_i2j76")] metadata/_custom_type_script = "uid://e7fduwypgvwr" [resource] diff --git a/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs b/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs index 7cea961..b004a15 100644 --- a/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs +++ b/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs @@ -24,6 +24,8 @@ namespace Rokojori { return false; } + + this.LogInfo( "Checking Icon:", device.GetType().Name, icon.GetType().Name ); return device.ContainsIcon( icon ); } diff --git a/Runtime/Sensors/Devices/GamePadDevice.cs b/Runtime/Sensors/Devices/GamePadDevice.cs index 4c87a5a..6793464 100644 --- a/Runtime/Sensors/Devices/GamePadDevice.cs +++ b/Runtime/Sensors/Devices/GamePadDevice.cs @@ -45,6 +45,8 @@ namespace Rokojori return ci.icons.Length == 1 && ContainsIcon( ci.icons[ 0 ] ); } + + return ReflectionHelper.IsTypeOneOf( icon, typeof( GamePadAxisIcon ), typeof( GamePadButtonIcon ) diff --git a/Runtime/Sensors/Devices/SensorDevice.cs b/Runtime/Sensors/Devices/SensorDevice.cs index d7eac9e..f534b0b 100644 --- a/Runtime/Sensors/Devices/SensorDevice.cs +++ b/Runtime/Sensors/Devices/SensorDevice.cs @@ -6,7 +6,7 @@ namespace Rokojori { [Tool] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/SensorGroup.svg")] - public partial class SensorDevice: Resource + public abstract partial class SensorDevice: Resource { public virtual string GetInfo() diff --git a/Runtime/Sensors/InputIcons/Types/SensorIcon.cs b/Runtime/Sensors/InputIcons/Types/SensorIcon.cs index fac4797..5a950ef 100644 --- a/Runtime/Sensors/InputIcons/Types/SensorIcon.cs +++ b/Runtime/Sensors/InputIcons/Types/SensorIcon.cs @@ -11,6 +11,13 @@ namespace Rokojori [Export] public Sensor sensor; + public static SensorIcon Create( Sensor sensor ) + { + var si = new SensorIcon(); + si.sensor = sensor; + return si; + } + public override bool Equals( object obj ) { var value = obj as SensorIcon; diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc new file mode 100644 index 0000000..0a36d53 --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc @@ -0,0 +1,9 @@ + +vec3 translation; +mat3 rotation; + +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc" +mat4 combined = createMat4FromBasisAndOrigin( rotation, translation ); + +MODELVIEW_MATRIX *= combined; +MODELVIEW_NORMAL_MATRIX *= rotation; \ No newline at end of file diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc.uid new file mode 100644 index 0000000..c850fcb --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc.uid @@ -0,0 +1 @@ +uid://k6hhfjejkh5p diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc new file mode 100644 index 0000000..e75021f --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc @@ -0,0 +1,4 @@ +// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc" + +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Transform.gdshaderinc" +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Bezier.gdshaderinc" \ No newline at end of file diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc.uid new file mode 100644 index 0000000..3cb28b8 --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc.uid @@ -0,0 +1 @@ +uid://c1f4jt1qpwk42 diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc new file mode 100644 index 0000000..89262ff --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc @@ -0,0 +1,24 @@ +// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc" +// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc" + +instance uniform vec3 startPosition; +instance uniform vec3 startForward; +instance uniform vec3 startUp; +instance uniform float startNormalizedDistance; + +instance uniform vec3 endPosition; +instance uniform vec3 endForward; +instance uniform vec3 endUp; +instance uniform float endNormalizedDistance; + +instance uniform float lineLength; + +uniform float scaling:hint_range(0.0,2.0) = 1.0; +uniform int positionInterpolationMode = 0; +uniform float bezierCurvature:hint_range(0.0,0.5) = 0.3333333333; +uniform float rationalCurvature :hint_range(0.0,0.5) = 0.5; +uniform float rationalWeighting :hint_range(0.0,1.0) = 0.5; + +uniform int rotationInterpolationMode = 0; +varying float normalizedDistance; +varying float t; \ No newline at end of file diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc.uid new file mode 100644 index 0000000..c004245 --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc.uid @@ -0,0 +1 @@ +uid://buho4jxq4dkpl diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc new file mode 100644 index 0000000..c72b92b --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc @@ -0,0 +1,86 @@ +// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc" +// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc" +// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc" + +// vec3 translation; mat3 rotation; + + if ( positionInterpolationMode == 0 ) + { + translation = mix( startPosition, endPosition, t ); + } + else if ( positionInterpolationMode == 1 ) + { + float controlLength = length( endPosition - startPosition ) * bezierCurvature; + vec3 c0 = startPosition + normalize( startForward ) * controlLength; + vec3 c1 = endPosition - normalize( endForward ) * controlLength; + + translation = cubicBezier( t, startPosition, c0, c1, endPosition ); + } + else if ( positionInterpolationMode == 2 ) + { + float controlLength = length( endPosition - startPosition ) * rationalCurvature; + vec3 c0 = startPosition + normalize( startForward ) * controlLength; + vec3 c1 = endPosition - normalize( endForward ) * controlLength; + + translation = rationalCubicBezier( t, + startPosition, c0, c1, endPosition, + 1.0, rationalWeighting, rationalWeighting, 1.0 + ); + + } + + + if ( rotationInterpolationMode == 0 ) + { + vec3 forward = normalize( mix( startForward, endForward, t ) ); + vec3 up = normalize( mix( startUp, endUp, t ) ); + rotation = lookRotation( forward, up ); + + } + else if ( rotationInterpolationMode == 1 ) + { + vec4 startRotation = quaternionFromLookRotation( startForward, startUp ); + vec4 endRotation = quaternionFromLookRotation( endForward, endUp ); + + vec4 qRotation = quaternionSlerp( startRotation, endRotation, t ); + rotation = quaternionToRotationMatrix( qRotation ); + } + else if ( rotationInterpolationMode == 2 ) + { + + float controlLength = length( endPosition - startPosition ) * bezierCurvature; + vec3 c0 = startPosition + normalize( startForward ) * controlLength; + vec3 c1 = endPosition - normalize( endForward ) * controlLength; + + vec3 forward = normalize( cubicBezierDerivative( t, startPosition, c0, c1, endPosition ) ); + vec3 up = normalize( mix( startUp, endUp, t ) ); + rotation = lookRotation( forward, up ); + } + else if ( rotationInterpolationMode == 3 ) + { + vec3 lineDirection = normalize( endPosition - startPosition ); + vec3 forward = t < 0.5 ? mix( startForward, lineDirection, t * 2.0 ) : + mix( lineDirection, endForward, ( t - 0.5 ) * 2.0 ); + vec3 up = normalize( mix( startUp, endUp, t ) ); + rotation = lookRotation( forward, up ); + } + else if ( rotationInterpolationMode == 4 ) + { + bool isStart = t < 0.5; + vec3 lineDirection = normalize( endPosition - startPosition ); + vec3 centerUp = normalize( mix( startUp, endUp, 0.5 ) ); + + vec3 forwardA = isStart ? startForward : lineDirection; + vec3 forwardB = isStart ? lineDirection : endForward; + + vec3 upA = isStart ? startUp : centerUp; + vec3 upB = isStart ? centerUp : endUp; + + vec4 rotationA = quaternionFromLookRotation( forwardA, upA ); + vec4 rotationB = quaternionFromLookRotation( forwardB, upB ); + + float rt = isStart ? ( t * 2.0 ) : ( ( t -0.5 ) * 2.0 ); + + vec4 qRotation = quaternionSlerp( rotationA, rotationB, rt ); + rotation = quaternionToRotationMatrix( qRotation ); + } \ No newline at end of file diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc.uid new file mode 100644 index 0000000..3f747d0 --- /dev/null +++ b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc.uid @@ -0,0 +1 @@ +uid://dairdipwvqk75 diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs new file mode 100644 index 0000000..8fdf53f --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs @@ -0,0 +1,177 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +namespace Rokojori; + +public class GDScriptFromCSAST +{ + public GDScriptGeneratorClass gdClass = new GDScriptGeneratorClass(); + public string rokojoriPrefix = "RJ_"; + + + public static string CStoGDVariable( string csName ) + { + var sb = new StringBuilder(); + var hasUnderscore = false; + var wordStarted = false; + + for ( int i = 0; i < csName.Length; i++ ) + { + if ( char.IsUpper( csName[ i ] ) ) + { + if ( ! hasUnderscore && wordStarted ) + { + sb.Append( "_" ); + hasUnderscore = true; + } + + sb.Append( char.ToLower( csName[ i ] ) ); + wordStarted = true; + + } + else + { + sb.Append( csName[ i ] ); + hasUnderscore = csName[ i ] == '_'; + + if ( ! hasUnderscore ) + { + wordStarted = true; + } + } + } + + return sb.ToString(); + } + + + public string GetClassName( string className, string ns ) + { + if ( ns.StartsWith( "Rokojori" ) ) + { + return rokojoriPrefix + className; + } + + return className; + } + + public void Convert( CSFileRoot root ) + { + var walker = root.walker; + var csClass = walker.Find( root, n => n is CSClassDeclaration, true ) as CSClassDeclaration; + + gdClass.name = GetClassName( csClass.GetClassName(), "Rokojori" ); + + if ( csClass.objectTail != null && csClass.objectTail.inheritanceDeclaration != null ) + { + gdClass.extendingClassName = GetClassName( csClass.objectTail.GetExtendingObject(), "Rokojori" ); + } + + var atts = CSModifierAttributesParser.GetAttributes( csClass.attributeBrackets ); + + RJLog.Log( "Att:", atts.Map( a => "'" + a + "'" ) ); + + atts.ForEach( + ( att )=> + { + + if ( att == "Tool" ) + { + gdClass.annotations.Add( "tool" ); + } + else if ( att.StartsWith( "Icon" ) ) + { + var lcAtt = ( att[ 0 ] + "" ).ToLower() + att.Substring( 1 ); + gdClass.annotations.Add( lcAtt ); + } + } + ); + + + var members = new List(); + + walker.Iterate( csClass, + n => + { + if ( n is CSEnumDeclaration en ) + { + var enumType = new GDScriptGeneratorEnum(); + enumType.name = en.objectName.match; + + var values = en.objectBody.children.FilterType( ); + enumType.values =values.Map( v => v.GetEnumName() ); + + gdClass.members.Add( enumType ); + + return; + } + + if ( ! ( n is CSMemberDeclaration ) ) + { + return; + } + + + var m = n as CSMemberDeclaration; + + GDScriptGeneratorMember gdMember = null; + + if ( m is CSFieldDeclaration f ) + { + var gdField = new GDScriptGeneratorField(); + gdField.name = CStoGDVariable( f.GetMemberName() ); + gdField.memberType = f.GetMemberType(); + + gdMember = gdField; + } + else if ( m is CSMethodMemberDeclaration me ) + { + var gdMethod = new GDScriptGeneratorMethod(); + gdMethod.name = me.isContructor ? "_init" : CStoGDVariable( me.GetMemberName() ); + gdMethod.memberType = me.GetMemberType(); + gdMethod.isConstructor = me.isContructor; + + if ( me.parametersContent != null ) + { + me.parametersContent.children.ForEach( + ( c ) => + { + var p = c as CSParameterDeclaration; + + var gdParameter = new GDScriptGeneratorParameter(); + gdParameter.name = p.GetParameterName(); + gdParameter.parameterType = p.GetParameterType(); + + gdMethod.parameters.Add( gdParameter ); + + if ( p.parameterValue != null ) + { + gdParameter.parameterValue = p.GetParameterValue(); + } + } + ); + } + + gdMember = gdMethod; + } + + if ( gdMember == null ) + { + return; + } + + if ( CSModifierAttributesParser.IsExported( m.attributeBrackets ) ) + { + gdMember.annotations.Add( "export" ); + } + + gdClass.members.Add( gdMember ); + + }, + false + ); + + } +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs.uid new file mode 100644 index 0000000..f1707d2 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs.uid @@ -0,0 +1 @@ +uid://cgi2d0hhd5d6t diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs new file mode 100644 index 0000000..585981c --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs @@ -0,0 +1,28 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public class GDScriptGenerator +{ + public static readonly string GD_SCRIPT_TRANSPILING = "GD_SCRIPT_TRANSPILING"; + public List gdClasses = new List(); + + + public void Generate( string outputPath ) + { + gdClasses.ForEach( + ( gd )=> + { + var source = gd.Generate(); + RJLog.Log( "GD Script from:", gd.name, "\n" + source ); + var path = FilePath.Join( outputPath, gd.name + ".gd" ); + + RJLog.Log( "GD Script Save to:", path ); + FilesSync.SaveUTF8( path, source ); + } + ); + } +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs.uid new file mode 100644 index 0000000..dd97096 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs.uid @@ -0,0 +1 @@ +uid://duym6hiqy40dh diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs new file mode 100644 index 0000000..d733200 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public class GDScriptGeneratorClass +{ + public List annotations = []; + public string name; + public string extendingClassName; + public List members = []; + + StringBuilder sb = new StringBuilder(); + + public string Generate() + { + sb.Append( "\n" ); + + annotations.ForEach( + annotation => + { + sb.Append( "@" ); + sb.Append( annotation ); + sb.Append( "\n" ); + } + ); + + AddClassHeader(); + sb.Append( "\n" ); + + members.ForEach( m => + { + m.Generate( sb ); + sb.Append( "\n" ); + }); + + return sb.ToString(); + } + + void AddClassHeader() + { + sb.Append( "class_name " + name ); + + if ( extendingClassName != null ) + { + sb.Append( " extends " + extendingClassName ); + } + + sb.Append( "\n" ); + } +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs.uid new file mode 100644 index 0000000..b74042d --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs.uid @@ -0,0 +1 @@ +uid://dvt4yeqpmmrur diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs new file mode 100644 index 0000000..631599e --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs @@ -0,0 +1,32 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public class GDScriptGeneratorEnum:GDScriptGeneratorMember +{ + public List values = new List(); + + public override void Generate( StringBuilder sb ) + { + sb.Append( "enum " + name + "\n" ); + sb.Append( "{\n" ); + + for ( int i = 0; i < values.Count; i ++ ) + { + var ending = "\n"; + + if ( i != ( values.Count - 1 ) ) + { + ending = ",\n"; + } + + sb.Append( " " + values[ i ] + ending ); + } + + sb.Append( "}\n" ); + } + +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs.uid new file mode 100644 index 0000000..9be4ffc --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs.uid @@ -0,0 +1 @@ +uid://eqbysvejll0q diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs new file mode 100644 index 0000000..81919f6 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs @@ -0,0 +1,24 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public class GDScriptGeneratorField:GDScriptGeneratorMember +{ + public override void Generate( StringBuilder sb ) + { + annotations.ForEach( + ( an )=> + { + sb.Append( "@" ); + sb.Append( an ); + sb.Append( "\n" ); + } + ); + + sb.Append( "var " + name + ": " + memberType + "; " ); + } + +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs.uid new file mode 100644 index 0000000..e78ebb0 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs.uid @@ -0,0 +1 @@ +uid://51c533ougel diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs new file mode 100644 index 0000000..7684242 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs @@ -0,0 +1,17 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public abstract class GDScriptGeneratorMember +{ + public string name; + public string memberType; + public List annotations = []; + + + public abstract void Generate( StringBuilder sb ); + +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs.uid new file mode 100644 index 0000000..e864a06 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs.uid @@ -0,0 +1 @@ +uid://bnl20gavp2hi2 diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs new file mode 100644 index 0000000..16fd301 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs @@ -0,0 +1,75 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public class GDScriptGeneratorMethod:GDScriptGeneratorMember +{ + public List parameters = []; + public string body = ""; + public bool isConstructor = false; + + public override void Generate( StringBuilder sb ) + { + sb.Append( "\n" ); + sb.Append( "func " + name + "(" ); + + var first = true; + + if ( parameters.Count > 0 ) + { + sb.Append( " " ); + } + + parameters.ForEach( + ( p ) => + { + if ( first ) + { + first = false; + } + else + { + sb.Append( ", " ); + } + + p.Generate( sb ); + + } + ); + + if ( parameters.Count > 0 ) + { + sb.Append( " " ); + } + + if ( isConstructor ) + { + sb.Append( "):\n" ); + } + else + { + sb.Append( ") -> " + memberType + ":\n" ); + } + + + if ( string.IsNullOrEmpty( body ) ) + { + sb.Append( " pass" ); + } + else + { + sb.Append( body ); + } + + + sb.Append( "\n" ); + sb.Append( "## ---"); + sb.Append( "\n" ); + + } + + +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs.uid new file mode 100644 index 0000000..1b2114c --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs.uid @@ -0,0 +1 @@ +uid://ddcgqrokie8en diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs new file mode 100644 index 0000000..9004d41 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs @@ -0,0 +1,24 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Rokojori; + +public class GDScriptGeneratorParameter +{ + public string name; + public string parameterType; + public string parameterValue; + + public void Generate( StringBuilder sb ) + { + sb.Append( name + ": " + parameterType ); + + if ( parameterValue != null ) + { + sb.Append( " = " + parameterValue ); + } + } + +} \ No newline at end of file diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs.uid new file mode 100644 index 0000000..c786982 --- /dev/null +++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs.uid @@ -0,0 +1 @@ +uid://bg3fdqomodfh2 diff --git a/Runtime/Text/Lexing/Lexer.cs b/Runtime/Text/Lexing/Lexer.cs index 9b66233..eff29e6 100644 --- a/Runtime/Text/Lexing/Lexer.cs +++ b/Runtime/Text/Lexing/Lexer.cs @@ -42,6 +42,10 @@ namespace Rokojori public bool hasError => _hasError; + public virtual void Clear() + { + _hasError = false; + } void AddMatcher( LexerMatcher matcher ) { @@ -74,6 +78,16 @@ namespace Rokojori AddMatcher( type, new Regex( regex ), mode, nextMode ); } + public virtual bool HasVariableMatch( string type ) + { + return LexerMatcherLibrary.CwordMatcher.type == type || LexerMatcherLibrary.CFunctionMatcher.type == type; + } + + public static bool IsVariableMatchType( string type ) + { + return LexerMatcherLibrary.CwordMatcher.type == type || LexerMatcherLibrary.CFunctionMatcher.type == type; + } + public LexerMatcher GetMatcher( string source, string mode ="" ) { var matchers = _modes[ mode ]; diff --git a/Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs b/Runtime/Text/Lexing/LexerLibrary/CSLexer.cs similarity index 92% rename from Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs rename to Runtime/Text/Lexing/LexerLibrary/CSLexer.cs index 198f374..e051c33 100644 --- a/Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs +++ b/Runtime/Text/Lexing/LexerLibrary/CSLexer.cs @@ -12,11 +12,11 @@ namespace Rokojori } - public class CSharpLexer:Lexer + public class CSLexer:Lexer { public static List Lex( string source ) { - var lexer = new CSharpLexer(); + var lexer = new CSLexer(); var events = lexer.LexToList( source ); if ( lexer.hasError ) @@ -36,8 +36,7 @@ namespace Rokojori } public static List GetAllObjectDefinitions( List tokens ) - { - + { var START = Trillean.True; var END = Trillean.False; @@ -72,7 +71,7 @@ namespace Rokojori return sequences.Map( s => new CSharpObjectDefinition{ type = s[ 0 ], name = s[ s.Count - 1 ] } ); } - public CSharpLexer() + public CSLexer() { AddAllMatchers( LexerMatcherLibrary.SingleLineCommentMatcher, @@ -87,7 +86,7 @@ namespace Rokojori LexerMatcherLibrary.WhiteSpaceMatcher, LexerMatcherLibrary.LogicMatcher, LexerMatcherLibrary.BracketMatcher, - LexerMatcherLibrary.AccessModifierMatcher, + LexerMatcherLibrary.CSAccessModifierMatcher, LexerMatcherLibrary.ClassMatcher, LexerMatcherLibrary.EnumMatcher, LexerMatcherLibrary.StructMatcher, @@ -95,6 +94,8 @@ namespace Rokojori LexerMatcherLibrary.RecordMatcher, LexerMatcherLibrary.OperatorMatcher, LexerMatcherLibrary.CFunctionMatcher, + LexerMatcherLibrary.UsingMatcher, + LexerMatcherLibrary.NamespaceMatcher, LexerMatcherLibrary.CwordMatcher, LexerMatcherLibrary.AnySymbolMatcher ); diff --git a/Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs.uid b/Runtime/Text/Lexing/LexerLibrary/CSLexer.cs.uid similarity index 100% rename from Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs.uid rename to Runtime/Text/Lexing/LexerLibrary/CSLexer.cs.uid diff --git a/Runtime/Text/Lexing/LexerMatcherLibrary.cs b/Runtime/Text/Lexing/LexerMatcherLibrary.cs index 1a8686f..fa998f9 100644 --- a/Runtime/Text/Lexing/LexerMatcherLibrary.cs +++ b/Runtime/Text/Lexing/LexerMatcherLibrary.cs @@ -18,6 +18,11 @@ namespace Rokojori public static readonly LexerMatcher PHPWordMatcher = new LexerMatcher( "PHPWord", @"\$?[a-zA-Z_]\w*" ); + public static readonly LexerMatcher UsingMatcher = + new LexerMatcher( "Using", @"using" ); + + public static readonly LexerMatcher NamespaceMatcher = + new LexerMatcher( "Namespace", @"namespace" ); public static readonly LexerMatcher CSS_ClassSelectorMatcher = new LexerMatcher( "CSS_ClassSelector", @"\.[a-zA-Z_](\w|\-)*" ); @@ -58,7 +63,7 @@ namespace Rokojori new LexerMatcher( "Logic", "if|else|switch|do|while|for|break|continue|return" ); public static readonly LexerMatcher OperatorMatcher = - new LexerMatcher( "Operator", "(?:\\=\\=)|(?:\\+\\+)|(?:\\-\\-)|(?:\\+\\=)|(?:\\*\\=)|(?:\\-\\=)|(?:\\/\\=)|\\+|\\-|\\*|\\/|\\^|\\||\\~|\\&|\\%|\\<|\\>|\\=|\\!|\\.|\\:|\\,|\\;" ); + new LexerMatcher( "Operator", "(?:\\=\\=)|(?:\\+\\+)|(?:\\-\\-)|(?:\\+\\=)|(?:\\*\\=)|(?:\\-\\=)|(?:\\/\\=)|(?:\\=\\>)|\\+|\\-|\\*|\\/|\\^|\\|\\||\\||\\~|\\&\\&|\\&|\\%|\\<|\\>|\\=|\\!|\\.|\\:|\\,|\\;" ); public static readonly LexerMatcher BracketMatcher = new LexerMatcher( "Bracket", @"\(|\)|\[|\]|\{|\}" ); @@ -87,6 +92,9 @@ namespace Rokojori public static readonly LexerMatcher AccessModifierMatcher = new LexerMatcher( "AccessModifier", @"\b(?:public|protected|private|const)\b" ); + public static readonly LexerMatcher CSAccessModifierMatcher = + new LexerMatcher( "AccessModifier", @"\b(?:public|protected|private|const|partial|internal|abstract|static|sealed|virtual|override|readonly|ref|unsafe|new)\b" ); + public static readonly LexerMatcher SingleLineCommentMatcher = new LexerMatcher( "SingleLineComment", @"//.*" ); diff --git a/Runtime/Text/Parsing/AST/ASTFileRoot.cs b/Runtime/Text/Parsing/AST/ASTFileRoot.cs new file mode 100644 index 0000000..59bc54c --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTFileRoot.cs @@ -0,0 +1,18 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface ASTFileRoot +{ + public string GetFilePath(); + public string GetSource(); + public TextLinesMapper GetTextLinesMapper(); + public Parser GetParser(); + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ASTFileRoot.cs.uid b/Runtime/Text/Parsing/AST/ASTFileRoot.cs.uid new file mode 100644 index 0000000..d9acadb --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTFileRoot.cs.uid @@ -0,0 +1 @@ +uid://blsoe8oknj2wy diff --git a/Runtime/Text/Parsing/AST/ASTNode.cs b/Runtime/Text/Parsing/AST/ASTNode.cs new file mode 100644 index 0000000..f1e43ee --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTNode.cs @@ -0,0 +1,918 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public abstract class ASTNode +{ + Parser _parser; + + public Parser parser + { + get + { + if ( _parser == null ) + { + var root = this is ASTFileRoot ? (ASTFileRoot) this : + ( ASTWalker.instance.GetParentWithType( this ) as ASTFileRoot ); + + _parser = root.GetParser(); + } + + return _parser; + } + } + + public ASTNode parent; + public List children = []; + + + int ComputeIndex( int index ) + { + return index >= 0 ? index : ( children.Count + index ); + } + + + public string CreateDebugTreeInfo() + { + var walker = ASTWalker.instance; + + var end = walker.IterationEndOf( this ); + + var it = this; + + var depthMap = new Dictionary(); + + Func GetDepth = null; + + GetDepth = n => + { + if ( depthMap.ContainsKey( n ) ) + { + return depthMap[ n ]; + } + + if ( n.parent == null ) + { + return 0; + } + + var parentDepth = GetDepth( n.parent ); + var ownDepth = parentDepth + 1; + + depthMap[ n ] = ownDepth; + + return ownDepth; + }; + + var lines = new List(); + + while ( it != end ) + { + var indent = " ".Repeat( GetDepth( it ) ); + var info = indent + "-- [#" + it.childIndex + "] " + it.GetType(); + + + if ( it is Token tk ) + { + info += "'" + tk.match+ "'"; + } + else + { + info += "(" + it.children.Count + ")"; + } + + lines.Add( info ); + + it = walker.NextNode( it ); + } + + return lines.Join( "\n"); + + } + + public List GrabTokenRange( Token start, Token end, bool filter ) + { + if ( start.parent != this || end.parent != this ) + { + RJLog.Error( "Tokens are not children of this", GetType().Name, "start:", start, "end:", end ); + return null; + } + + var startIndex = start.childIndex; + var endIndex = end.childIndex; + + // RJLog.Log( "Grabbing Child Range:", startIndex, "to", endIndex, " num children:", children.Count ); + var unfiltered = children.Range( start.childIndex, end.childIndex ); + var filtered = unfiltered.Filter( n => n is Token && ( ! filter || ! n.IsIgnoreToken() ) ); + return filtered.Map( f => f as Token ); + } + + public void MergeChildren( int start, int length, ASTNode merger ) + { + merger.parent = this; + merger.children = children.Sub( start, length ); + merger.children.ForEach( c => c.parent = merger ); + + children.ReplaceRange( start, length, [ merger ] ); + } + + public T MergeInner( int indexStart, int indexEnd ) where T:ASTNode,new() + { + var start = indexStart + 1; + var length = indexEnd - start; + + return MergeChildrenWith( start, length ); + } + + public T MergeOuter( int indexStart, int indexEnd ) where T:ASTNode,new() + { + var start = indexStart; + var length = indexEnd - start + 1; + + return MergeChildrenWith( start, length ); + } + + public T MergeOuter( ASTNode nodeStart, ASTNode nodeEnd ) where T:ASTNode,new() + { + if ( nodeStart.parent != this || nodeEnd.parent != this ) + { + RJLog.Error( "Nodes are not child of this node:", this, + "start:", nodeStart, "start is child:", nodeStart.parent == this, + "end:", nodeEnd, "end is child:", nodeEnd.parent == this + ); + return null; + } + + var startIndex = nodeStart.childIndex; + var endIndex = children.FindIndex( startIndex, c => c == nodeEnd ); + + return MergeOuter( startIndex, endIndex ); + } + + public T MergeInner( ASTNode nodeStart, ASTNode nodeEnd ) where T:ASTNode,new() + { + if ( nodeStart.parent != this || nodeEnd.parent != this ) + { + RJLog.Error( "Nodes are not child of this node:", this, "start:", nodeStart, "end:", nodeEnd ); + return null; + } + + var startIndex = nodeStart.childIndex; + var endIndex = children.FindIndex( startIndex, c => c == nodeEnd ); + + RJLog.Log( "Merging:", startIndex, endIndex ); + + if ( startIndex == -1 || endIndex == - 1 ) + { + return null; + } + + return MergeInner( startIndex, endIndex ); + } + + public int childIndex => parent == null ? -1 : parent.children.IndexOf( this ); + public int reverseIndexOffset => parent == null ? -1 : + ( ( parent.children.Count - 1 ) - childIndex ); + + public string CombinedMatch() + { + if ( this is Token tk ) + { + return tk.match; + } + + var tokens = children.FilterType(); + + return tokens.Map( t => t.match ).Join( "" ); + } + + public void ExpandToPrevious( ASTNode previousSibling ) + { + if ( parent == null || previousSibling == null || parent != previousSibling.parent ) + { + RJLog.Error( "Invalid sibling", previousSibling?.GetType().Name ?? "null" ); + return; + } + + var start = previousSibling.childIndex; + var length = childIndex - start; + + var beforeCount = children.Count; + + var range = parent.children.Sub( start, length ); + parent.children.RemoveRange( start, length ); + + range.ForEach( r => r.parent = this ); + children.Prepend( range ); + + RJLog.Log( "Expanded from", beforeCount, "to", children.Count, "( " + length + " )" ); + } + + public ASTWalker walker => Singleton.Get(); + + public T GetParentWithType() + { + return walker.GetParentWithType( this ); + } + + public T MergeChildrenWith( int start, int length ) where T:ASTNode, new() + { + var t = new T(); + MergeChildren( start, length, t ); + return t; + } + + public int FindIndex( System.Func evaluator, int offset = 0, int end = -1, bool forward = true ) + { + offset = ComputeIndex( offset ); + end = ComputeIndex( end ); + + var change = forward ? 1 : -1; + end += change; + + // RJLog.Log( "start:", offset, "end:", end, "direction:", change > 0 ? "forward" : "backwards", change, "children:", children.Count ); + for ( int i = offset; i != end; i += change ) + { + if ( evaluator( children[ i ] ) ) + { + return i; + } + else + { + // RJLog.Log( "not matching", children[ i ] ); + } + } + + return -1; + } + + public ASTNode FindNode( System.Func evaluator, int offset = 0 ) + { + var index = FindIndex( evaluator, offset ); + return index == -1 ? null : children[ index ]; + } + + public int ReverseFindBracketOpenerIndex( string open, string close, int closeIndex ) + { + closeIndex --; + var count = 1; + + // RJLog.Log( "ReverseFindBracketOpenerIndex", open, close, closeIndex ); + + for ( int i = closeIndex; i >= 0; i-- ) + { + + var child = children[ i ]; + + // RJLog.Log( "index", i, count, child ); + + if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, open ) ) + { + count --; + + if ( count == 0 ) + { + return i; + } + } + else if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, close ) ) + { + count ++; + } + + // RJLog.Log( "index", i, count ); + } + + return -1; + } + + public int FindBracketCloserIndex( string open, string close, int openIndex ) + { + openIndex ++; + var count = 1; + + // RJLog.Log( "ReverseFindBracketOpenerIndex", open, close, closeIndex ); + + for ( int i = openIndex; i < children.Count; i++ ) + { + + var child = children[ i ]; + + // RJLog.Log( "index", i, count, child ); + + if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, close ) ) + { + count --; + + if ( count == 0 ) + { + return i; + } + } + else if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, open ) ) + { + count ++; + } + + // RJLog.Log( "index", i, count ); + } + + return -1; + } + + public List GetSeparatorIndices( string separator, int start, int end, List blockPredicates = null, Lexer lexer = null ) + { + lexer = lexer ?? new CSLexer(); + + var hasBlockPredicated = blockPredicates != null; + + var separatorPredicate = TokenPredicateData.Lexed( lexer, separator ); + + if ( ! hasBlockPredicated ) + { + blockPredicates = new List(); + + blockPredicates.Add( TokenPredicateData.Lexed( lexer, "<" ) ); + blockPredicates.Add( TokenPredicateData.Lexed( lexer, ">" ) ); + + blockPredicates.Add( TokenPredicateData.Lexed( lexer, "[" ) ); + blockPredicates.Add( TokenPredicateData.Lexed( lexer, "]" ) ); + + blockPredicates.Add( TokenPredicateData.Lexed( lexer, "(" ) ); + blockPredicates.Add( TokenPredicateData.Lexed( lexer, ")" ) ); + + blockPredicates.Add( TokenPredicateData.Lexed( lexer, "{" ) ); + blockPredicates.Add( TokenPredicateData.Lexed( lexer, "}" ) ); + } + + var bcCounter = new List(); + + for ( int i = 0; i < blockPredicates.Count; i+= 2 ) + { + bcCounter.Add( 0 ); + } + + + var inBlock = false; + + var indices = new List(); + + for ( int i = start + 1; i < end; i++ ) + { + if ( children[ i ].IsIgnoreToken() ) + { + continue; + } + + if ( ! inBlock && separatorPredicate.Matches( children[ i ] ) ) + { + indices.Add( i ); + continue; + } + + var bcIndex = blockPredicates.FindIndex( bc => bc.Matches( children[ i ] ) ); + + if ( bcIndex == -1 ) + { + continue; + } + + var index = bcIndex / 2; + var isUp = index * 2 == bcIndex; + + var change = isUp ? 1 : -1; + + bcCounter[ index ] += change; + + var sum = 0; bcCounter.ForEach( b => sum += b ); + inBlock = sum != 0; + + } + + return indices; + } + + public void CreateSeperatedList( string separator, Action callback = null ) where T:ASTNode, new() + { + var indices = GetSeparatorIndices( separator, -1, children.Count ); + + indices.Insert( 0, -1 ); + indices.Add( children.Count ); + + RJLog.Log( "Parameters Indices:", indices.Count, CombinedMatch() ); + + var nodes = new List(); + + + for ( int i = 0; i < indices.Count - 1; i++ ) + { + var start = indices[ i ] + 1; + var end = indices[ i + 1 ] - 1; + + var t = new T(); + + RJLog.Log( "Parameters Grabbing Indices:", start, end ); + + if ( start > end || start < 0 || end < 0 || start >= children.Count || end >= children.Count ) + { + RJLog.Error( "Invalid seperation indices", this, CombinedMatch() ); + throw new Exception(); + } + + if ( start == end ) + { + t.children = [ children[ start ] ]; + } + else + { + t.children = children.Range( start, end ); + } + + t.children.ForEach( c => c.parent = t ); + nodes.Add( t ); + t.parent = this; + } + + children = nodes; + + if ( callback != null ) + { + children.ForEach( n => callback( n as T ) ); + } + + } + + + public Token FindBracketCloser( string open, string close, int openIndex ) + { + var index = FindBracketCloserIndex( open, close, openIndex ); + + return index == -1 ? null : ( children[ index ] as Token ); + } + + public Token ReverseFindBracketOpener( string open, string close, int closeIndex ) + { + var index = ReverseFindBracketOpenerIndex( open, close, closeIndex ); + + return index == -1 ? null : ( children[ index ] as Token ); + } + + public bool IsToken( LexerMatcher matcher, string match = null ) + { + return this is Token tk && tk.Is( matcher, match ); + } + + public bool IsToken( string type, string match = null ) + { + return this is Token tk && tk.Is( type, match ); + } + + public bool IsAnyTokenOf( LexerMatcher[] matchers ) + { + return this is Token tk && tk.lexerEvent.IsAnyOf( matchers ); + } + + public bool IsAnyTokenOf( List predicates ) + { + return this is Token && predicates.Find( p => p.Matches( this ) ) != null ; + } + + public bool IsIgnoreToken() + { + return IsAnyTokenOf( LexerMatcherLibrary.Ignore ); + } + + public int IndexOffset( int index, int offset ) + { + if ( offset < 0 ) + { + while ( offset < 0 ) + { + index = PreviousIndex( index ); + offset ++; + } + } + else + { + while ( offset > 0 ) + { + index = NextIndex( index ); + offset--; + } + } + + return index; + } + + public int PreviousIndex( int index ) + { + for ( int i = index - 1; i >= 0; i-- ) + { + if ( children[ i ].IsIgnoreToken() ) + { + continue; + } + + return i; + } + + return -1; + } + + public ASTNode PreviousNode( int index ) + { + return IndexToChildNode( PreviousIndex( index ) ); + } + + public int NextIndex( int index ) + { + for ( int i = index + 1; i < children.Count; i++ ) + { + if ( children[ i ].IsIgnoreToken() ) + { + continue; + } + + return i; + } + + return -1; + } + + public ASTNode NextNode( int index ) + { + return IndexToChildNode( NextIndex( index ) ); + } + + ASTNode IndexToChildNode( int index ) + { + return index == -1 ? null : children[ index ]; + } + + public Token FindToken( LexerMatcher matcher, int offset = 0 ) + { + return FindToken( matcher, null, offset ); + } + + public Token FindToken( TokenPredicateData predicateData, int offset = 0 ) + { + return FindToken( predicateData.type, predicateData.match, offset ); + } + + public Token FindToken( string type, string match, int offset = 0 ) + { + return FindNode( n => n.IsToken( type, match ), offset ) as Token; + } + + + public Token FindToken( LexerMatcher matcher, string match, int offset = 0 ) + { + return FindNode( n => n.IsToken( matcher, match ), offset ) as Token; + } + + public int FindTokenIndex( LexerMatcher matcher, string match, int offset = 0, int end = -1, bool forward = true ) + { + return FindIndex( n => n.IsToken( matcher, match ), offset, end, forward ); + } + + public int FindTokenIndex( string type, string match, int offset = 0, int end = -1, bool forward = true ) + { + return FindIndex( n => n.IsToken( type, match ), offset, end, forward ); + } + + public int FindTokenIndex( LexerMatcher matcher, int offset = 0, int end = -1, bool forward = true ) + { + return FindIndex( n => n.IsToken( matcher, null ), offset, end, forward ); + } + + public int ReverseFindTokenIndex( LexerMatcher matcher, int reverseOffset = 0) + { + return FindTokenIndex( matcher, -( 1 + reverseOffset ), 0, false ); + } + + public int ReverseFindTokenIndex( TokenPredicateData predicateData, int reverseOffset = 0 ) + { + return FindTokenIndex( predicateData.type, predicateData.match, -( 1 + reverseOffset ), 0, false ); + } + + public Token ReverseFindToken( TokenPredicateData predicateData, int reverseOffset = 0 ) + { + var index = ReverseFindTokenIndex( predicateData, reverseOffset ); + + return index == -1 ? null : ( children[ index ] as Token ); + } + + public List GetFilteredTokens( int offset = 0, int end = -1 ) + { + var tokens = new List(); + + IterateTokens( tokens.Add, offset, end ); + + return tokens; + } + + + + public void Iterate( Action action, Predicate filter = null, int offset = 0, int end = -1, bool forward = true ) + { + offset = ComputeIndex( offset ); + end = ComputeIndex( end ); + + int change = forward ? 1 : -1; + end += change; + + for ( int i = offset; i != end; i += change ) + { + if ( children[ i ] is T t && ( filter == null || filter( t ) ) ) + { + action( t ); + } + } + + + } + + public void IterateTokens( Action action, int start = 0, int end = -1, LexerMatcher[] ignoreMatchers = null, bool forward = true ) + { + start = ComputeIndex( start ); + end = ComputeIndex( end ); + + ignoreMatchers = ignoreMatchers ?? LexerMatcherLibrary.Ignore; + Iterate( action, ( t ) => ! t.IsAnyTokenOf( ignoreMatchers ), start, end, true ); + } + + public string GetTokenMatches( int offset = 0, int end = -1, LexerMatcher[] ignoreMatchers = null ) + { + var sb = new StringBuilder(); + + IterateTokens( + ( tk )=> + { + sb.Append( tk.match ); + }, + offset, end, + ignoreMatchers, + true + ); + + return sb.ToString(); + } + + public int SearchIndex( Predicate searchPredicate, Predicate ignore = null, int offset = 0, int end = -1, bool forward = true ) + { + offset = ComputeIndex( offset ); + end = ComputeIndex( end ); + + var change = forward ? 1 : -1; + end += change; + + // RJLog.Log( "SearchIndex", offset, end, "Change", change ); + + if ( change > 0 && end < offset ) + { + throw new System.Exception( "Invalid range, offset is higher than end: " + offset + " >> " + end ); + } + else if ( change < 0 && end > offset ) + { + throw new System.Exception( "Invalid range, offset is lower than end: " + offset + " >> " + end ); + } + + for ( int i = offset; i != end; i += change ) + { + if ( searchPredicate( children[ i ] ) ) + { + return i; + } + + if ( ignore( children[ i ] ) ) + { + continue; + } + + return -1; + } + + + return -1; + } + + public int SearchFilteredTokenIndex( LexerMatcher matcher, string match, int offset = 0 ) + { + return SearchIndex( + ( n ) => n.IsToken( matcher, match ), + ( n ) => n.IsAnyTokenOf( LexerMatcherLibrary.Ignore ), + offset, -1, + true + ); + } + + public int SearchFilteredTokenIndex( string type, string match, int offset = 0 ) + { + return SearchIndex( + ( n ) => n.IsToken( type, match ), + ( n ) => n.IsAnyTokenOf( LexerMatcherLibrary.Ignore ), + offset, -1, + true + ); + } + + public int SearchFilteredTokenIndex( Predicate predicate, int offset = 0 ) + { + return SearchIndex( + ( n ) => n is Token t && predicate( t ), + ( n ) => n.IsAnyTokenOf( LexerMatcherLibrary.Ignore ), + offset, -1, + true + ); + } + + public int SearchFilteredTokenIndex( LexerMatcher matcher, int offset = 0 ) + { + return SearchFilteredTokenIndex( matcher, null, offset ); + } + + public List SearchFilteredSequence( List> sequence, int offset = 0 ) + { + var output = new List(); + + for ( int i = 0; i < sequence.Count; i++ ) + { + var next = SearchFilteredTokenIndex( sequence[ i ], offset ); + + if ( next == -1 ) + { + // RJLog.Log( "Could not find sequence step", i, "at offset", offset ); + return null; + } + + // RJLog.Log( "Found sequence step", i, "at offset", offset, "in", next ); + output.Add( next ); + + offset = next + 1; + } + + + return output; + } + + public List SearchFilteredRepeatSequence( List> start, List> sequence, List> end, int offset = 0 ) + { + // RJLog.Log( "==== SearchFilteredRepeatSequence", offset ); + var output = new List(); + + if ( start != null ) + { + var startList = SearchFilteredSequence( start, offset ); + + if ( startList == null ) + { + // RJLog.Log( "Start not matched", offset ); + return null; + } + + // RJLog.Log( "Start matched", offset ); + output.AddRange( startList ); + + offset = output[ output.Count - 1 ] + 1; + + // RJLog.Log( "Offset after start", offset ); + } + + if ( sequence.Count > 0 ) + { + var repeatedNext = SearchFilteredSequence( sequence, offset ); + + if ( repeatedNext == null ) + { + // RJLog.Log( "Repeat not matched", offset ); + } + + var maxSteps = 1000; + var steps = 0; + + while ( repeatedNext != null && steps < maxSteps ) + { + // RJLog.Log( "Repeat matched:", + // "offset", offset, + // "steps", steps + // ); + output.AddRange( repeatedNext ); + offset = output[ output.Count - 1 ] + 1; + repeatedNext = SearchFilteredSequence( sequence, offset ); + + steps ++; + } + + + // RJLog.Log( "Offset after repeat", offset ); + + } + + if ( end != null ) + { + var endList = SearchFilteredSequence( end, offset ); + + if ( endList == null ) + { + // RJLog.Log( "End not matched", offset ); + return null; + } + + // RJLog.Log( "End matched", offset ); + output.AddRange( endList ); + } + + return output; + } + + public Token FindTriggerToken( int offset, List triggerPredicates, List blockPredicates ) + { + var index = FindTriggerTokenIndex( offset, triggerPredicates, blockPredicates ); + + return index == -1 ? null : children[ index ] as Token; + } + + static bool _IsInsideBlock( List counters ) + { + for ( int i = 0; i < counters.Count; i++ ) + { + if ( counters[ i ] > 0 ) + { + return true; + } + } + + return false; + } + + public int FindTriggerTokenIndex( int offset, List triggerPredicates, List blockPredicates ) + { + var blockTypesCounter = new List(); + var insideBlock = false; + + for ( int i = 0; i < blockPredicates.Count / 2; i++ ) + { + blockTypesCounter.Add( 0 ); + } + + for ( int i = offset; i < children.Count; i++ ) + { + + var child = children[ i ]; + + if ( child.IsIgnoreToken() ) + { + continue; + } + + + + if ( ! insideBlock ) + { + var triggerIndex = triggerPredicates.FindIndex( t => t.Matches( child ) ); + + // RJLog.Log( "Checking:", insideBlock, children[ i ], triggerIndex ); + + if ( triggerIndex != -1 ) + { + return i; + } + + } + else + { + // RJLog.Log( "Checking:", insideBlock, children[ i ] ); + } + + var blockIndex = blockPredicates.FindIndex( b => b.Matches( child ) ); + + if ( blockIndex == -1 ) + { + continue; + } + + var typeIndex = blockIndex / 2; + + var change = typeIndex * 2 == blockIndex ? 1 : -1; + + blockTypesCounter[ typeIndex ] += change; + + + insideBlock = _IsInsideBlock( blockTypesCounter ); + + + + // RJLog.Log( "bracket type:", typeIndex, "change:", change, "insideBlock:", insideBlock, "counters:", blockTypesCounter.Join( ", " ) ); + } + + return -1; + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ASTNode.cs.uid b/Runtime/Text/Parsing/AST/ASTNode.cs.uid new file mode 100644 index 0000000..11244aa --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTNode.cs.uid @@ -0,0 +1 @@ +uid://c2sgo6erb113h diff --git a/Runtime/Text/Parsing/AST/ASTNodeList.cs b/Runtime/Text/Parsing/AST/ASTNodeList.cs new file mode 100644 index 0000000..b27d055 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTNodeList.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + + +public class ASTNodeList:ASTNode +{ + +} diff --git a/Runtime/Text/Parsing/AST/ASTNodeList.cs.uid b/Runtime/Text/Parsing/AST/ASTNodeList.cs.uid new file mode 100644 index 0000000..a87e025 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTNodeList.cs.uid @@ -0,0 +1 @@ +uid://b7bdp0xuww804 diff --git a/Runtime/Text/Parsing/AST/ASTWalker.cs b/Runtime/Text/Parsing/AST/ASTWalker.cs new file mode 100644 index 0000000..a8b42e7 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTWalker.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + + +public class ASTWalker:TreeWalker +{ + public static readonly ASTWalker instance = new ASTWalker(); + + public override ASTNode Parent( ASTNode node ) + { + return node?.parent; + } + + public override ASTNode ChildAt( ASTNode node, int index ) + { + if ( node == null || index < 0 || index >= node.children.Count ) + { + return null; + } + + return node.children[ index ]; + } + + public override int NumChildren( ASTNode node ) + { + return node?.children.Count ?? 0; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ASTWalker.cs.uid b/Runtime/Text/Parsing/AST/ASTWalker.cs.uid new file mode 100644 index 0000000..6af338c --- /dev/null +++ b/Runtime/Text/Parsing/AST/ASTWalker.cs.uid @@ -0,0 +1 @@ +uid://dckstcta240bf diff --git a/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs new file mode 100644 index 0000000..55111d9 --- /dev/null +++ b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface EnumValueDeclaration +{ + public string GetEnumName(); + public string GetEnumValue(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs.uid b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs.uid new file mode 100644 index 0000000..1e3a888 --- /dev/null +++ b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bm88qdxlr5bbl diff --git a/Runtime/Text/Parsing/AST/ImportDeclaration.cs b/Runtime/Text/Parsing/AST/ImportDeclaration.cs new file mode 100644 index 0000000..31d3795 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ImportDeclaration.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface ImportDeclaration +{ + public string GetImportPath(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ImportDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ImportDeclaration.cs.uid new file mode 100644 index 0000000..e3f3bc1 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ImportDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bb50r0rlavqev diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs new file mode 100644 index 0000000..d0ea560 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs @@ -0,0 +1,55 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class ASTMatchResult +{ + public ASTNode parent = null; + public int childOffset = -1; + public int resultStart = -1; + public int resultEnd = -1; + public bool matched = false; + + public Token resultStartToken => ! matched ? null : parent.children[ resultStart ] as Token; + public Token resultEndToken => ! matched ? null : parent.children[ resultEnd ] as Token; + + public void SetMatchedByLength( int matchLength ) + { + resultStart = childOffset; + resultEnd = childOffset + ( matchLength - 1 ); + matched = true; + } + + public void SetMatched( int index, int endIndex = -1 ) + { + resultStart = index; + resultEnd = endIndex == -1 ? index : endIndex; + matched = true; + } + + + + public int matchLength => ( resultEnd - resultStart ) + 1; + public int childOffsetMatchLength => ( resultEnd - childOffset ) + 1; + + public ASTMatchResult Clone() + { + var c = new ASTMatchResult(); + c.parent = parent; + c.childOffset = childOffset; + c.resultStart = resultStart; + c.resultEnd = resultEnd; + c.matched = matched; + + return c; + } + + +} diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs.uid b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs.uid new file mode 100644 index 0000000..6cc5ddb --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs.uid @@ -0,0 +1 @@ +uid://d0oglqq8hrpqq diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs new file mode 100644 index 0000000..5ef5477 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs @@ -0,0 +1,26 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public abstract class ASTMatcher +{ + public virtual int GetMatchLength( ASTNode parent, int childOffset ) + { + var astResult = new ASTMatchResult(); + astResult.parent = parent; + astResult.childOffset = childOffset; + + Match( astResult ); + + return astResult.matched ? astResult.childOffsetMatchLength : -1; + } + + public abstract void Match( ASTMatchResult result ); +} diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs.uid new file mode 100644 index 0000000..c42cd26 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://djut8mpfu6sep diff --git a/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs new file mode 100644 index 0000000..98913c3 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs @@ -0,0 +1,98 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class BracketBlockMatcher:ASTMatcher +{ + public TokenPredicateData blockStart; + public TokenPredicateData blockEnd; + public bool matchingAtStartIsMandatory = true; + + public override void Match( ASTMatchResult result ) + { + var parent = result.parent; + var childOffset = result.childOffset; + + var count = 0; + + if ( matchingAtStartIsMandatory && ! blockStart.Matches( parent.children[ childOffset ] ) ) + { + return; + } + + for ( int i = childOffset; i < parent.children.Count; i++ ) + { + var child = parent.children[ i ]; + + if ( blockStart.Matches( child ) ) + { + if ( count == 0 ) + { + result.resultStart = i; + } + + count ++; + } + else if ( blockEnd.Matches( child ) ) + { + count --; + + if ( count == 0 ) + { + result.SetMatched( childOffset, i ); + return; + } + } + else if ( count < 0 ) + { + result.resultStart = -1; + return; + } + } + + result.resultStart = -1; + return; + } + + public override int GetMatchLength( ASTNode parent, int childOffset ) + { + var count = 0; + + if ( matchingAtStartIsMandatory && ! blockStart.Matches( parent.children[ childOffset ] ) ) + { + return -1; + } + + for ( int i = childOffset; i < parent.children.Count; i++ ) + { + var child = parent.children[ i ]; + + if ( blockStart.Matches( child ) ) + { + count ++; + } + else if ( blockEnd.Matches( child ) ) + { + count --; + + if ( count == 0 ) + { + return ( i - childOffset + 1 ); + } + } + else if ( count < 0 ) + { + return -1; + } + } + + return -1; + } +} diff --git a/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs.uid new file mode 100644 index 0000000..8e85daf --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://c4niejh1k1gal diff --git a/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs new file mode 100644 index 0000000..382c62c --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs @@ -0,0 +1,70 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class CombinedASTMatcher:ASTMatcher +{ + public List matchers; + + public override void Match( ASTMatchResult result ) + { + var offset = result.childOffset; + var end = -1; + + for ( int i = 0; i < matchers.Count; i++ ) + { + var subResult = result.Clone(); + subResult.childOffset = offset; + + matchers[ i ].Match( subResult ); + + end = subResult.resultEnd; + + // var matchLength = matchers[ i ].GetMatchLength( result.parent, offset ); + + if ( ! subResult.matched ) + { + return; + } + + offset = subResult.resultEnd + 1; + + // RJLog.Log( "Matched", i, matchers[ i ], "length:", matchLength, "combinedMatch:", combinedMatchLength, "offset:", matchOffset, ">>", offset ); + } + + result.SetMatched( result.childOffset, end ); + + return; + } + + public override int GetMatchLength( ASTNode parent, int childOffset ) + { + var offset = childOffset; + var combinedMatchLength = 0; + + for ( int i = 0; i < matchers.Count; i++ ) + { + var matchOffset = offset; + var matchLength = matchers[ i ].GetMatchLength( parent, offset ); + + if ( matchLength == -1 ) + { + return -1; + } + + combinedMatchLength += matchLength; + offset += matchLength; + + RJLog.Log( "Matched", i, matchers[ i ], "length:", matchLength, "combinedMatch:", combinedMatchLength, "offset:", matchOffset, ">>", offset ); + } + + return combinedMatchLength; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs.uid new file mode 100644 index 0000000..1f8813d --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://boxrq5cfmtlat diff --git a/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs new file mode 100644 index 0000000..d49d7d5 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class LambdaASTMatcher:ASTMatcher +{ + public Action func; + + public override void Match( ASTMatchResult result ) + { + func( result ); + } + +} diff --git a/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs.uid new file mode 100644 index 0000000..a524a75 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://c2svke11rfs5p diff --git a/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs new file mode 100644 index 0000000..76a202a --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs @@ -0,0 +1,39 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class MultiTriggerASTMatcher:ASTMatcher +{ + public List triggerPredicates = []; + public List blockPredicates = []; + public bool matchSticky = false; + + public override void Match( ASTMatchResult result ) + { + var parent = result.parent; + var childOffset = result.childOffset; + + var triggerIndex = parent.FindTriggerTokenIndex( childOffset, triggerPredicates, blockPredicates ); + + if ( matchSticky && triggerIndex != childOffset ) + { + return; + } + + if ( triggerIndex == -1 ) + { + return; + } + + result.SetMatched( triggerIndex ); + + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs.uid new file mode 100644 index 0000000..5dbfdec --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://ceitlc83bl3fv diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs new file mode 100644 index 0000000..cd79060 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs @@ -0,0 +1,65 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class TokenRepeatSequenceASTMatcher:ASTMatcher +{ + public List> startSequence = []; + public List> repeatSequence = []; + public List> endSequence = []; + + public override void Match( ASTMatchResult result ) + { + var parent = result.parent; + var childOffset = result.childOffset; + + var output = parent.SearchFilteredRepeatSequence( startSequence, repeatSequence, endSequence, childOffset ); + + if ( output == null ) + { + return; + } + + result.SetMatched( output.First(), output.Last() ); + + } + + public override int GetMatchLength( ASTNode parent, int childOffset ) + { + var output = parent.SearchFilteredRepeatSequence( startSequence, repeatSequence, endSequence, childOffset ); + + if ( output != null ) + { + var lastOffset = output.Last(); + // RJLog.Log( "First child:", childOffset, parent.children[ childOffset ] ); + // RJLog.Log( "Last child:", lastOffset, parent.children[ lastOffset ] ); + + var num = lastOffset - childOffset + 1; + // RJLog.Log( "Num Matches:", num ); + + + return num; + } + + return -1; + } + + public static TokenRepeatSequenceASTMatcher CreateWithLexer( Lexer lexer, string start, string repeat, string end ) + { + var trsm = new TokenRepeatSequenceASTMatcher(); + + trsm.startSequence = Token.CreateLexedSequence( lexer, start ); + trsm.repeatSequence = Token.CreateLexedSequence( lexer, repeat ); + trsm.endSequence = Token.CreateLexedSequence( lexer, end ); + + return trsm; + } + +} diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs.uid new file mode 100644 index 0000000..44ea7fb --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://0duohxt3mrve diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs new file mode 100644 index 0000000..cae87d3 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class TokenSequenceASTMatcher:ASTMatcher +{ + public List> sequence = []; + + public override void Match( ASTMatchResult result ) + { + var parent = result.parent; + var childOffset = result.childOffset; + + var output = parent.SearchFilteredSequence( sequence, childOffset ); + + if ( output == null ) + { + return; + } + + result.SetMatched( output.First(), output.Last() ); + + } + + public override int GetMatchLength( ASTNode parent, int childOffset ) + { + var output = parent.SearchFilteredSequence( sequence, childOffset ); + + if ( output != null ) + { + return output.Last() - childOffset + 1 ; + } + + return -1; + } + +} diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs.uid new file mode 100644 index 0000000..607c75d --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://bbtojg1s1nyk3 diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs new file mode 100644 index 0000000..96482c2 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs @@ -0,0 +1,59 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; +using System; + +namespace Rokojori; + +public class TokenWordASTMatcher:ASTMatcher +{ + public LexerMatcher matcher; + public string type; + public string match; + + public override void Match( ASTMatchResult result ) + { + var parent = result.parent; + var searchOffset = result.childOffset; + + var node = parent.children[ searchOffset ]; + + var resolvedType = matcher?.type ?? type; + + if ( ! node.IsToken( resolvedType, match ) ) + { + return; + } + + var endIndex = parent.SearchFilteredTokenIndex( LexerMatcherLibrary.CwordMatcher, searchOffset + 1 ); + + if ( endIndex == -1 ) + { + return; + } + + result.SetMatched( searchOffset, endIndex ); + + } + + public override int GetMatchLength( ASTNode parent, int childOffset ) + { + var node = parent.children[ childOffset ]; + + var resolvedType = matcher?.type ?? type; + + if ( ! node.IsToken( resolvedType, match ) ) + { + return -1; + } + + var endIndex = parent.SearchFilteredTokenIndex( LexerMatcherLibrary.CwordMatcher, childOffset + 1 ); + + return endIndex == -1 ? -1 : ( endIndex - childOffset + 1 ); + } + +} diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs.uid new file mode 100644 index 0000000..aa3aad9 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs.uid @@ -0,0 +1 @@ +uid://4mc5huqdh54k diff --git a/Runtime/Text/Parsing/AST/MemberDeclaration.cs b/Runtime/Text/Parsing/AST/MemberDeclaration.cs new file mode 100644 index 0000000..8e58b10 --- /dev/null +++ b/Runtime/Text/Parsing/AST/MemberDeclaration.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface MemberDeclaration +{ + public string GetMemberName(); + public string GetMemberType(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/MemberDeclaration.cs.uid b/Runtime/Text/Parsing/AST/MemberDeclaration.cs.uid new file mode 100644 index 0000000..fe1eeac --- /dev/null +++ b/Runtime/Text/Parsing/AST/MemberDeclaration.cs.uid @@ -0,0 +1 @@ +uid://b2ny6t7p63kd5 diff --git a/Runtime/Text/Parsing/AST/NamespaceBlock.cs b/Runtime/Text/Parsing/AST/NamespaceBlock.cs new file mode 100644 index 0000000..61eb999 --- /dev/null +++ b/Runtime/Text/Parsing/AST/NamespaceBlock.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface NamespaceBlock +{ + public string GetNamespace(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/NamespaceBlock.cs.uid b/Runtime/Text/Parsing/AST/NamespaceBlock.cs.uid new file mode 100644 index 0000000..f9ea0a0 --- /dev/null +++ b/Runtime/Text/Parsing/AST/NamespaceBlock.cs.uid @@ -0,0 +1 @@ +uid://blj2e4c7oid0g diff --git a/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs new file mode 100644 index 0000000..6b5564a --- /dev/null +++ b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface NamespaceDeclaration +{ + public string GetNamespace(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs.uid b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs.uid new file mode 100644 index 0000000..9fd6d2b --- /dev/null +++ b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs.uid @@ -0,0 +1 @@ +uid://cxa0tcnbff0ma diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs new file mode 100644 index 0000000..571c860 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface ClassDeclaration +{ + public string GetClassName(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs.uid new file mode 100644 index 0000000..231f452 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bj0nh64qu2by1 diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs new file mode 100644 index 0000000..1e5aad7 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface EnumDeclaration +{ + public string GetEnumName(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs.uid new file mode 100644 index 0000000..0f93ff7 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bsu314s2w3b38 diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs new file mode 100644 index 0000000..295ec4f --- /dev/null +++ b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface InterfaceDeclaration +{ + public string GetInterfaceName(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs.uid new file mode 100644 index 0000000..4b69256 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs.uid @@ -0,0 +1 @@ +uid://j8qw38s8gwe1 diff --git a/Runtime/Text/Parsing/AST/ParameterDeclaration.cs b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs new file mode 100644 index 0000000..919f4dc --- /dev/null +++ b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface ParameterDeclaration +{ + public string GetParameterName(); + public string GetParameterType(); + public string GetParameterValue(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ParameterDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs.uid new file mode 100644 index 0000000..3a9f87f --- /dev/null +++ b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs.uid @@ -0,0 +1 @@ +uid://ijaip1ompbed diff --git a/Runtime/Text/Parsing/AST/ResolvableASTNode.cs b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs new file mode 100644 index 0000000..43af084 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public interface ResolvableASTNode +{ + public void Resolve(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/ResolvableASTNode.cs.uid b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs.uid new file mode 100644 index 0000000..1618308 --- /dev/null +++ b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs.uid @@ -0,0 +1 @@ +uid://fd3sy5gl6b6 diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs new file mode 100644 index 0000000..fd3f44d --- /dev/null +++ b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs @@ -0,0 +1,34 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public abstract class ASTMatcherResolver +{ + public ASTMatcher matcher; + + // public abstract void Resolve( ASTNode parent, ASTMatcher matcher, int start, int length ); + public abstract int Resolve( ASTMatchResult result, ASTMatcher matcher ); +} + +public class ASTMatcherResolver:ASTMatcherResolver where T:ASTNode, new() +{ + public System.Func initializer; + + // public override void Resolve( ASTNode parent, ASTMatcher matcher, int start, int length ) + // { + // var t = parent.MergeChildrenWith( start, length ); + // initializer( t, matcher ); + // } + + public override int Resolve( ASTMatchResult result, ASTMatcher matcher ) + { + var t = result.parent.MergeChildrenWith( result.childOffset, result.childOffsetMatchLength ); + return initializer( t, matcher ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs.uid b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs.uid new file mode 100644 index 0000000..3854e8c --- /dev/null +++ b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs.uid @@ -0,0 +1 @@ +uid://33q46ptb0ryn diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs new file mode 100644 index 0000000..5f2167d --- /dev/null +++ b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs @@ -0,0 +1,120 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public class ASTParser +{ + public ASTNode root; + public List resolvers = []; + + public int maxSteps = 1000; + + + public void Process() + { + var result = Resolve(); + + var steps = 0; + + while ( result && steps < maxSteps) + { + RJLog.Log( "Step", steps ); + result = Resolve(); + steps ++; + } + } + + bool Resolve() + { + var hasResult = false; + + for ( int tokenOffset = 0; tokenOffset < root.children.Count; tokenOffset++ ) + { + if ( root.children[ tokenOffset ].IsIgnoreToken() ) + { + continue; + } + + // RJLog.Log( "\n\n---- [ Checking node ]", root.children[ tokenOffset ], tokenOffset ); + + var matchResult = new ASTMatchResult(); + matchResult.childOffset = tokenOffset; + matchResult.parent = root; + + for ( int resolverIndex = 0; resolverIndex < resolvers.Count; resolverIndex++ ) + { + var matcherResolver = resolvers[ resolverIndex ]; + matcherResolver.matcher.Match( matchResult ); + + if ( ! matchResult.matched ) + { + // RJLog.Log( ">>> Not Matched:", resolverIndex, matcherResolver.matcher, matcherResolver ); + + continue; + } + + RJLog.Log( ">>> Matched:", resolverIndex, matcherResolver.matcher, matcherResolver ); + + if ( root.children[ tokenOffset ] is Token tk ) + { + RJLog.Log( "...", tk.lineInfo ); + } + + var resolvedOffset = matcherResolver.Resolve( matchResult, matcherResolver.matcher ); + tokenOffset = resolvedOffset; + + hasResult = true; + resolverIndex = resolvers.Count; + + // RJLog.Log( "Matched:", matcherIndex, matcherResolver.matcher, matcherResolver ); + //return true; + } + } + + return hasResult; + } + + // bool ResolveOld() + // { + // var hasResult = false; + + // for ( int tokenOffset = 0; tokenOffset < root.children.Count; tokenOffset++ ) + // { + // if ( root.children[ tokenOffset ].IsIgnoreToken() ) + // { + // continue; + // } + + // RJLog.Log( "Checking node:", tokenOffset, root.children[ tokenOffset ] ); + + // for ( int matcherIndex = 0; matcherIndex < resolvers.Count; matcherIndex++ ) + // { + // var matcherResolver = resolvers[ matcherIndex ]; + // var matchLength = matcherResolver.matcher.GetMatchLength( root, tokenOffset ); + + // if ( matchLength == -1 ) + // { + + // continue; + // } + + // matcherResolver.Resolve( root, matcherResolver.matcher, tokenOffset, matchLength ); + + + // hasResult = true; + + // RJLog.Log( "Matched:", matcherIndex, matcherResolver.matcher, matcherResolver ); + // //return true; + // } + // } + + // return hasResult; + // } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs.uid b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs.uid new file mode 100644 index 0000000..af341d0 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs.uid @@ -0,0 +1 @@ +uid://2i1vuxaa3b2w diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs new file mode 100644 index 0000000..4ee06a9 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + +public abstract class ASTResolver +{ + public abstract void Resolve( ASTNode parent, ASTMatcher matcher, int start, int length ); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs.uid b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs.uid new file mode 100644 index 0000000..202acf7 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs.uid @@ -0,0 +1 @@ +uid://dijwir0cj2lkj diff --git a/Runtime/Text/Parsing/AST/Token.cs b/Runtime/Text/Parsing/AST/Token.cs new file mode 100644 index 0000000..fa6893e --- /dev/null +++ b/Runtime/Text/Parsing/AST/Token.cs @@ -0,0 +1,163 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + + + +public class Token:ASTNode +{ + // public class PredicateData + // { + // public string type; + // public string match; + + // public bool Matches( ASTNode node ) + // { + // return node.IsToken( type, match ); + // } + + // public System.Predicate predicate + // { + // get + // { + // System.Predicate pred = ( tk ) => tk.Is( type, match ); + // return pred; + // } + // } + + // public static PredicateData Create( string type, string match = null ) + // { + // var pd = new PredicateData(); + // pd.type = type; + // pd.match = match; + // return pd; + // } + + // public static TokenPredicateData Lexed( Lexer lexer, string value ) + // { + // var lexedSequence = CreateLexedSequenceData( lexer, value ); + // return lexedSequence[ 0 ]; + // } + // } + + public LexerEvent lexerEvent; + + public string match => lexerEvent.match; + public string type => lexerEvent.type; + + + public override string ToString() + { + var matchInfo = match.Replace( "\n", "\\n" ).Replace( "\r", "\\r" ); + + return $"Token{{ '{matchInfo}' ({type}) }}"; + } + + public bool Is( string type, string match = null ) + { + return lexerEvent.Is( type, match ); + } + + public bool Is( LexerMatcher matcher, string match = null ) + { + return lexerEvent.Is( matcher.type, match ); + } + + + ASTFileRoot _root; + + public string lineInfo + { + get + { + if ( _root == null ) + { + _root = ASTWalker.instance.GetInParents( this, n => n is ASTFileRoot ) as ASTFileRoot; + } + + var textLine = _root.GetTextLinesMapper().GetLine( lexerEvent.offset ); + return "[ " + textLine.textEditorLineIndex + " ] | " + textLine.GetContent( _root.GetSource() ); + } + } + + public static Token Create( LexerEvent le, ASTNode parent = null ) + { + var t = new Token(); + t.lexerEvent = le; + t.parent = parent; + + return t; + } + + public System.Predicate ToPredicate( Lexer lexer = null ) + { + var isVariableMatch = lexer == null ? Lexer.IsVariableMatchType( type ) : lexer.HasVariableMatch( type ); + var match = isVariableMatch ? null : this.match; + System.Predicate predicate = ( tk ) => tk.Is( type, match ); + return predicate; + } + + public TokenPredicateData ToPredicateData( Lexer lexer = null ) + { + var isVariableMatch = lexer == null ? Lexer.IsVariableMatchType( type ) : lexer.HasVariableMatch( type ); + var match = isVariableMatch ? null : this.match; + return TokenPredicateData.Create( type, match ); + } + + + public static System.Predicate CreateRawPredicate( LexerMatcher matcher, string match = null ) + { + System.Predicate predicate = ( tk ) => tk.Is( matcher, match ); + return predicate; + } + + public static List> CreateLexedSequence( Lexer lexer, string sequence ) + { + lexer.Clear(); + var lexedSequence = lexer.LexToList( sequence ); + + if ( lexer.hasError ) + { + throw new System.Exception( "Lexer has error at char " + lexedSequence.Last().offset + " >> '" + sequence + "'" ); + } + + lexedSequence.Pop(); + lexer.GrabMatches( lexedSequence, sequence ); + + var filteredEvents = lexedSequence.Filter( le => ! le.IsAnyOf( LexerMatcherLibrary.Ignore ) ); + + // RJLog.Log( "Creating predicates:", "'" + sequence + "'", ">", filteredEvents.Count, ">>", filteredEvents.Map( e => e.type + " : " + e.match ).Join( ", " ) ); + + var tokenSequence = filteredEvents.Map( le => Create( le ).ToPredicate( lexer ) ); + + return tokenSequence; + } + + public static List CreateLexedSequenceData( Lexer lexer, string sequence ) + { + lexer.Clear(); + var lexedSequence = lexer.LexToList( sequence ); + + if ( lexer.hasError ) + { + throw new System.Exception( "Lexer has error at char " + lexedSequence.Last().offset + " >> '" + sequence + "'" ); + } + + lexedSequence.Pop(); + lexer.GrabMatches( lexedSequence, sequence ); + + var filteredEvents = lexedSequence.Filter( le => ! le.IsAnyOf( LexerMatcherLibrary.Ignore ) ); + + // RJLog.Log( "Creating predicates:", "'" + sequence + "'", ">", filteredEvents.Count, ">>", filteredEvents.Map( e => e.type + " : " + e.match ).Join( ", " ) ); + + var tokenSequence = filteredEvents.Map( le => Create( le ).ToPredicateData( lexer ) ); + + return tokenSequence; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/AST/Token.cs.uid b/Runtime/Text/Parsing/AST/Token.cs.uid new file mode 100644 index 0000000..e110739 --- /dev/null +++ b/Runtime/Text/Parsing/AST/Token.cs.uid @@ -0,0 +1 @@ +uid://cphvqqm60m3r7 diff --git a/Runtime/Text/Parsing/AST/TokenPredicateData.cs b/Runtime/Text/Parsing/AST/TokenPredicateData.cs new file mode 100644 index 0000000..7fd1837 --- /dev/null +++ b/Runtime/Text/Parsing/AST/TokenPredicateData.cs @@ -0,0 +1,45 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Text; + +using System.Globalization; +using Godot; + +namespace Rokojori; + + + +public class TokenPredicateData +{ + public string type; + public string match; + + public bool Matches( ASTNode node ) + { + return node.IsToken( type, match ); + } + + public System.Predicate predicate + { + get + { + System.Predicate pred = ( tk ) => tk.Is( type, match ); + return pred; + } + } + + public static TokenPredicateData Create( string type, string match = null ) + { + var pd = new TokenPredicateData(); + pd.type = type; + pd.match = match; + return pd; + } + + public static TokenPredicateData Lexed( Lexer lexer, string value ) + { + var lexedSequence = Token.CreateLexedSequenceData( lexer, value ); + return lexedSequence[ 0 ]; + } +} diff --git a/Runtime/Text/Parsing/AST/TokenPredicateData.cs.uid b/Runtime/Text/Parsing/AST/TokenPredicateData.cs.uid new file mode 100644 index 0000000..ed0c756 --- /dev/null +++ b/Runtime/Text/Parsing/AST/TokenPredicateData.cs.uid @@ -0,0 +1 @@ +uid://ckmrtyfsdfncg diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs new file mode 100644 index 0000000..a72d4aa --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class ExpressionContext +{ + public ExpressionResult result; + public List messages = []; +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs.uid b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs.uid new file mode 100644 index 0000000..0f6700f --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs.uid @@ -0,0 +1 @@ +uid://c6itj3geuk3nu diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs new file mode 100644 index 0000000..7a3226c --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public abstract class ExpressionEvaluator +{ + protected virtual ExpressionContext _CreateContext(){ return new ExpressionContext(); } + protected abstract ExpressionResult _Evaluate( ExpressionContext context, OperatorExpression expression ); + + public ExpressionContext EvaluateExpression( OperatorExpression expression ) + { + var context = _CreateContext(); + context.result = _Evaluate( context, expression ); + + return context; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs.uid b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs.uid new file mode 100644 index 0000000..68ff8f9 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs.uid @@ -0,0 +1 @@ +uid://bfwfkc6f5kl6o diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs new file mode 100644 index 0000000..1bb5f6a --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class ExpressionResult +{ + public object value; + public List messages = []; + + public bool hasError => messages.Find( m => m.type == MessageType.Error ) != null; +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs.uid b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs.uid new file mode 100644 index 0000000..2b9c24d --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs.uid @@ -0,0 +1 @@ +uid://isphlk2qxbbd diff --git a/Runtime/Text/Parsing/Expressions/ExpressionParser.cs b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs new file mode 100644 index 0000000..dbcf1f5 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class ExpressionParser:ParserPhase +{ + public List levels = []; + + public override void Process( Parser parser ) + { + ProcessExpression( parser.root ); + } + + public void ProcessExpression( ASTNode expressionParent ) + { + var parser = expressionParent.parser; + + for ( int i = 0; i < levels.Count; i++ ) + { + var changed = levels[ i ].Process( expressionParent ); + + if ( parser.hasErrors ) + { + return; + } + + if ( changed ) + { + i = -1; + } + } + } + + protected PrecedenceLevel AddPrecedenceLevel( params ExpressionOperator[] operators ) + { + var level = new PrecedenceLevel(); + level.operators.AddRange( operators ); + + var isFromRight = operators.Find( op => ! op.IsFromLeft() ) != null; + level.fromLeft = ! isFromRight; + + this.levels.Add( level ); + return level; + } +} diff --git a/Runtime/Text/Parsing/Expressions/ExpressionParser.cs.uid b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs.uid new file mode 100644 index 0000000..283bce8 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs.uid @@ -0,0 +1 @@ +uid://b21erul0athda diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs new file mode 100644 index 0000000..eb9654b --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public interface IBinaryExpression:OperatorExpression +{ + public void InitializeBinaryExpression( ASTNode left, ASTNode opNode, ASTNode right ); + public ASTNode GetLeftExpression(); + public ASTNode GetOperatorExpression(); + public ASTNode GetRightExpression(); +} + +public class BinaryExpression:ASTNode,IBinaryExpression +{ + public ASTNode left; + public ASTNode op; + public ASTNode right; + + public void InitializeBinaryExpression( ASTNode left, ASTNode op, ASTNode right ) + { + this.left = left; + this.op = op; + this.right = right; + } + + public ASTNode GetLeftExpression() + { + return left; + } + + public ASTNode GetOperatorExpression() + { + return op; + } + + public ASTNode GetRightExpression() + { + return right; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs.uid new file mode 100644 index 0000000..6811953 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs.uid @@ -0,0 +1 @@ +uid://h3v0ijwgdy5a diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs new file mode 100644 index 0000000..90a25ef --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class BinaryOperator:ExpressionOperator where T:ASTNode,IBinaryExpression, new() +{ + bool _fromLeft = false; + + public BinaryOperator( string symbol, bool fromLeft = true ) + { + startTokenPredicate = TokenPredicateData.Create( LexerMatcherLibrary.OperatorMatcher.type, symbol ); + _fromLeft = fromLeft; + } + + public override bool IsFromLeft() + { + return _fromLeft; + } + + public override bool ProcessStartNode( ASTNode parent, int startChildIndex ) + { + var leftIndex = parent.PreviousIndex( startChildIndex ); + var rightIndex = parent.NextIndex( startChildIndex ); + + if ( leftIndex < 0 || rightIndex < 0 || leftIndex >= parent.children.Count || rightIndex >= parent.children.Count ) + { + parent.parser.AddError( "Could not find left/right expressions for " + this + " in parent:" + parent + " child start: " + startChildIndex ); + return false; + } + + var leftExpression = parent.children[ leftIndex ]; + var rightExpression = parent.children[ rightIndex ]; + var op = parent.children[ startChildIndex ]; + + var binaryExpression = parent.MergeOuter( leftIndex, rightIndex ); + binaryExpression.InitializeBinaryExpression( leftExpression, op, rightExpression ); + return true; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs.uid new file mode 100644 index 0000000..a6486a1 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs.uid @@ -0,0 +1 @@ +uid://buximvl87r1m2 diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs new file mode 100644 index 0000000..b39b280 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public interface IConstantExpression:OperatorExpression +{ + public void InitializeConstantExpression( ASTNode expression ); + public ASTNode GetConstantExpression(); +} + +public class ConstantExpression:ASTNode,IConstantExpression +{ + public ASTNode constant; + + public void InitializeConstantExpression( ASTNode constant ) + { + this.constant = constant; + } + + public ASTNode GetConstantExpression() + { + return constant; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs.uid new file mode 100644 index 0000000..ed5414a --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs.uid @@ -0,0 +1 @@ +uid://caqotfege5pwp diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs new file mode 100644 index 0000000..38456d4 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class ConstantOperator:ExpressionOperator where T:ASTNode,IConstantExpression, new() +{ + public ConstantOperator( TokenPredicateData predicateData ) + { + startTokenPredicate = predicateData; + } + + public override bool ProcessStartNode( ASTNode parent, int startChildIndex ) + { + var ce = parent.children[ startChildIndex ]; + var ve = parent.MergeOuter( ce, ce ); + ve.InitializeConstantExpression( ce ); + + return true; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs.uid new file mode 100644 index 0000000..8d12ab7 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs.uid @@ -0,0 +1 @@ +uid://jfvs735hl3ld diff --git a/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs new file mode 100644 index 0000000..dc5ce79 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public abstract class ExpressionOperator +{ + public TokenPredicateData startTokenPredicate; + + public virtual bool IsFromLeft() + { + return true; + } + + public bool IsStartNode( ASTNode node ) + { + return startTokenPredicate.Matches( node ); + } + + public virtual int FindStartNodeIndex( ASTNode parent ) + { + var start = IsFromLeft() ? 0 : ( parent.children.Count - 1 ); + var end = IsFromLeft() ? parent.children.Count : -1; + + var step = IsFromLeft() ? 1 : -1; + + for ( int i = start; i != end; i += step ) + { + if ( IsStartNode( parent.children[ i ] ) ) + { + return i; + } + } + + return -1; + } + + public abstract bool ProcessStartNode( ASTNode parent, int startChildIndex ); +} diff --git a/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs.uid new file mode 100644 index 0000000..377a09d --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs.uid @@ -0,0 +1 @@ +uid://bpa5v70lmadw7 diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs new file mode 100644 index 0000000..bc9d237 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public interface IGroupExpression:OperatorExpression +{ + public void InitializeGroup( ASTNode left, ASTNode groupBody, ASTNode right ); + public ASTNode GetGroupBody(); +} + +public class GroupExpression:ASTNode,IGroupExpression +{ + public ASTNode left; + public ASTNode groupBody; + public ASTNode right; + + + public void InitializeGroup( ASTNode left, ASTNode groupBody, ASTNode right ) + { + this.left = left; + this.groupBody = groupBody; + this.right = right; + } + + public ASTNode GetGroupBody() + { + return groupBody; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs.uid new file mode 100644 index 0000000..da6b6ef --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs.uid @@ -0,0 +1 @@ +uid://dxsmj25b5f13r diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs new file mode 100644 index 0000000..a3bba34 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class GroupOperator:ExpressionOperator where T:ASTNode,IGroupExpression, new() +{ + public TokenPredicateData endTokenPredicate; + + public GroupOperator( string startSymbol, string endSymbol, string type = null ) + { + type = type ?? LexerMatcherLibrary.BracketMatcher.type; + + startTokenPredicate = TokenPredicateData.Create( type, startSymbol ); + endTokenPredicate = TokenPredicateData.Create( type, endSymbol ); + } + + public override bool ProcessStartNode( ASTNode parent, int startChildIndex ) + { + var endIndex = parent.FindBracketCloserIndex( startTokenPredicate.match, endTokenPredicate.match, startChildIndex ); + + if ( endIndex == -1 ) + { + parent.parser.AddError( "Missing end of " + this + "in parent:" + parent + " at: " + startChildIndex ); + return false; + } + + var start = parent.children[ startChildIndex ]; + var end = parent.children[ endIndex ]; + + var groupBodyExpression = parent.MergeInner( start, end ); + + var groupExpression = parent.MergeOuter( start, end ); + groupExpression.InitializeGroup( start, groupBodyExpression, end ); + + var expressionParser = parent.parser.GetExpressionParser(); + + if ( expressionParser != null ) + { + expressionParser.ProcessExpression( groupBodyExpression ); + } + + return true; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs.uid new file mode 100644 index 0000000..d5ca98a --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs.uid @@ -0,0 +1 @@ +uid://bbylgy3f16ly diff --git a/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs new file mode 100644 index 0000000..80695ce --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public interface OperatorExpression +{ + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs.uid new file mode 100644 index 0000000..4857c4a --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs.uid @@ -0,0 +1 @@ +uid://etmo2vwlenna diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs new file mode 100644 index 0000000..60d6d7b --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public interface IUnaryExpression:OperatorExpression +{ + public void InitializeUnaryExpression( ASTNode unary, ASTNode expression ); + public ASTNode GetExpression(); + public ASTNode GetOperator(); +} + +public class UnaryExpression:ASTNode,IUnaryExpression +{ + public ASTNode unaryOperator; + public ASTNode expression; + + public void InitializeUnaryExpression( ASTNode unaryOperator, ASTNode expression ) + { + this.unaryOperator = unaryOperator; + this.expression = expression; + } + + public ASTNode GetOperator() + { + return unaryOperator; + } + + public ASTNode GetExpression() + { + return expression; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs.uid new file mode 100644 index 0000000..4b4bcfb --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs.uid @@ -0,0 +1 @@ +uid://denmdwmr7fq47 diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs new file mode 100644 index 0000000..016f4f9 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class UnaryOperator:ExpressionOperator where T:ASTNode,IUnaryExpression, new() +{ + bool _fromLeft = false; + bool _isPost = false; + bool _checkForOperators = false; + + public override bool IsFromLeft() + { + return _fromLeft; + } + + public UnaryOperator( string symbol, bool fromLeft = true, bool post = false, bool checkForOperators = false ) + { + startTokenPredicate = TokenPredicateData.Create( LexerMatcherLibrary.OperatorMatcher.type, symbol ); + _fromLeft = fromLeft; + _isPost = post; + _checkForOperators = checkForOperators; + } + + public override bool ProcessStartNode( ASTNode parent, int startChildIndex ) + { + var operatorNode = parent.children[ startChildIndex ]; + var isFirstIndex = startChildIndex == 0; + var isLastIndex = startChildIndex == ( parent.children.Count - 1 ); + + if ( _isPost && isFirstIndex ) + { + parent.parser.AddError( "Missing left for " + this + "in parent:" + parent + " at child:" + startChildIndex ); + return false; + } + + if ( ! _isPost && isLastIndex ) + { + parent.parser.AddError( "Missing right " + this + "in parent:" + parent + " at child:" + startChildIndex ); + + return false; + } + + var otherNodeIndexOff = _isPost ? -1 : 1; + var otherNodeIndex = parent.IndexOffset( startChildIndex, otherNodeIndexOff ); + var expressionNode = parent.children[ otherNodeIndex ]; + + var startNode = operatorNode; + var endNode = expressionNode; + + if ( _isPost ) + { + startNode = expressionNode; + endNode = operatorNode; + } + + var uniExpression = parent.MergeOuter( startNode, endNode ); + uniExpression.InitializeUnaryExpression( operatorNode, expressionNode ); + + return true; + } + + public override int FindStartNodeIndex( ASTNode parent ) + { + if ( ! _checkForOperators ) + { + return base.FindStartNodeIndex( parent ); + } + + var start = IsFromLeft() ? 0 : ( parent.children.Count - 1 ); + var end = IsFromLeft() ? parent.children.Count : -1; + + var step = IsFromLeft() ? 1 : -1; + + for ( int i = start; i != end; i += step ) + { + if ( IsStartNode( parent.children[ i ] ) && CheckStartWithOperators( parent, i ) ) + { + return i; + } + } + + return -1; + } + + + bool CheckStartWithOperators( ASTNode parent, int index ) + { + var isStartIndex = index == 0; + + var isPre = ! _isPost; + + if ( isPre ) + { + if ( isStartIndex ) + { + return true; + } + + var nodeBefore = parent.PreviousNode( index ); // nodes[ index - 1 ]; + + if ( nodeBefore.IsToken( LexerMatcherLibrary.OperatorMatcher.type ) ) + { + return true; + } + else + { + // console.log( "node before not a operator:", nodes[ index ], ">>", nodeBefore ); + } + } + + return false; + + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs.uid new file mode 100644 index 0000000..f1365f4 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs.uid @@ -0,0 +1 @@ +uid://d3puyem33kchk diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs new file mode 100644 index 0000000..34b110b --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public interface IVariableExpression:OperatorExpression +{ + public void InitializeVariableExpression( ASTNode expression ); +} + +public class VariableExpression:ASTNode,IVariableExpression +{ + public ASTNode expression; + + public void InitializeVariableExpression( ASTNode expression ) + { + this.expression = expression; + } + + public ASTNode GetExpression() + { + return expression; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs.uid new file mode 100644 index 0000000..9b0e43e --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs.uid @@ -0,0 +1 @@ +uid://bkuyqglhvww16 diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs new file mode 100644 index 0000000..611f3b1 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class VariableOperator:ExpressionOperator where T:ASTNode,IVariableExpression, new() +{ + public VariableOperator() + { + startTokenPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type, null ); + } + + public override bool ProcessStartNode( ASTNode parent, int startChildIndex ) + { + var v = parent.children[ startChildIndex ]; + var ve = parent.MergeOuter( v, v ); + ve.InitializeVariableExpression( v ); + + return true; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs.uid new file mode 100644 index 0000000..09d9bf6 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs.uid @@ -0,0 +1 @@ +uid://b76eexwinywf7 diff --git a/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs new file mode 100644 index 0000000..f12ee00 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class PrecedenceLevel +{ + public bool fromLeft = true; + public List operators = []; + + public bool Process( ASTNode parent ) + { + SearchExpressionForOperators( parent ); + + if ( _operatorIndex == -1 ) + { + return false; + } + + var currentOperator = operators[ _operatorIndex ]; + + var changed = currentOperator.ProcessStartNode( parent, _expressionIndex ); + + if ( changed ) + { + //console.log( "Processed", className( currentOperator ), currentOperator.tokenType, currentOperator.tokenValue ); + } + + return changed; + } + + + public bool HasHigherPrecedence( int i, int e ) + { + return fromLeft ? i < e : i > e; + } + + int _expressionIndex = -1; + int _operatorIndex = -1; + + + public void SearchExpressionForOperators( ASTNode parent ) + { + _expressionIndex = fromLeft ? parent.children.Count : -1; + _operatorIndex = -1; + + for ( int i = 0; i < operators.Count; i++ ) + { + var index = operators[ i ].FindStartNodeIndex( parent ); + + if ( index == -1 ) + { + continue; + } + + if ( ! HasHigherPrecedence( index, this._expressionIndex ) ) + { + continue; + } + + _expressionIndex = index; + _operatorIndex = i; + + } + + } +} diff --git a/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs.uid b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs.uid new file mode 100644 index 0000000..fdb6fd0 --- /dev/null +++ b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs.uid @@ -0,0 +1 @@ +uid://7dusnbxqom3j diff --git a/Runtime/Text/Parsing/Parser/ASTParserPhase.cs b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs new file mode 100644 index 0000000..b54cc04 --- /dev/null +++ b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public abstract class ASTParserPhase:ParserPhase +{ + public ASTParser parserProcessor; + + public ASTParserPhase( ASTParser parserProcessor ) + { + this.parserProcessor = parserProcessor; + } + + public abstract ASTNode GetParsingRoot( Parser parser ); + + public override void Process( Parser parser ) + { + parserProcessor.root = GetParsingRoot( parser ); + parserProcessor.Process(); + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Parser/ASTParserPhase.cs.uid b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs.uid new file mode 100644 index 0000000..4130bde --- /dev/null +++ b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs.uid @@ -0,0 +1 @@ +uid://6uj7v6150kcc diff --git a/Runtime/Text/Parsing/Parser/LexerPhase.cs b/Runtime/Text/Parsing/Parser/LexerPhase.cs new file mode 100644 index 0000000..317c138 --- /dev/null +++ b/Runtime/Text/Parsing/Parser/LexerPhase.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class LexerPhase:ParserPhase +{ + public LexerPhase( Lexer lexer ) + { + this.lexer = lexer; + } + public Lexer lexer; + + public bool outputDebugInfo = false; + + public override void Process( Parser parser ) + { + parser.lexerEvents = lexer.LexToList( parser.source ); + + if ( lexer.hasError ) + { + hasStopError = true; + return; + } + + parser.lexerEvents.Pop(); + + lexer.GrabMatches( parser.lexerEvents, parser.source ); + + var root = parser.root; + + parser.root.children.AddRange( parser.lexerEvents.Map( le => Token.Create( le, root ) ) ); + + if ( outputDebugInfo ) + { + var index = 0; + + RJLog.Log( "Lexer Info:", "\n" + + parser.lexerEvents.Map( le => "["+ ( index++ ) + "] '" + ( le.type == "Break" ? "\\n" : le.match ) + "' : " + le.type + " ("+ le.offset +")" ).Join( "\n" ) + ); + } + + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Parser/LexerPhase.cs.uid b/Runtime/Text/Parsing/Parser/LexerPhase.cs.uid new file mode 100644 index 0000000..410324c --- /dev/null +++ b/Runtime/Text/Parsing/Parser/LexerPhase.cs.uid @@ -0,0 +1 @@ +uid://q6mj5ke2y7h7 diff --git a/Runtime/Text/Parsing/Parser/Parser.cs b/Runtime/Text/Parsing/Parser/Parser.cs new file mode 100644 index 0000000..95f19b3 --- /dev/null +++ b/Runtime/Text/Parsing/Parser/Parser.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public abstract class Parser +{ + public string source; + public List lexerEvents = []; + public ASTNode root; + public List phases = []; + public List messages = []; + + + + public ParserPhase stoppedParsingPhase = null; + + public virtual ExpressionParser GetExpressionParser() + { + return null; + } + + public void Parse( string source ) + { + this.source = source; + + foreach ( var p in phases ) + { + p.Process( this ); + + if ( p.hasStopError ) + { + stoppedParsingPhase = p; + return; + } + } + } + + bool _hasErrors = false; + public bool hasErrors => _hasErrors; + + public void AddError( string message, params TextSelection[] textSelections ) + { + AddMessage( MessageType.Error, message, textSelections ); + } + + public void AddMessage( MessageType type, string message, params TextSelection[] textSelections ) + { + var pm = new ParserMessage(); + pm.message = Message.Create( type, message ); + + if ( textSelections != null && textSelections.Length > 0 ) + { + pm.selections.AddRange( textSelections ); + } + + messages.Add( pm ); + + if ( type == MessageType.Error ) + { + _hasErrors = true; + } + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Parser/Parser.cs.uid b/Runtime/Text/Parsing/Parser/Parser.cs.uid new file mode 100644 index 0000000..697bc5d --- /dev/null +++ b/Runtime/Text/Parsing/Parser/Parser.cs.uid @@ -0,0 +1 @@ +uid://7j0igvrgv6jp diff --git a/Runtime/Text/Parsing/Parser/ParserMessage.cs b/Runtime/Text/Parsing/Parser/ParserMessage.cs new file mode 100644 index 0000000..b5c69df --- /dev/null +++ b/Runtime/Text/Parsing/Parser/ParserMessage.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class ParserMessage +{ + public Message message; + public List selections = []; + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Parser/ParserMessage.cs.uid b/Runtime/Text/Parsing/Parser/ParserMessage.cs.uid new file mode 100644 index 0000000..23c412a --- /dev/null +++ b/Runtime/Text/Parsing/Parser/ParserMessage.cs.uid @@ -0,0 +1 @@ +uid://dci6pck0rxfu5 diff --git a/Runtime/Text/Parsing/Parser/ParserPhase.cs b/Runtime/Text/Parsing/Parser/ParserPhase.cs new file mode 100644 index 0000000..6ab4f42 --- /dev/null +++ b/Runtime/Text/Parsing/Parser/ParserPhase.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public abstract class ParserPhase +{ + public abstract void Process( Parser parser ); + public bool hasStopError = false; +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/Parser/ParserPhase.cs.uid b/Runtime/Text/Parsing/Parser/ParserPhase.cs.uid new file mode 100644 index 0000000..ff27537 --- /dev/null +++ b/Runtime/Text/Parsing/Parser/ParserPhase.cs.uid @@ -0,0 +1 @@ +uid://c663techcgo6w diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs new file mode 100644 index 0000000..96ab705 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSParser:Parser +{ + public LexerPhase lexerPhase = new LexerPhase( new CSLexer() ); + public CSPreProcessor preProcessor = new CSPreProcessor(); + public CSRootFileParser rootPhase = new CSRootFileParser(); + + public CSParser( string filePath, HashSet defines = null ) + { + root = CSFileRoot.Create( filePath, this ); + + phases = + [ + lexerPhase, + preProcessor, + rootPhase + ]; + + rootPhase.preProcessorContext.defines = defines ?? new HashSet(); + + Parse( FilesSync.LoadUTF8( filePath ) ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs.uid new file mode 100644 index 0000000..d4f968e --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs.uid @@ -0,0 +1 @@ +uid://ckn0wj4udiupw diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs new file mode 100644 index 0000000..a0e560f --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs @@ -0,0 +1,91 @@ +using System.Collections.Generic; +using Godot; + +namespace Rokojori; + +[Tool,GlobalClass] +public partial class CSParserTest:Node +{ + [Export] + public string defines = "a,b,c"; + + [Export] + public string formula = ""; + [ExportToolButton( "Parse Formula" )] + public Callable parseFormulaButton => Callable.From( + ()=> + { + ParseFormula(); + } + ); + + [Export( PropertyHint.File )] + public string path; + + [Export] + public bool createGD = false; + + + + [ExportToolButton( "Parse" )] + public Callable parseButton => Callable.From( + ()=> + { + Parse(); + } + ); + + void Parse() + { + var defines = new HashSet(); + defines.Add( GDScriptGenerator.GD_SCRIPT_TRANSPILING ); + + var parser = new CSParser( ProjectSettings.GlobalizePath( path ), defines ); + + var root = parser.root as CSFileRoot; + + this.LogInfo( "Parsed Nodes:", root.parsedNodes.Count ); + + + for ( int i = 0; i < root.parsedNodes.Count; i++ ) + { + this.LogInfo( i, root.parsedNodes[ i ] ); + } + + if ( createGD ) + { + CreateGDClass( root ); + } + } + + void CreateGDClass( CSFileRoot root ) + { + var originalPath = FilePath.Absolute( root.GetFilePath() ); + + var converter = new GDScriptFromCSAST(); + converter.Convert( root ); + var gdclass = converter.gdClass; + + var gdgenerator = new GDScriptGenerator(); + gdgenerator.gdClasses = [ gdclass ]; + gdgenerator.Generate( originalPath.parentAbsolutePath ); + + } + + void ParseFormula() + { + var defines = this.defines.Split( "," ); + var evaluator = new CSPreProcessorConditionalEvaluator(); + defines.ForEach( d => evaluator.defines.Add( d ) ); + evaluator.Parse( formula ); + + var result = evaluator.Evaluate(); + + this.LogInfo( "Result:", result ); + + this.LogInfo( "Context:", evaluator.context.messages ); + + var info = evaluator.root.CreateDebugTreeInfo(); + this.LogInfo( "\n" + info ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs.uid new file mode 100644 index 0000000..296b402 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs.uid @@ -0,0 +1 @@ +uid://btbsqwh2k3ocl diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs new file mode 100644 index 0000000..8535a8e --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSFileRoot:ASTNode, ASTFileRoot +{ + public string filePath; + CSParser _parser; + public CSParser parser => _parser; + public Parser GetParser() + { + return _parser; + } + + public string GetFilePath() + { + return filePath; + } + + public string GetSource() + { + return _parser.source; + } + + TextLinesMapper _textLinesMapper = null; + + public TextLinesMapper GetTextLinesMapper() + { + if ( _textLinesMapper == null ) + { + _textLinesMapper = new TextLinesMapper(); + _textLinesMapper.Map( GetSource() ); + } + + return _textLinesMapper; + } + + + + public static CSFileRoot Create( string path, CSParser parser ) + { + var root = new CSFileRoot(); + root.filePath = path; + root._parser = parser; + return root; + } + + public List parsedNodes = new List(); + + public List imports = []; + public CSNamespaceDeclaration namespaceDeclaration; + public List allMemberDeclarations = []; + public List blocks = []; + public List objectDefinitions = []; + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs.uid new file mode 100644 index 0000000..6dfb829 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs.uid @@ -0,0 +1 @@ +uid://dqq08jh3q0tx5 diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs new file mode 100644 index 0000000..e0c8093 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class CSImportDeclaration: ASTNode, ImportDeclaration +{ + public Token usingToken; + public List importPath; + public Token end; + + public string GetImportPath() + { + return importPath.Map( tk => tk.match ).Join( "" ); + } + + public override string ToString() + { + return GetType().Name + "{ using " + GetImportPath()+ "; } "; + } + + public static ASTMatcherResolver Resolver() + { + var usingMR = new ASTMatcherResolver(); + + var sequenceMatcher = TokenRepeatSequenceASTMatcher.CreateWithLexer( new CSLexer(), + "using cword",".cword",";" + ); + + usingMR.matcher = sequenceMatcher; + + usingMR.initializer = ( imp, matcher ) => + { + var usingIndex = imp.FindTokenIndex( LexerMatcherLibrary.UsingMatcher ); + var endIndex = imp.ReverseFindTokenIndex( LexerMatcherLibrary.OperatorMatcher ); + + RJLog.Log( "Endindex:", endIndex ); + imp.usingToken = imp.children[ usingIndex ] as Token; + imp.end = imp.children[ endIndex ] as Token; + + var inbetween = imp.children.Sub( usingIndex + 1, endIndex - usingIndex - 1 ); + imp.importPath = inbetween.Filter( n => ! n.IsIgnoreToken() ).Map( n => n as Token ); + + RJLog.Log( + "INIT IMPORT:", imp.usingToken, ">>", inbetween.Join( ", " ), ">>", imp.end, + imp.children.Last(), + "path only:",imp.importPath.Join( "|| ") ); + + var root = imp.GetParentWithType(); + + if ( root == null ) + { + return imp.childIndex; + } + + root.parsedNodes.Add( imp ); + root.imports.Add( imp ); + + return imp.childIndex; + }; + + return usingMR; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs.uid new file mode 100644 index 0000000..a81b5f8 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bhawdwu83nael diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs new file mode 100644 index 0000000..cbbf2de --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSNamespaceBlock: ASTNode, NamespaceBlock +{ + public Token namespaceToken; + public List namespacePath; + public Token blockStart; + public Token blockEnd; + + public string GetNamespace() + { + return namespacePath.Map( tk => tk.match ).Join( "" ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs.uid new file mode 100644 index 0000000..d404374 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs.uid @@ -0,0 +1 @@ +uid://dngeubh7s682t diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs new file mode 100644 index 0000000..9d0e81b --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSNamespaceDeclaration: ASTNode, NamespaceDeclaration +{ + public Token namespaceToken; + public List namespacePath; + public Token end; + + public string GetNamespace() + { + return namespacePath.Map( tk => tk.match ).Join( "" ); + } + + public override string ToString() + { + return GetType().Name + "{ namespace " + GetNamespace()+ "; } "; + } + + public static ASTMatcherResolver Resolver() + { + var namespaceMR = new ASTMatcherResolver(); + + var sequenceMatcher = TokenRepeatSequenceASTMatcher.CreateWithLexer( new CSLexer(), + "namespace cword",".cword",";" + ); + + namespaceMR.matcher = sequenceMatcher; + + namespaceMR.initializer = ( nsd, matcher ) => + { + var nsIndex = nsd.FindTokenIndex( LexerMatcherLibrary.NamespaceMatcher ); + var endIndex = nsd.ReverseFindTokenIndex( LexerMatcherLibrary.OperatorMatcher ); + + RJLog.Log( "Endindex:", endIndex ); + nsd.namespaceToken = nsd.children[ nsIndex ] as Token; + nsd.end = nsd.children[ endIndex ] as Token; + + var inbetween = nsd.children.Sub( nsIndex + 1, endIndex - nsIndex - 1 ); + nsd.namespacePath = inbetween.Filter( n => ! n.IsIgnoreToken() ).Map( n => n as Token ); + + RJLog.Log( + "INIT IMPORT:", nsd.namespaceToken, ">>", inbetween.Join( ", " ), ">>", nsd.end, + nsd.children.Last(), + "path only:",nsd.namespacePath.Join( "|| ") ); + + var root = nsd.GetParentWithType(); + + if ( root == null ) + { + return nsd.childIndex; + } + + root.parsedNodes.Add( nsd ); + root.namespaceDeclaration = nsd; + + return nsd.childIndex; + }; + + return namespaceMR; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs.uid new file mode 100644 index 0000000..b52ff0f --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs.uid @@ -0,0 +1 @@ +uid://c5j8xld75nofs diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs new file mode 100644 index 0000000..3feb2cd --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSTypeDefinition: ASTNode +{ + public string GetTypeDefinition() + { + return CombinedMatch().Trim(); + } + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs.uid new file mode 100644 index 0000000..aae00f5 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs.uid @@ -0,0 +1 @@ +uid://brtto8fv57gml diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs new file mode 100644 index 0000000..b24844d --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSEnumValueDeclaration: ASTNode, EnumDeclaration +{ + public Token parameterName; + public ASTNode parameterValue; + + public void Resolve() + { + var assignmentToken = FindToken( TokenPredicateData.Lexed( new CSLexer(), "=" ) ); + + if ( assignmentToken != null ) + { + var start = assignmentToken.childIndex + 1; + var length = ( children.Count - 1 ) - start; + parameterValue = MergeChildrenWith( start, length ); + } + + + var last = assignmentToken == null ? children.Last() : PreviousNode( assignmentToken.childIndex ); + + if ( ! last.IsToken( LexerMatcherLibrary.CwordMatcher ) ) + { + last = PreviousNode( last.childIndex ); + } + + parameterName = last as Token; + + } + + + public string GetEnumName() + { + return parameterName.match; + } + + public string GetEnumValue() + { + return parameterValue?.CombinedMatch().Trim(); + } + + public override string ToString() + { + return GetType().Name + " " + GetEnumName() + " ( ''" + parameterName.lineInfo + "'' ) "; + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs.uid new file mode 100644 index 0000000..ccc2e02 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs.uid @@ -0,0 +1 @@ +uid://7jnddwcp20jd diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs new file mode 100644 index 0000000..77e7a6a --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSFieldDeclaration: CSMemberDeclaration +{ + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs.uid new file mode 100644 index 0000000..3544921 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs.uid @@ -0,0 +1 @@ +uid://00vegm6r68g8 diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs new file mode 100644 index 0000000..71cd34e --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public abstract class CSMemberDeclaration: ASTNode, MemberDeclaration +{ + public List attributeBrackets; + public List modifiers; + public Token memberName; + public CSTypeDefinition memberType; + + public List GetMemberModifiers() + { + return new List(); + } + + public string GetMemberName() + { + return memberName.match; + } + + public string GetMemberType() + { + if ( this is CSMethodMemberDeclaration mm && mm.isContructor ) + { + return GetMemberName(); + } + + return memberType == null ? "void" : memberType.GetTypeDefinition(); + } + + public override string ToString() + { + return GetType().Name + " " + GetMemberType() + " " + GetMemberName() + " ( ''" + memberName.lineInfo + "'' ) "; + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs.uid new file mode 100644 index 0000000..f4955cd --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bi4sl13ggdb7d diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs new file mode 100644 index 0000000..45c2fb1 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSMethodMemberDeclaration: CSMemberDeclaration +{ + public bool isContructor = false; + public Token parametersStart; + public ASTNode parametersContent; + public Token parametersEnd; + + public Token blockStart; + public ASTNode blockContent; + public Token blockEnd; + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs.uid new file mode 100644 index 0000000..d675a6f --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bf4bnrj5kdugb diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs new file mode 100644 index 0000000..98cf9ef --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSParameterDeclaration: ASTNode, ParameterDeclaration +{ + public Token parameterName; + public CSTypeDefinition parameterType; + public ASTNode parameterValue; + + public void ResolveNameAndType() + { + var assignmentToken = FindToken( TokenPredicateData.Lexed( new CSLexer(), "=" ) ); + + if ( assignmentToken != null ) + { + var start = assignmentToken.childIndex + 1; + var length = ( children.Count - 1 ) - start; + parameterValue = MergeChildrenWith( start, length ); + } + + + var last = assignmentToken == null ? children.Last() : PreviousNode( assignmentToken.childIndex ); + + if ( ! last.IsToken( LexerMatcherLibrary.CwordMatcher ) ) + { + last = PreviousNode( last.childIndex ); + } + + // RJLog.Log( "parameterName:", last, children.Count, children.Map( c => "'" + c.CombinedMatch() + "'" ).Join( " " )); + + parameterName = last as Token; + + // RJLog.Log( "Creating type:", 0, parameterName.childIndex - 1 ); + parameterType = MergeOuter( 0, parameterName.childIndex - 1 ); + } + + + public string GetParameterName() + { + return parameterName.match; + } + + public string GetParameterType() + { + return parameterType.GetTypeDefinition(); + } + + public string GetParameterValue() + { + return parameterValue?.CombinedMatch().Trim(); + } + + + public override string ToString() + { + return GetType().Name + " " + GetParameterType() + " " + GetParameterName() + " ( ''" + parameterName.lineInfo + "'' ) "; + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs.uid new file mode 100644 index 0000000..82f79e6 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs.uid @@ -0,0 +1 @@ +uid://cuw23g0pnu3md diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs new file mode 100644 index 0000000..c79a1f4 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSPropertyDeclaration: CSMemberDeclaration +{ + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs.uid new file mode 100644 index 0000000..a91b589 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs.uid @@ -0,0 +1 @@ +uid://cnomgidksu0i8 diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs new file mode 100644 index 0000000..19c2b35 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSClassDeclaration: CSObjectDeclaration, ClassDeclaration +{ + public string GetClassName() + { + return objectName.match; + } + + public static ASTMatcherResolver Resolver() + { + return Resolver( "class" ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs.uid new file mode 100644 index 0000000..e362a0b --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs.uid @@ -0,0 +1 @@ +uid://c4gua113a0b3a diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs new file mode 100644 index 0000000..6f4da9b --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSEnumDeclaration: CSObjectDeclaration, EnumDeclaration +{ + public string GetEnumName() + { + return objectName.match; + } + + public static ASTMatcherResolver Resolver() + { + return Resolver( "enum" ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs.uid new file mode 100644 index 0000000..fe2ea3a --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs.uid @@ -0,0 +1 @@ +uid://b1wp4j3s7wxip diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs new file mode 100644 index 0000000..7af53d9 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSInterfaceDeclaration: CSObjectDeclaration, InterfaceDeclaration +{ + public string GetInterfaceName() + { + return objectName.match; + } + + public static ASTMatcherResolver Resolver() + { + return Resolver( "interface" ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs.uid new file mode 100644 index 0000000..2727499 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs.uid @@ -0,0 +1 @@ +uid://bjr3hv63luv34 diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs new file mode 100644 index 0000000..5426afd --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs @@ -0,0 +1,170 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public abstract class CSObjectDeclaration: ASTNode +{ + public List attributeBrackets = []; + public List modifiers = []; + public Token objectType; + public Token objectName; + + public CSObjectDeclarationTail objectTail; + + public Token blockStart; + public ASTNode objectBody; + public Token blockEnd; + + public override string ToString() + { + var modsInfo = ""; + + if ( modifiers.Count > 0 ) + { + modsInfo = modifiers.Map( m => m.match ).Join( " " ) + " "; + } + + List atts = []; + + for ( int i = 0; i < attributeBrackets.Count; i+= 2 ) + { + var attRange = GrabTokenRange( attributeBrackets[ i ], attributeBrackets[ i + 1 ], false ); + + if ( attRange == null ) + { + continue; + } + + atts.Add( attRange.Map( a => a.match ).Join( "" ) ); + } + + var attsInfo = ""; + + if ( atts.Count > 0 ) + { + attsInfo = atts.Join( " " ) + " "; + + } + + return GetType().Name + "{ " + attsInfo + modsInfo + objectType.match + " " + objectName.match + " {...} } "; + } + + protected static ASTMatcherResolver Resolver( string objectDeclartion ) where T:CSObjectDeclaration,new() + { + var lexer = new CSLexer(); + var objectMR = new ASTMatcherResolver(); + + var odPredicate = TokenPredicateData.Lexed( lexer, objectDeclartion ); + var objectMatcher = new TokenWordASTMatcher(); + objectMatcher.type = odPredicate.type; + objectMatcher.match = odPredicate.match; + + var blockMatcher = new BracketBlockMatcher(); + blockMatcher.blockStart = TokenPredicateData.Lexed( lexer, "{" ); + blockMatcher.blockEnd = TokenPredicateData.Lexed( lexer, "}" ); + blockMatcher.matchingAtStartIsMandatory = false; + + var combinedMatcher = new CombinedASTMatcher(); + combinedMatcher.matchers = [ objectMatcher, blockMatcher ]; + + objectMR.matcher = combinedMatcher; + + objectMR.initializer = ( t, matcher ) => + { + var parent = t.parent; + var parentIndex = parent.children.IndexOf( t ); + + // for ( int i = 0; i < parent.children.Count; i++ ) + // { + // RJLog.Log( i, parent.children[ i ].CombinedMatch(), parent.children[ i ].parent?.GetType().Name ); + // } + + var ma = CSModifierAttributesParser.ParseReverse( parent, parentIndex ); + + if ( ma.modifiers.Count > 0 ) + { + t.modifiers = ma.modifiers; + } + + if ( ma.attributeBrackets.Count > 0 ) + { + t.attributeBrackets = ma.attributeBrackets; + } + + if ( t.modifiers.Count > 0 || t.attributeBrackets.Count > 0 ) + { + if ( t.attributeBrackets.Count > 0 ) + { + // RJLog.Log( + // "Has Same parent:", t.parent == t.attributeBrackets[ 0 ], + // "Parent", t.parent?.GetType().Name, + // "Atts Type:", t.attributeBrackets[ 0 ].GetType().Name, + // "Atts Match:", t.attributeBrackets[ 0 ].CombinedMatch(), + // "Atts Parent", t.attributeBrackets[ 0 ].parent?.GetType().Name + // ); + + t.ExpandToPrevious( t.attributeBrackets[ 0 ] ); + } + else + { + t.ExpandToPrevious( t.modifiers[ 0 ] ); + } + } + + t.objectType = t.FindToken( odPredicate ); + t.objectName = t.FindToken( LexerMatcherLibrary.CwordMatcher, t.children.IndexOf( t.objectType ) + 1 ); + + + + t.blockEnd = t.ReverseFindToken( TokenPredicateData.Lexed( lexer, "}" ) ); + t.blockStart = t.ReverseFindBracketOpener( "{", "}", t.blockEnd.childIndex ); + + var afterName = t.NextNode( t.objectName.childIndex ); + + if ( afterName != t.blockStart ) + { + t.objectTail = t.MergeInner( t.objectName, t.blockStart ); + t.objectTail.Resolve(); + + } + + // RJLog.Log( "BLOCK:", t.blockStart, t.blockEnd ); + t.objectBody = t.MergeInner( t.blockStart, t.blockEnd ); + + + + // t.blockStart = t.FindToken( blockMatcher.blockStart, t.children.IndexOf( t.objectName ) + 1 ); + // t.blockEnd = t.ReverseFindToken( blockMatcher.blockEnd ); + + var root = t.GetParentWithType(); + + if ( root == null ) + { + return t.childIndex; + } + + if ( typeof( T ) == typeof( CSEnumDeclaration ) ) + { + t.objectBody.CreateSeperatedList( ",", + e => + { + e.Resolve(); + } + ); + } + else + { + var objectParser = new CSObjectParser( t.objectBody ); + objectParser.Process( root.parser ); + } + + + root.parsedNodes.Add( t ); + root.objectDefinitions.Add( t ); + + return t.childIndex; + }; + + return objectMR; + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs.uid new file mode 100644 index 0000000..a8602e0 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs.uid @@ -0,0 +1 @@ +uid://dng66k350e8pr diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs new file mode 100644 index 0000000..a2c265e --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSObjectDeclarationTail: ASTNode +{ + public ASTNodeList genericsDeclaration; + public ASTNodeList inheritanceDeclaration; + + + public void Resolve() + { + var genericsStart = FindToken( TokenPredicateData.Lexed( new CSLexer(), "<" ) ); + var colon = FindToken( TokenPredicateData.Lexed( new CSLexer(), ":" ) ); + + if ( genericsStart != null ) + { + var length = colon == null ? children.Count : colon.childIndex; + genericsDeclaration = MergeChildrenWith( 0, length ); + } + + if ( colon != null ) + { + var start = colon.childIndex + 1; + var length = ( children.Count - 1 ) - start; + inheritanceDeclaration = MergeChildrenWith( start, length ); + } + } + + public string GetExtendingObject() + { + return inheritanceDeclaration.FindToken( LexerMatcherLibrary.CwordMatcher ).match; + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs.uid new file mode 100644 index 0000000..82fa879 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs.uid @@ -0,0 +1 @@ +uid://b05a10eey26lx diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs new file mode 100644 index 0000000..04cf4ca --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSObjectDependency +{ + public string name; + public List genericParameters; + public string ns; +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs.uid new file mode 100644 index 0000000..7e0cced --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs.uid @@ -0,0 +1 @@ +uid://dsip8ijfdo6hv diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs new file mode 100644 index 0000000..416cfeb --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSStructDeclaration: CSObjectDeclaration +{ + public string GetStructName() + { + return objectName.match; + } + + public static ASTMatcherResolver Resolver() + { + return Resolver( "struct" ); + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs.uid new file mode 100644 index 0000000..c80ba6d --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs.uid @@ -0,0 +1 @@ +uid://byuxdfq3chm4h diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs new file mode 100644 index 0000000..14ee2c7 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Rokojori; + + +public class SquareBlock:ASTNode +{ + public Token GetSquareStart() + { + return FindToken( LexerMatcherLibrary.BracketMatcher, "[" ); + } + + public Token GetSquareEnd() + { + return ReverseFindToken( TokenPredicateData.Create( LexerMatcherLibrary.BracketMatcher.type, "]" ) ); + } + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs.uid new file mode 100644 index 0000000..fe950ec --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs.uid @@ -0,0 +1 @@ +uid://cw4ghe8ficgwj diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs new file mode 100644 index 0000000..8bd00c3 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs @@ -0,0 +1,317 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSMemberResolver:ASTMatcherResolver +{ + public CSMemberResolver() + { + Initialize(); + } + + void Initialize() + { + var csLexer = new CSLexer(); + var triggerMatcher = new MultiTriggerASTMatcher(); + triggerMatcher.triggerPredicates = + [ + TokenPredicateData.Lexed( csLexer, "(" ), + TokenPredicateData.Lexed( csLexer, "{" ), + TokenPredicateData.Lexed( csLexer, "=>" ), + TokenPredicateData.Lexed( csLexer, "=" ), + TokenPredicateData.Lexed( csLexer, ";" ), + ]; + + triggerMatcher.blockPredicates = + [ + TokenPredicateData.Lexed( csLexer, "[" ), + TokenPredicateData.Lexed( csLexer, "]" ), + TokenPredicateData.Lexed( csLexer, "<" ), + TokenPredicateData.Lexed( csLexer, ">" ) + ]; + + triggerMatcher.matchSticky = true; + + matcher = triggerMatcher; + + } + + public override int Resolve( ASTMatchResult result, ASTMatcher matcher ) + { + var mc = ResolveDeclaration( result, matcher ); + + if ( mc == null ) + { + return -1; + } + + + var parent = result.parent; + + var memberStartIndex = FindMemberDefinitionStart( parent, mc.childIndex ); + + // RJLog.Log( "Found member:", mc.memberName, "start:", memberStartIndex, "name:", mc.childIndex ); + var atts = CSModifierAttributesParser.ParseForward( parent, memberStartIndex - 1 ); + + var isConstructor = IsConstructorMethod( parent, mc ); + + ASTNode earliestNode = null; + + if ( atts.attributeBrackets != null && atts.attributeBrackets.Count > 0 ) + { + earliestNode = atts.attributeBrackets[ 0 ]; + mc.attributeBrackets = atts.attributeBrackets; + } + + if ( atts.modifiers != null && atts.modifiers.Count > 0 ) + { + if ( earliestNode == null ) + { + earliestNode = atts.modifiers[ 0 ]; + } + + mc.modifiers = atts.modifiers; + } + + if ( ! isConstructor ) + { + var typeFirstIndex = atts.nextNode.childIndex; + var typeLastIndex = parent.PreviousIndex( mc.childIndex ); + var memberType = parent.MergeOuter( typeFirstIndex, typeLastIndex ); + mc.memberType = memberType; + + if ( earliestNode == null ) + { + earliestNode = memberType; + } + } + else + { + var mm = mc as CSMethodMemberDeclaration; + mm.isContructor = true; + } + + mc.ExpandToPrevious( earliestNode ); + + RJLog.Log( "Found member", mc.memberType?.GetTypeDefinition() ?? "(constructor)" , mc.memberName ); + + AddToRoot( mc ); + + return mc.childIndex; + + } + + bool IsConstructorMethod( ASTNode parent, CSMemberDeclaration md ) + { + if ( ! ( md is CSMethodMemberDeclaration ) ) + { + return false; + } + + var objectRoot = parent.walker.GetParentWithType( parent ) as CSObjectDeclaration; + + if ( objectRoot == null ) + { + return false; + } + + var me = md as CSMethodMemberDeclaration; + + return me.GetMemberName() == objectRoot.objectName.match; + + } + + + public CSMemberDeclaration ResolveDeclaration( ASTMatchResult result, ASTMatcher matcher ) + { + var token = result.resultStartToken; + + if ( token.match == "(" ) + { + return ResolveMethod( result, matcher ); + } + + if ( token.match == "{" ) + { + return ResolveProperty( result, matcher ); + } + + if ( token.match == "=" ) + { + return ResolveFieldOrProperty( result, matcher ); + } + + if ( token.match == "=>" ) + { + return ResolveFieldOrProperty( result, matcher ); + } + + if ( token.match == ";" ) + { + return ResolveField( result, matcher ); + } + + return null; + } + + + void AddToRoot( CSMemberDeclaration md ) + { + var root = md.GetParentWithType(); + + if ( root == null ) + { + return; + } + + root.parsedNodes.Add( md ); + root.allMemberDeclarations.Add( md ); + } + + int FindMemberDefinitionStart( ASTNode parent, int memberDeclarationIndex ) + { + for ( int i = memberDeclarationIndex - 1; i >= 0; i-- ) + { + var child = parent.children[ i ]; + + if ( child is CSMemberDeclaration || child is CSObjectDeclaration ) + { + return i + 1; + } + } + + return 0; + } + + CSMethodMemberDeclaration ResolveMethod( ASTMatchResult result, ASTMatcher matcher ) + { + var parent = result.parent; + var parametersStart = result.resultStartToken; + + var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CFunctionMatcher.type ); + var startReverseOffsetIndex = parametersStart.reverseIndexOffset; + + var name = parent.ReverseFindToken( cwordPredicate, startReverseOffsetIndex ); + + + var parametersEnd = parent.FindBracketCloser( "(", ")", result.resultStart ); + + + + var blockStart = parent.FindToken( TokenPredicateData.Lexed( new CSLexer(), "{" ), parametersEnd.childIndex ); + + + var blockEnd = parent.FindBracketCloser( "{", "}", blockStart.childIndex ); + + var memberDeclaration = parent.MergeOuter( name, blockEnd ); + memberDeclaration.parametersStart = parametersStart; + memberDeclaration.parametersEnd = parametersEnd; + + var hasParameterTokens = memberDeclaration.NextNode( parametersStart.childIndex ) != parametersEnd; + + if ( hasParameterTokens ) + { + var parametersContent = memberDeclaration.MergeInner( parametersStart, parametersEnd ); + // RJLog.Log( "Parameters:", parametersContent.CombinedMatch() ); + + var info = new List(); + parametersContent.CreateSeperatedList( ",", + p => + { + p.ResolveNameAndType(); + info.Add( p.GetParameterName() + ": " + p.GetParameterType() ); + } + ); + + RJLog.Log( "[ Parameters for " + name.match + "() ]", info.Join( ", " ) ); + + + + + memberDeclaration.parametersContent = parametersContent; + } + else + { + RJLog.Log( "[ No parameters:", name.match + "() ]" ); + } + memberDeclaration.memberName = name; + + return memberDeclaration; + } + + + + CSPropertyDeclaration ResolveProperty( ASTMatchResult result, ASTMatcher matcher ) + { + var parent = result.parent; + var blockStart = result.resultStartToken; + + var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type ); + var name = parent.ReverseFindToken( cwordPredicate, blockStart.reverseIndexOffset ); + var blockEnd = parent.FindBracketCloser( "{", "}", blockStart.childIndex ); + + var memberDeclaration = parent.MergeOuter( name, blockEnd ); + memberDeclaration.memberName = name; + + return memberDeclaration; + } + + CSMemberDeclaration ResolveFieldOrProperty( ASTMatchResult result, ASTMatcher matcher ) + { + var csLexer = new CSLexer(); + + var parent = result.parent; + var assigner = result.resultStartToken; + + var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type ); + var name = parent.ReverseFindToken( cwordPredicate, assigner.reverseIndexOffset ); + var end = parent.FindTriggerToken( + assigner.childIndex, + [ TokenPredicateData.Lexed( csLexer, ";" ) ], + [ + TokenPredicateData.Lexed( csLexer, "(" ), + TokenPredicateData.Lexed( csLexer, ")" ), + TokenPredicateData.Lexed( csLexer, "{" ), + TokenPredicateData.Lexed( csLexer, "}" ), + + TokenPredicateData.Lexed( csLexer, "[" ), + TokenPredicateData.Lexed( csLexer, "]" ), + TokenPredicateData.Lexed( csLexer, "<" ), + TokenPredicateData.Lexed( csLexer, ">" ) + ] + ); + + var isField = assigner.match == "="; + + CSMemberDeclaration memberDeclaration; + + if ( isField ) + { + memberDeclaration = parent.MergeOuter( name, end ); + } + else + { + memberDeclaration = parent.MergeOuter( name, end ); + } + + memberDeclaration.memberName = name; + + return memberDeclaration; + } + + CSFieldDeclaration ResolveField( ASTMatchResult result, ASTMatcher matcher ) + { + var parent = result.parent; + var closer = result.resultStartToken; + + var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type ); + var closerReverseOffsetIndex = closer.reverseIndexOffset; + var name = parent.ReverseFindToken( cwordPredicate, closerReverseOffsetIndex ); + var end = closer; + + var memberDeclaration = parent.MergeOuter( name, end ); + memberDeclaration.memberName = name; + return memberDeclaration; + + } +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs.uid new file mode 100644 index 0000000..96b53b7 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs.uid @@ -0,0 +1 @@ +uid://cxgnt4inbrsd2 diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs new file mode 100644 index 0000000..6be3562 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; +using System.Text; + +namespace Rokojori; + + +public class CSModifierAttributesParser +{ + public static bool IsExported( List attPairs ) + { + return HasAttribute( "Export", attPairs ); + } + + public static bool HasAttribute( string name, List attPairs ) + { + if ( attPairs == null ) + { + return false; + } + + var atts = GetAttributes( attPairs ); + + return atts.IndexOf( name ) != -1; + } + + public static List GetAttributes( List attPairs ) + { + var atts = new List(); + + if ( attPairs == null ) + { + return atts; + } + + for ( int i = 0; i < attPairs.Count; i+= 2 ) + { + var s = attPairs[ i ]; + var e = attPairs[ i + 1 ]; + + var parent = s.parent; + + var tokens = parent.children.Range( s.childIndex + 1, e.childIndex - 1 ); + + // var att = tokens.Map( t => t.CombinedMatch() ).Join( "" ).Trim(); + // atts.Add( att ); + + var buffer = new ASTNodeList(); + buffer.children = tokens; + buffer.children.ForEach( c => c.parent = buffer ); + + buffer.CreateSeperatedList( "," , + ( n )=> + { + var att = n.CombinedMatch().Trim(); + atts.Add( att ); + // atts.Add( n.CombinedMatch().Trim() ); + } + ); + + tokens.ForEach( c => c.parent = parent ); + } + + return atts; + + } + + public class Data + { + public List attributeBrackets = []; + public List modifiers = []; + public ASTNode nextNode; + + public string GetAttributeValue( Token start, Token end ) + { + if ( start == null || end == null ) + { + return "Invalid: start == null: " + ( start == null ) + " end == null: " + ( end == null ); + } + + if ( start == end ) + { + return start.CombinedMatch(); + } + + var startIndex = start.childIndex; + var endIndex = end.childIndex; + + var sb = new StringBuilder(); + + sb.Append( "[" ); + + for ( int i = startIndex + 1; i < endIndex; i++ ) + { + + sb.Append( start.parent.children[ i ].CombinedMatch() ); + } + + sb.Append( "]" ); + + + return sb.ToString(); + } + + public string GetStringInfo() + { + var sb = new StringBuilder(); + + for ( int i = 0; i < attributeBrackets.Count; i+=2 ) + { + sb.Append( GetAttributeValue( attributeBrackets[ i ], attributeBrackets[ i + 1 ] ) ); + } + + modifiers.ForEach( + m => + { + sb.Append( " " ); + sb.Append( m.CombinedMatch() ); + } + ); + + return sb.ToString(); + } + } + + public static Data ParseReverse( ASTNode parent, int offset ) + { + var data = new Data(); + + var prevIndex = parent.PreviousIndex( offset ); + var prev = prevIndex == -1 ? null : parent.children[ prevIndex ]; + + while ( prev != null && prev.IsToken( LexerMatcherLibrary.CSAccessModifierMatcher ) ) + { + data.modifiers.Insert( 0, prev as Token ); + + prevIndex = parent.PreviousIndex( prevIndex ); + prev = prevIndex == -1 ? null : parent.children[ prevIndex ]; + } + + while ( prev != null && prev.IsToken( LexerMatcherLibrary.BracketMatcher, "]" ) ) + { + var bracketOpenerIndex = parent.ReverseFindBracketOpenerIndex( "[", "]", prevIndex ); + + if ( bracketOpenerIndex != -1 ) + { + data.attributeBrackets.Add( parent.children[ prevIndex ] as Token ); + data.attributeBrackets.Add( parent.children[ bracketOpenerIndex ] as Token ); + } + + prevIndex = parent.PreviousIndex( bracketOpenerIndex ); + prev = prevIndex == -1 ? null : parent.children[ prevIndex ]; + } + + if ( data.attributeBrackets.Count > 0 ) + { + data.attributeBrackets.Reverse(); + } + + return data; + } + + public static Data ParseForward( ASTNode parent, int offset ) + { + var data = new Data(); + + var nextIndex = parent.NextIndex( offset ); + var next = nextIndex == -1 ? null : parent.children[ nextIndex ]; + + while ( next != null && + ( + next.IsToken( LexerMatcherLibrary.BracketMatcher, "[" ) || + next is SquareBlock + ) + ) + { + var isSquareBlock = next is SquareBlock; + + var bracketCloserIndex = isSquareBlock ? nextIndex : parent.FindBracketCloserIndex( "[", "]", nextIndex ); + + if ( bracketCloserIndex != -1 ) + { + if ( isSquareBlock ) + { + var sb = next as SquareBlock; + data.attributeBrackets.Add( sb.GetSquareStart() ); + data.attributeBrackets.Add( sb.GetSquareEnd() ); + } + else + { + data.attributeBrackets.Add( parent.children[ nextIndex ] as Token ); + data.attributeBrackets.Add( parent.children[ bracketCloserIndex ] as Token ); + } + + } + + nextIndex = parent.NextIndex( bracketCloserIndex ); + next = nextIndex == -1 ? null : parent.children[ nextIndex ]; + + } + + while ( next != null && next.IsToken( LexerMatcherLibrary.CSAccessModifierMatcher ) ) + { + data.modifiers.Add( next as Token ); + + nextIndex = parent.NextIndex( nextIndex ); + next = nextIndex == -1 ? null : parent.children[ nextIndex ]; + } + + data.nextNode = next as Token; + + return data; + } + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs.uid new file mode 100644 index 0000000..e0041b7 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs.uid @@ -0,0 +1 @@ +uid://cocfup6k7r425 diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs new file mode 100644 index 0000000..ec49e5f --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +namespace Rokojori; + + + +public class CSObjectParser:ASTParserPhase +{ + ASTNode objectRoot; + + public static ASTParser CreateParser( ASTNode root ) + { + var csLexer = new CSLexer(); + var blockResolver = new ASTMatcherResolver(); + var matcher = new BracketBlockMatcher(); + + matcher.blockStart = TokenPredicateData.Lexed( csLexer, "[" ); + matcher.blockEnd = TokenPredicateData.Lexed( csLexer, "]" ); + blockResolver.matcher = matcher; + blockResolver.initializer = ( sb, matcher ) => sb.childIndex; + + + List resolvers = + [ + CSClassDeclaration.Resolver(), + CSStructDeclaration.Resolver(), + CSEnumDeclaration.Resolver(), + CSInterfaceDeclaration.Resolver(), + + blockResolver, + + new CSMemberResolver() + ]; + + var astParser = new ASTParser(); + astParser.resolvers = resolvers; + astParser.root = root; + return astParser; + } + + public CSObjectParser( ASTNode root ):base( CreateParser( root ) ) + { + objectRoot = root; + + RJLog.Log( "Starting object parser", root ); + } + + public override ASTNode GetParsingRoot( Parser parser ) + { return objectRoot; } + + + + +} diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs.uid new file mode 100644 index 0000000..a9d5b85 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs.uid @@ -0,0 +1 @@ +uid://uososvnyibqx diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs new file mode 100644 index 0000000..888776f --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs @@ -0,0 +1,121 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class CSPreProcessor:ParserPhase +{ + public override void Process( Parser parser ) + { + var csParser = parser as CSParser; + var tokens = parser.root.children; + + var visible = true; + + var visibleEvents = new List(); + + var stack = new CSPreProcessorStack(); + + stack.defines.UnionWith( csParser.rootPhase.preProcessorContext.defines ); + + for ( int i = 0; i < tokens.Count; i++ ) + { + var tk = tokens[ i ]; + var match = tk.CombinedMatch(); + + if ( ! tk.IsToken( LexerMatcherLibrary.CInstructionMatcher ) ) + { + if ( visible ) + { + visibleEvents.Add( tk ); + } + else + { + RJLog.Log( "Removing:", tk ); + } + + continue; + } + + RJLog.Log( "Removing:", tk ); + + var type = GetPreProcessorType( match ); + + if ( type == 0 ) + { + continue; + } + + if ( IsDefinining( match ) ) + { + var defineType = match.StartsWith( "#define" ); + var value = match.Substring( match.IndexOf( " " ) ).Trim(); + + stack.ProcessDefine( value, defineType ); + } + else if ( IsConditional( match ) ) + { + if ( match.StartsWith( "#endif" ) ) + { + stack.CloseConditionalContext(); + } + else if ( match.StartsWith( "#else" ) ) + { + stack.SetElseBranch(); + } + else + { + if ( match.StartsWith( "#if" ) ) + { + stack.OpenConditionalContext(); + } + + var condition = match.Substring( match.IndexOf( " " ) ).Trim(); + var conditionActive = CSPreProcessorConditionalEvaluator.Evaluate( condition, stack.defines ); + + stack.SetConditionalContext( conditionActive ); + } + + visible = stack.GetVisibility(); + } + + + } + + parser.root.children.ForEach( c => c.parent = null ); + parser.root.children = visibleEvents; + parser.root.children.ForEach( c => c.parent = parser.root ); + + var infos = parser.root.children.Map( le => le + "" ); + RJLog.Log( "Filtered Events:", infos.Join( "\n" ) ); + } + + public int GetPreProcessorType( string match ) + { + if ( IsConditional( match ) ) + { + return 1; + } + + if ( IsDefinining( match ) ) + { + return 2; + } + + return 0; + } + + public bool IsConditional( string match ) + { + return match.StartsWithAny( "#if", "#elif", "#else", "#endif" ); + } + + public bool IsDefinining( string match ) + { + return match.StartsWithAny( "#define", "#undef" ); + } + + + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs.uid new file mode 100644 index 0000000..6bdc277 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs.uid @@ -0,0 +1 @@ +uid://s75c3k16outa diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs new file mode 100644 index 0000000..b1de982 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; + +namespace Rokojori; + + +public class CSPreProcessorConditionalEvaluator:Parser +{ + public class Root:ASTNode,ASTFileRoot + { + public string path; + public string GetFilePath() + { + return path; + } + + public CSPreProcessorConditionalEvaluator evaluator; + + public Parser GetParser() + { + return evaluator; + } + + public string GetSource() + { + return evaluator.source; + } + + public TextLinesMapper GetTextLinesMapper() + { + return evaluator.linesMapper; + } + + } + + public HashSet defines = new HashSet(); + + public CSPreProcessorExpressionParser expressionParser = new CSPreProcessorExpressionParser(); + + public override ExpressionParser GetExpressionParser() + { + return expressionParser; + } + + public LexerPhase lexerPhase = new LexerPhase( new CSLexer() ); + + public TextLinesMapper linesMapper = new TextLinesMapper(); + + public CSPreProcessorConditionalEvaluator() + { + phases = [ + lexerPhase, + expressionParser + ]; + + var root = new Root(); + root.evaluator = this; + + this.root = root; + } + + public static bool Evaluate( string expression, HashSet defines ) + { + var evaluator = new CSPreProcessorConditionalEvaluator(); + evaluator.defines.UnionWith( defines ); + evaluator.Parse( expression ); + + var result = evaluator.Evaluate(); + + if ( result == -1 ) + { + RJLog.Error( "Result:", result, "Context:", evaluator.context.messages ); + var info = evaluator.root.CreateDebugTreeInfo(); + RJLog.Error( "\n" + info ); + + throw new Exception(); + } + + return result == 1; + } + + public ExpressionContext context; + + public int Evaluate() + { + var rootExpression = this.root.walker.FindAnyChild( this.root, c => c is OperatorExpression ); + var ev = new CSPPEvaluator(); + ev.defines = defines ?? ( new HashSet() ); + + context = ev.EvaluateExpression( rootExpression as OperatorExpression ); + var result = context.result; + + if ( result.hasError ) + { + RJLog.Error( result.messages ); + return -1; + } + + return (bool)result.value == true ? 1 : 0; + } + + protected class CSPPEvaluator:ExpressionEvaluator + { + public HashSet defines = new HashSet(); + + public class Result:ExpressionResult + { + public static Result As( bool value ) + { + var r = new Result(); + r.value = value; + return r; + } + + public static Result True() + { + return As( true ); + } + + public static Result False() + { + return As( false ); + } + + public static Result Error( string message, params ExpressionResult[] extendingResults ) + { + var r = new Result(); + + for ( int i = 0; i < extendingResults.Length; i++ ) + { + r.messages.AddRange( extendingResults[ i ].messages ); + } + + r.messages.Add( Message.Error( message ) ); + + + return r; + } + } + + protected override ExpressionContext _CreateContext() + { + return new ExpressionContext(); + } + + protected override ExpressionResult _Evaluate( ExpressionContext context, OperatorExpression expression ) + { + if ( expression == null ) + { + return Result.Error( "Null expression!" ); + } + + + context.messages.Add( Message.Info( expression.GetType().Name ) ); + + if ( expression is ConstantExpression ce ) + { + return _Eval( context, ce ); + } + else if ( expression is VariableExpression ve ) + { + return _Eval( context, ve ); + } + else if ( expression is BinaryExpression bi ) + { + return _Eval( context, bi ); + } + else if ( expression is UnaryExpression un ) + { + return _Eval( context, un ); + } + else if ( expression is GroupExpression gr ) + { + return _Eval( context, gr ); + } + + return Result.Error( "Unknown expression type: " + expression.GetType().Name ); + } + + protected ExpressionResult _Eval( ExpressionContext context, ConstantExpression expression ) + { + var constant = expression.GetConstantExpression(); + + if ( constant.IsToken( LexerMatcherLibrary.BoolMatcher, "true" ) ) + { + return Result.True(); + } + else if ( constant.IsToken( LexerMatcherLibrary.BoolMatcher, "false" ) ) + { + return Result.False(); + } + + return Result.Error( "Unexpected token:" + expression ); + + } + + protected ExpressionResult _Eval( ExpressionContext context, VariableExpression expression ) + { + var variableName = expression.GetExpression().CombinedMatch(); + return Result.As( defines.Contains( variableName ) ); + } + + protected ExpressionResult _Eval( ExpressionContext context, BinaryExpression expression ) + { + var left = expression.GetLeftExpression() as OperatorExpression; + var right = expression.GetRightExpression() as OperatorExpression; + + if ( left == null ) + { + RJLog.Log( "left is null:", expression.GetLeftExpression() ); + } + + if ( right == null ) + { + RJLog.Log( "right is null:", expression.GetLeftExpression() ); + } + + var op = expression.GetOperatorExpression().CombinedMatch(); + + var leftResult = _Evaluate( context, left ); + var rightResult = _Evaluate( context, right ); + + if ( leftResult.hasError || rightResult.hasError ) + { + return Result.Error( "Has error: " + leftResult + " " + rightResult, leftResult, rightResult ); + } + + + if ( op == "==" ) + { + return Result.As( leftResult.value == rightResult.value ); + } + + else if ( op == "!=" ) + { + return Result.As( leftResult.value != rightResult.value ); + } + + else if ( op == "&&" ) + { + return Result.As( (bool)leftResult.value && (bool)rightResult.value ); + } + + else if ( op == "||" ) + { + return Result.As( (bool)leftResult.value || (bool)rightResult.value ); + } + + return Result.Error( "Unknown operator: " + op ); + + } + + protected ExpressionResult _Eval( ExpressionContext context, UnaryExpression expression ) + { + var exp = expression.GetExpression() as OperatorExpression; + + if ( exp == null ) + { + RJLog.Log( "exp is null:", expression.GetExpression() ); + } + + var value = _Evaluate( context, exp ); + + if ( value.hasError ) + { + return Result.Error( "Has error:" + value, value ); + } + + return Result.As( ! ( (bool)value.value ) ); + } + + protected ExpressionResult _Eval( ExpressionContext context, GroupExpression expression ) + { + var gb = expression.GetGroupBody(); + + var exp = gb.walker.FindDirectChild( gb, c => c is OperatorExpression ) as OperatorExpression; + + var value = _Evaluate( context, exp ); + + if ( value.hasError ) + { + return Result.Error( "Has error:" + value, value ); + } + + return Result.As( (bool)value.value ); + } + + } + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs.uid new file mode 100644 index 0000000..131da98 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs.uid @@ -0,0 +1 @@ +uid://bi7vo4gjed31l diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs new file mode 100644 index 0000000..4a2fad0 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSPreProcessorContext +{ + public HashSet defines = new HashSet(); +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs.uid new file mode 100644 index 0000000..51df0ec --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs.uid @@ -0,0 +1 @@ +uid://fmbkq7fn2mhf diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs new file mode 100644 index 0000000..48b0449 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; + +namespace Rokojori; + + +public class CSPreProcessorExpressionParser:ExpressionParser +{ + + public ConstantOperator boolConstantOperator; + + public GroupOperator groupOperator; + + public VariableOperator variableOperator; + + public BinaryOperator andOperator; + public BinaryOperator orOperator; + + public BinaryOperator equalsOperator; + public BinaryOperator notEqualsOperator; + + public UnaryOperator notOperator; + + public CSPreProcessorExpressionParser() + { + Initialize(); + } + + public void Initialize() + { + boolConstantOperator = new ConstantOperator( + TokenPredicateData.Create( LexerMatcherLibrary.BoolMatcher.type ) + ); + + groupOperator = new GroupOperator( "(", ")" ); + + variableOperator = new VariableOperator(); + + andOperator = new BinaryOperator( "&&" ); + orOperator = new BinaryOperator( "||" ); + + equalsOperator = new BinaryOperator( "==" ); + notEqualsOperator = new BinaryOperator( "!=" ); + + notOperator = new UnaryOperator( "!" ); + + + levels = []; + + AddPrecedenceLevel( boolConstantOperator ); + + AddPrecedenceLevel( groupOperator ); + + AddPrecedenceLevel( variableOperator ); + + AddPrecedenceLevel( notOperator ); + + AddPrecedenceLevel( equalsOperator, notEqualsOperator ); + + AddPrecedenceLevel( andOperator ); + + AddPrecedenceLevel( orOperator ); + + + } + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs.uid new file mode 100644 index 0000000..5735328 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs.uid @@ -0,0 +1 @@ +uid://bh4c4giiq32hk diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs new file mode 100644 index 0000000..0a9e722 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +public class CSPreProcessorConditionalContext +{ + public bool lastWasTrue = false; +} + +public class CSPreProcessorStack +{ + public HashSet defines = new HashSet(); + public List conditionalContexts = []; + + public void Push( string value ) + { + defines.Add( value ); + } + + public void Pop( string value ) + { + defines.Remove( value ); + } + + public void ProcessDefine( string value, bool push ) + { + if ( push ) + { + Push( value ); + } + else + { + Pop( value ); + } + } + + public void OpenConditionalContext() + { + conditionalContexts.Add( new CSPreProcessorConditionalContext() ); + } + + public void CloseConditionalContext() + { + conditionalContexts.Pop(); + } + + public void SetConditionalContext( bool value ) + { + conditionalContexts.Last().lastWasTrue = value; + } + + public void SetElseBranch() + { + conditionalContexts.Last().lastWasTrue = ! conditionalContexts.Last().lastWasTrue; + } + + public bool GetVisibility() + { + return conditionalContexts.Count == 0 || conditionalContexts.Last().lastWasTrue; + } +} + \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs.uid new file mode 100644 index 0000000..10c3b8d --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs.uid @@ -0,0 +1 @@ +uid://bfkjft2gy8yqy diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs new file mode 100644 index 0000000..e5bab43 --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace Rokojori; + +public class CSRootFileParser:ASTParserPhase +{ + public CSPreProcessorContext preProcessorContext = new CSPreProcessorContext(); + + public static ASTParser CreateParser() + { + List resolvers = + [ + CSImportDeclaration.Resolver(), + CSNamespaceDeclaration.Resolver(), + + CSClassDeclaration.Resolver(), + CSStructDeclaration.Resolver(), + CSEnumDeclaration.Resolver(), + CSInterfaceDeclaration.Resolver() + ]; + + var astParser = new ASTParser(); + astParser.resolvers = resolvers; + + return astParser; + } + + public CSRootFileParser():base( CreateParser() ) + {} + + public override ASTNode GetParsingRoot( Parser p ) + { + return p.root; + } + + +} \ No newline at end of file diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs.uid new file mode 100644 index 0000000..dec278f --- /dev/null +++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs.uid @@ -0,0 +1 @@ +uid://ciibe6tecx4h6 diff --git a/Runtime/Text/Text.cs b/Runtime/Text/Text.cs index c584cd3..1212e2a 100644 --- a/Runtime/Text/Text.cs +++ b/Runtime/Text/Text.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; +using System.Text; using System.Text.RegularExpressions; @@ -8,6 +9,23 @@ namespace Rokojori { public static class Text { + public static string Repeat( this string text, int times ) + { + if ( times <= 0 ) + { + return ""; + } + + var sb = new StringBuilder(); + + for ( int i = 0; i < times; i++ ) + { + sb.Append( text ); + } + + return sb.ToString(); + } + public static string GetInnerMatch( this string text, string start, string ending, int offset = 0) { var startIndex = text.IndexOf( start, offset ); @@ -133,6 +151,19 @@ namespace Rokojori return long.Parse( source ); } + public static bool StartsWithAny( this string source, params string[] starts ) + { + for ( int i = 0; i < starts.Length; i++ ) + { + if ( source.StartsWith( starts[ i ] ) ) + { + return true; + } + } + + return false; + } + public static string ReplaceStart( this string source, string start, string replacement = "" ) { if ( start == "" ) diff --git a/Runtime/Tools/Lists.cs b/Runtime/Tools/Lists.cs index 1a060e0..a59e3ad 100644 --- a/Runtime/Tools/Lists.cs +++ b/Runtime/Tools/Lists.cs @@ -502,6 +502,11 @@ namespace Rokojori return list == null ? 0 : list.Count; } + public static List Range( this List elements, int start, int end ) + { + return elements.Sub( start, end - start + 1 ); + } + public static List Sub( this List elements, int start, int length = 0 ) { var end = length == 0 ? elements.Count : ( start + length ); @@ -611,7 +616,12 @@ namespace Rokojori return PopLast( list ); } - public static T Shift( this List list ) + public static void Prepend( this List list, List other ) + { + list.InsertRange( 0, other ); + } + + public static T Shift( this List list ) { if ( list.Count == 0 ){ return default(T); } @@ -644,6 +654,16 @@ namespace Rokojori return GetLast( list ); } + public static T GetFirst( List list ) + { + return list.Count == 0 ? default(T) : list[ 0 ]; + } + + public static T First( this List list ) + { + return list.Count == 0 ? default(T) : list[ 0 ]; + } + public static T ReverseAt( this List list, int index ) { return list[ list.Count - 1 - index ]; diff --git a/Runtime/UI/Nodes/Image/UIImage.cs b/Runtime/UI/Nodes/Image/UIImage.cs index 3b08bf1..8a8b757 100644 --- a/Runtime/UI/Nodes/Image/UIImage.cs +++ b/Runtime/UI/Nodes/Image/UIImage.cs @@ -10,6 +10,14 @@ namespace Rokojori [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")] public partial class UIImage:TextureRect, UIStylePropertyContainerNode, UIHolderControl, IAssemblyReload { + [Export] + public bool activateDebugging = false; + + public bool HasDebugFlag() + { + return activateDebugging; + } + protected UIImageType _imageType; [Export] public UIImageType imageType @@ -84,10 +92,27 @@ namespace Rokojori } } - string hoverID = IDGenerator.GenerateID(); + string hoverID = IDGenerator.GenerateID(); + UICursor appliedCursor = null; public override void _Ready() { + VisibilityChanged += ()=> + { + var visible = IsVisibleInTree(); + + if ( visible ) + { + onVisible?.Trigger(); + } + else + { + onInvisible?.Trigger(); + } + + onVisibilityChanged?.Trigger(); + }; + FocusEntered += ()=> { this.LogInfo( "Focused", setActiveWhenFocused.Length ); @@ -141,6 +166,15 @@ namespace Rokojori { AddUISelectorFlag( UISelectorFlag.Hover, hoverID ); this.SetDirty(); + + var currentHoverCursor = UIStyle.ResolveHoverCursor( this ); + + if ( currentHoverCursor != null ) + { + currentHoverCursor.ApplyCursor( this ); + appliedCursor = currentHoverCursor; + this.LogInfo( "Set Cursor on Hover:", appliedCursor ); + } }; @@ -148,12 +182,20 @@ namespace Rokojori { RemoveUISelectorFlag( UISelectorFlag.Hover, hoverID ); this.SetDirty(); + + if ( appliedCursor != null ) + { + this.LogInfo( "Reset Cursor on Exit"); + appliedCursor.ClearCursor( this ); + } }; UpdateImageType(); ComputeUIAncestorDepth(); } + + public override void _EnterTree() { UpdateImageType(); @@ -198,7 +240,10 @@ namespace Rokojori protected override void Dispose( bool disposing) { _selectorFlagReferenceCounter.Clear(); - } + } + + [Export] + public UISelectorFlag[] additionalSelectorFlags = []; MapList _selectorFlagReferenceCounter = new MapList(); @@ -225,6 +270,8 @@ namespace Rokojori var numFlagsBefore = _selectorFlags.Count; _selectorFlags = _selectorFlagReferenceCounter.Keys.ToList(); + + _selectorFlags.AddRange( additionalSelectorFlags ); var changed = numFlagsBefore != _selectorFlags.Count; @@ -333,6 +380,158 @@ namespace Rokojori shaderUIColor.color = color; } + + [ExportGroup("Actions")] + + [Export] + public Action onVisible; + + [Export] + public Action onInvisible; + + [Export] + public Action onVisibilityChanged; + + [ExportGroup( "Interactivity" )] + [Export] + public UICursor hoverCursor; + + public UICursor GetHoverCursor( UIStylePropertyContainer container ) + { + return hoverCursor; + } + + + [Export] + public Action onUIConfirm; + + + public enum ConfirmClick + { + Ignore, + MouseDown, + MouseRelease, + Focused_MouseDown, + Focused_MouseRelease + } + + [Export] + public ConfirmClick confirmClickMode = ConfirmClick.MouseDown; + + [Export] + public Action onFocusEntered; + + [Export] + public Action onFocusExited; + + [Export] + public Control[] setActiveWhenFocused = []; + + [Export] + public Control focusControl; + + [Export] + public bool handleMouseEvents = false; + + [Export] + public Action onLeftClick; + + [Export] + public Action onMiddleClick; + + [Export] + public Action onRightClick; + + public override void _GuiInput( InputEvent inputEvent ) + { + var ui = GetUI(); + + // this.LogInfo( "InputEvent", inputEvent, ui.settings.uiConfirm.IsDown( inputEvent ) ); + + if ( ui.settings.uiConfirm.IsDown( inputEvent ) ) + { + onUIConfirm?.Trigger(); + // GD.Print("ui_accept pressed while focused"); + // AcceptEvent(); // Optional: stop propagation + } + + if ( inputEvent is InputEventMouseButton lmb ) + { + if ( lmb.IsPressed() ) + { + AddUISelectorFlag( UISelectorFlag.Dragging ); + + if ( focusControl != null ) + { + focusControl.GrabFocus(); + } + } + + if ( lmb.IsReleased() ) + { + RemoveUISelectorFlag( UISelectorFlag.Dragging ); + } + + + if ( lmb.Pressed && lmb.ButtonIndex == MouseButton.Left ) + { + if ( ConfirmClick.MouseDown == confirmClickMode || ConfirmClick.Focused_MouseDown == confirmClickMode ) + { + if ( HasFocus() || ConfirmClick.MouseDown == confirmClickMode ) + { + onUIConfirm?.Trigger(); + } + } + } + else if ( + lmb.IsReleased() && lmb.ButtonIndex == MouseButton.Left && + _selectorFlags != null && _selectorFlags.Contains( UISelectorFlag.Hover ) + ) + { + if ( ConfirmClick.MouseRelease == confirmClickMode || ConfirmClick.Focused_MouseRelease == confirmClickMode ) + { + if ( HasFocus() || ConfirmClick.MouseRelease == confirmClickMode ) + { + onUIConfirm?.Trigger(); + } + } + } + } + + if ( ! handleMouseEvents ) + { + return; + } + + + if ( inputEvent is InputEventMouseButton mb ) + { + if ( mb.Pressed ) + { + this.LogInfo( "Clicked" ); + + if ( mb.ButtonIndex == MouseButton.Left ) + { + Action.Trigger( onLeftClick ); + } + + if ( mb.ButtonIndex == MouseButton.Middle ) + { + Action.Trigger( onMiddleClick ); + } + + if ( mb.ButtonIndex == MouseButton.Right ) + { + Action.Trigger( onRightClick ); + } + } + } + + } + + + [ExportCategory( "UIStyle" )] + [Export] public UIStyle parentStyle; @@ -475,24 +674,7 @@ namespace Rokojori } - [ExportGroup( "Interactivity" )] - [Export] - public UICursor hoverCursor; - - [Export] - public Action onFocusEntered; - - [Export] - public Action onFocusExited; - - [Export] - public Control[] setActiveWhenFocused = []; - - public UICursor GetHoverCursor( UIStylePropertyContainer container ) - { - return hoverCursor; - } - + [ExportGroup( "Sound" )] [Export] diff --git a/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs b/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs index 1ca2cfb..6ee55d3 100644 --- a/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs +++ b/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs @@ -123,6 +123,11 @@ namespace Rokojori return offset; } + if ( RoundedRectangleShader.strokeSize.propertyName == shaderPropertyName ) + { + return strokeSize; + } + return null; } diff --git a/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs b/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs index 135b978..b9e6e8e 100644 --- a/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs +++ b/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs @@ -26,6 +26,8 @@ public partial class UIScrollSlider:UISlider _onSliderChange.AddAction( ( pos ) => { SyncScroll(); } ); _hasEventListener = true; } + + UpdateVisibility(); } @@ -41,15 +43,67 @@ public partial class UIScrollSlider:UISlider } base._Process( delta ); + + UpdateVisibility(); + + } Vector2 _lastOffset = Vector2.Zero; + [Export] + public bool showInfo = false; + + [Export] + public bool automaticVisibility = true; + + void UpdateVisibility( bool force = false ) + { + if ( ! force && ! automaticVisibility ) + { + return; + } + + var viewSize = scrollContainer.Size; + var contentSize = scrollArea.Size; + + if ( showInfo ) + { + this.LogInfo( + "containerSize", viewSize, + "areaSize", contentSize + ); + } + + + if ( UISlider.Direction.Horizontal == direction ) + { + + if ( viewSize.X > contentSize.X ) + { + this.SetVisibility( false ); + return; + } + } + else if ( UISlider.Direction.Vertical == direction ) + { + if ( viewSize.Y > contentSize.Y ) + { + this.SetVisibility( false ); + return; + } + } + + this.SetVisibility( true ); + } + public void SyncScroll() { var containerSize = scrollContainer.Size; var areaSize = scrollArea.Size; + UpdateVisibility(); + var scroll = areaSize - containerSize; scroll = scroll.Max( Vector2.Zero ); diff --git a/Runtime/UI/Nodes/Sliders/UISlider.cs b/Runtime/UI/Nodes/Sliders/UISlider.cs index d8de45f..93fb9c4 100644 --- a/Runtime/UI/Nodes/Sliders/UISlider.cs +++ b/Runtime/UI/Nodes/Sliders/UISlider.cs @@ -94,6 +94,14 @@ public partial class UISlider:UIImage, UIFocusProcessor { base._Ready(); + VisibilityChanged += ()=> + { + if ( IsVisibleInTree() ) + { + SyncSliderValue(); + } + }; + if ( imageType == null ) { imageType = new SliderUIImageType(); @@ -117,7 +125,6 @@ public partial class UISlider:UIImage, UIFocusProcessor SyncSliderValue(); - AssignListener(); } @@ -133,47 +140,7 @@ public partial class UISlider:UIImage, UIFocusProcessor float lastUp = 0f; float lastDown = 0f; - public void OnFocusProcess( double delta ) - { - var settings = GetUI().settings; - - if ( settings == null ) - { - return; - } - - if ( Direction.Horizontal == direction ) - { - - var offset = 0; - - if ( settings.uiLeft.IsRepeatDown( ref lastLeft ) ) - { - offset --; - } - - if ( settings.uiRight.IsRepeatDown( ref lastRight ) ) - { - offset ++; - } - - if ( offset != 0 ) - { - var nextMainValue = MathX.Clamp01( mainValue + offset * offsetPerInput ); - nextValue = NormalizedToButtonPosition( GetNextSliderMainValue( nextMainValue ) ); - - if ( ! _updatingPosition ) - { - _updatingPosition = true; - GetUI().onProcess.AddAction( UpdatePosition ); - } - - } - } - - - // UpdatePosition( (float) delta ); - } + // public override void _GuiInput( InputEvent inputEvent ) // { @@ -384,6 +351,56 @@ public partial class UISlider:UIImage, UIFocusProcessor bool _listenerAssigned = false; + public void OnFocusProcess( double delta ) + { + var settings = GetUI().settings; + + if ( settings == null ) + { + return; + } + + if ( Direction.Horizontal == direction ) + { + + var offset = 0; + + if ( settings.uiLeft.IsRepeatDown( ref lastLeft ) ) + { + offset --; + } + + if ( settings.uiRight.IsRepeatDown( ref lastRight ) ) + { + offset ++; + } + + if ( offset != 0 ) + { + var nextMainValue = MathX.Clamp01( mainValue + offset * offsetPerInput ); + nextValue = NormalizedToButtonPosition( GetNextSliderMainValue( nextMainValue ) ); + // var dir = direction == Direction.Horizontal ? Vector2.Right : Vector2.Down; + // var cachedButtonPosition = NormalizedToButtonPosition( sliderValue ); + // var nextPosition = cachedButtonPosition + dir * offset * offsetPerInput ; + // nextValue = nextPosition.Clamp( buttonPositionMin, buttonPositionMax ); + + if ( ! _updatingPosition ) + { + if ( smoothing != null ) + { + smoothing?.SetCurrent( NormalizedToButtonPosition( sliderValue ) ); + } + _updatingPosition = true; + GetUI().onProcess.AddAction( UpdatePosition ); + } + + } + } + + + // UpdatePosition( (float) delta ); + } + void AssignListener() { if ( _listenerAssigned ) diff --git a/Runtime/UI/Nodes/UIInputInfo.cs b/Runtime/UI/Nodes/UIInputInfo.cs index f497cc1..c4a42da 100644 --- a/Runtime/UI/Nodes/UIInputInfo.cs +++ b/Runtime/UI/Nodes/UIInputInfo.cs @@ -44,7 +44,7 @@ namespace Rokojori UpdateInfo(); } - void UpdateInfo() + public void UpdateInfo() { Nodes.RemoveAndDeleteChildren( this ); @@ -84,7 +84,7 @@ namespace Rokojori localeText.locale = locale; localeText.font = iiLib.font; - localeText.fontSize = this.fontSize != null ? this.fontSize : iiLib.fontSize; + localeText.fontSize = this.fontSize ?? iiLib.fontSize; localeText.Uppercase = upperCase; localeText.marginLeft = UINumber.EM( 0.25f ); diff --git a/Runtime/UI/Nodes/UIRegion.cs b/Runtime/UI/Nodes/UIRegion.cs index 0eda2ed..a12e5d7 100644 --- a/Runtime/UI/Nodes/UIRegion.cs +++ b/Runtime/UI/Nodes/UIRegion.cs @@ -9,27 +9,202 @@ namespace Rokojori [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIRegion.svg")] public partial class UIRegion : Control, UIStylePropertyContainerNode, UIHolderControl { + + [Export] + public bool activateDebugging = false; + + public bool HasDebugFlag() + { + return activateDebugging; + } [Export] - public UIStyle parentStyle; + public string currentSelectors = ""; - [ExportGroup( "Layout" )] + [ExportGroup("Actions")] + [Export] - public UILayout layout; + public Action onVisible; + + [Export] + public Action onInvisible; [Export] - public UINumber horizontalAlignment; + public Action onVisibilityChanged; + + [ExportGroup( "Interactivity" )] [Export] - public UINumber verticalAlignment; - [Export] - public UINumber verticalPlacement; + public UICursor hoverCursor; + + public UICursor GetHoverCursor( UIStylePropertyContainer container ) + { + return hoverCursor; + } + [Export] - public UINumber elementSpacing; + public Action onUIConfirm; + + + public enum ConfirmClick + { + Ignore, + MouseDown, + MouseRelease, + Focused_MouseDown, + Focused_MouseRelease + } + [Export] - public UINumber lineSpacing; + public ConfirmClick confirmClickMode = ConfirmClick.MouseDown; + + [Export] + public Action onFocusEntered; + + [Export] + public Action onFocusExited; + + [Export] + public Control[] setActiveWhenFocused = []; + + [Export] + public Control focusControl; + + [Export] + public bool handleMouseEvents = false; + + [Export] + public Action onLeftClick; + + [Export] + public Action onMiddleClick; + + [Export] + public Action onRightClick; + + public override void _GuiInput( InputEvent inputEvent ) + { + var ui = GetUI(); + + // this.LogInfo( "InputEvent", inputEvent, ui.settings.uiConfirm.IsDown( inputEvent ) ); + + if ( ui.settings.uiConfirm.IsDown( inputEvent ) ) + { + onUIConfirm?.Trigger(); + // GD.Print("ui_accept pressed while focused"); + // AcceptEvent(); // Optional: stop propagation + } + + if ( inputEvent is InputEventMouseButton lmb ) + { + if ( lmb.IsPressed() ) + { + AddUISelectorFlag( UISelectorFlag.Dragging ); + + if ( focusControl != null ) + { + focusControl.GrabFocus(); + } + } + + if ( lmb.IsReleased() ) + { + RemoveUISelectorFlag( UISelectorFlag.Dragging ); + } + + + if ( lmb.Pressed && lmb.ButtonIndex == MouseButton.Left ) + { + if ( ConfirmClick.MouseDown == confirmClickMode || ConfirmClick.Focused_MouseDown == confirmClickMode ) + { + if ( HasFocus() || ConfirmClick.MouseDown == confirmClickMode ) + { + onUIConfirm?.Trigger(); + } + } + } + else if ( + lmb.IsReleased() && lmb.ButtonIndex == MouseButton.Left && + _selectorFlags != null && _selectorFlags.Contains( UISelectorFlag.Hover ) + ) + { + if ( ConfirmClick.MouseRelease == confirmClickMode || ConfirmClick.Focused_MouseRelease == confirmClickMode ) + { + if ( HasFocus() || ConfirmClick.MouseRelease == confirmClickMode ) + { + onUIConfirm?.Trigger(); + } + } + } + } + + if ( ! handleMouseEvents ) + { + return; + } + + + if ( inputEvent is InputEventMouseButton mb ) + { + if ( mb.Pressed ) + { + this.LogInfo( "Clicked" ); + + if ( mb.ButtonIndex == MouseButton.Left ) + { + Action.Trigger( onLeftClick ); + } + + if ( mb.ButtonIndex == MouseButton.Middle ) + { + Action.Trigger( onMiddleClick ); + } + + if ( mb.ButtonIndex == MouseButton.Right ) + { + Action.Trigger( onRightClick ); + } + } + } + + } + + [ExportGroup( "Functions" )] + [Export] + public UI.FocusOrderType focusOrderType = UI.FocusOrderType.Vertical_List; + + [ExportToolButton( "Set Focus Connections" )] + public Callable setFocusConnectionButton => Callable.From( + ( ) => + { + UI.SetChildFocusOrder( this, focusOrderType, null, FocusModeEnum.Click ); + } + ); + + #if TOOLS + [ExportGroup("Editor SceneSetup")] + [Export] + public UISettings uiSettings; + + [Export] + public bool updateInEditor = false; + + [Export] + public float fontZoom = 1f; + + [Export] + public bool reassignUI; + [ExportGroup("Editor SceneSetup/Read Only")] + [Export] + public float computedFontSize = 0f; + + #endif + + [ExportCategory( "UIStyle" )] + + [ExportGroup( "Size & Margins" )] [Export] public UINumber width; @@ -64,6 +239,23 @@ namespace Rokojori [Export] public UINumber bottom; + + [ExportGroup( "Child Layout" )] + [Export] + public UILayout layout; + + [Export] + public UINumber horizontalAlignment; + [Export] + public UINumber verticalAlignment; + [Export] + public UINumber verticalPlacement; + + [Export] + public UINumber elementSpacing; + [Export] + public UINumber lineSpacing; + [ExportGroup( "Font" )] [Export] public Font font; @@ -93,15 +285,6 @@ namespace Rokojori [Export] public UIColor selfModulationColor; - // public List> GetActiveShaderUIColorTransitions() - // { - // return null; - // } - - // public List> GetActiveShaderUINumberTransitions() - // { - // return null; - // } [ExportGroup("Transitions")] [Export] @@ -169,32 +352,14 @@ namespace Rokojori } } - [Export] - public Action onFocusEntered; - [Export] - public Action onFocusExited; - - #if TOOLS - [ExportGroup("Editor SceneSetup")] - [Export] - public UISettings uiSettings; - - [Export] - public bool updateInEditor = false; - - [Export] - public float fontZoom = 1f; - + [ExportGroup( "" )] [Export] - public bool reassignUI; - [ExportGroup("Editor SceneSetup/Read Only")] - [Export] - public float computedFontSize = 0f; + public UIStyle parentStyle; + - #endif public UIStyle GetUIStyleParent() @@ -231,11 +396,6 @@ namespace Rokojori { return null; } - - public UICursor GetHoverCursor( UIStylePropertyContainer container ) - { - return null; - } public Font GetFont() { @@ -363,8 +523,26 @@ namespace Rokojori string hoverID = IDGenerator.GenerateID(); + UICursor appliedCursor = null; + public override void _Ready() { + VisibilityChanged += ()=> + { + var visible = IsVisibleInTree(); + + if ( visible ) + { + onVisible?.Trigger(); + } + else + { + onInvisible?.Trigger(); + } + + onVisibilityChanged?.Trigger(); + }; + FocusEntered += ()=> { AddUISelectorFlag( UISelectorFlag.Focus ); @@ -399,6 +577,15 @@ namespace Rokojori { AddUISelectorFlag( UISelectorFlag.Hover, hoverID ); this.SetDirty(); + + var currentHoverCursor = UIStyle.ResolveHoverCursor( this ); + + if ( currentHoverCursor != null ) + { + currentHoverCursor.ApplyCursor( this ); + appliedCursor = currentHoverCursor; + this.LogInfo( "Set Cursor on Hover:", appliedCursor ); + } }; @@ -406,6 +593,12 @@ namespace Rokojori { RemoveUISelectorFlag( UISelectorFlag.Hover, hoverID ); this.SetDirty(); + + if ( appliedCursor != null ) + { + this.LogInfo( "Reset Cursor on Exit"); + appliedCursor.ClearCursor( this ); + } }; } @@ -438,6 +631,9 @@ namespace Rokojori _uiAncestorDepth = -1; } + [Export] + public UISelectorFlag[] additionalSelectorFlags = []; + MapList _selectorFlagReferenceCounter = new MapList(); public void AddUISelectorFlag( UISelectorFlag flag, string reference = "" ) @@ -450,7 +646,7 @@ namespace Rokojori SetSelectorFlagReference( flag, reference, false ); } - protected override void Dispose( bool disposing) + protected override void Dispose( bool disposing ) { _selectorFlagReferenceCounter.Clear(); } @@ -468,22 +664,25 @@ namespace Rokojori var numFlagsBefore = _selectorFlags.Count; _selectorFlags = _selectorFlagReferenceCounter.Keys.ToList(); + _selectorFlags.AddRange( additionalSelectorFlags ); + var changed = numFlagsBefore != _selectorFlags.Count; UISelector.UpdateParentUISelectorFlags( this ); - this.LogInfo( - "flag:", flag, - "reference:", reference, - "enable:", enable, - "changed:", changed, - "numFlagsBefore:", numFlagsBefore, - "_selectorFlags:", _selectorFlags.Map( sf => sf.ResourcePath + " " + sf.ResourceName ).Join( ", " ) - ); + // this.LogInfo( + // "flag:", flag, + // "reference:", reference, + // "enable:", enable, + // "changed:", changed, + // "numFlagsBefore:", numFlagsBefore, + // "_selectorFlags:", _selectorFlags.Map( sf => sf.ResourcePath + " " + sf.ResourceName ).Join( ", " ) + // ); if ( changed ) { + currentSelectors = _selectorFlags.Map( sf => RegexUtility.TrimToLastPathFragment( sf.ResourcePath ) ).Join( ", " ); this.SetDirty(); } } diff --git a/Runtime/UI/Nodes/UIText.cs b/Runtime/UI/Nodes/UIText.cs index 2cac4fd..04b5329 100644 --- a/Runtime/UI/Nodes/UIText.cs +++ b/Runtime/UI/Nodes/UIText.cs @@ -10,6 +10,13 @@ namespace Rokojori [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIText.svg")] public partial class UIText:Label,UIStylePropertyContainerNode, iLocalizable, UIHolderControl, IAssemblyReload { + [Export] + public bool activateDebugging = false; + + public bool HasDebugFlag() + { + return activateDebugging; + } LocalizedString _locale; @@ -59,6 +66,74 @@ namespace Rokojori [Export] public bool alwaysMinimumSize = true; + + [ExportGroup("Actions")] + + [Export] + public Action onVisible; + + [Export] + public Action onInvisible; + + [Export] + public Action onVisibilityChanged; + + [ExportGroup( "Interactivity" )] + + [Export] + public UICursor hoverCursor; + + public UICursor GetHoverCursor( UIStylePropertyContainer container ) + { + return hoverCursor; + } + + + [Export] + public Action onUIConfirm; + + + public enum ConfirmClick + { + Ignore, + MouseDown, + MouseRelease, + Focused_MouseDown, + Focused_MouseRelease + } + + [Export] + public ConfirmClick confirmClickMode = ConfirmClick.MouseDown; + + [Export] + public Action onFocusEntered; + + [Export] + public Action onFocusExited; + + [Export] + public Control[] setActiveWhenFocused = []; + + [Export] + public Control focusControl; + + [Export] + public bool handleMouseEvents = false; + + [Export] + public Action onLeftClick; + + [Export] + public Action onMiddleClick; + + [Export] + public Action onRightClick; + + + + + [ExportCategory( "UIStyle" )] + UIStyle _parentStyle; [Export] public UIStyle parentStyle @@ -68,6 +143,7 @@ namespace Rokojori } Font _font; + [ExportGroup( "Font" )] [Export] public Font font @@ -185,6 +261,22 @@ namespace Rokojori public override void _Ready() { + VisibilityChanged += ()=> + { + var visible = IsVisibleInTree(); + + if ( visible ) + { + onVisible?.Trigger(); + } + else + { + onInvisible?.Trigger(); + } + + onVisibilityChanged?.Trigger(); + }; + FocusEntered += ()=> { AddUISelectorFlag( UISelectorFlag.Focus ); @@ -240,8 +332,6 @@ namespace Rokojori currentHoverCursor.ApplyCursor( this ); appliedCursor = currentHoverCursor; this.LogInfo( "Set Cursor on Hover:", appliedCursor ); - // Input.SetDefaultCursorShape( hoverCursorShape ); - // MouseDefaultCursorShape = hoverCursorShape; } }; @@ -293,6 +383,9 @@ namespace Rokojori _selectorFlagReferenceCounter.Clear(); } + [Export] + public UISelectorFlag[] additionalSelectorFlags = []; + MapList _selectorFlagReferenceCounter = new MapList(); public void AddUISelectorFlag( UISelectorFlag flag, string reference = "" ) @@ -320,6 +413,7 @@ namespace Rokojori var numFlagsBefore = _selectorFlags.Count; _selectorFlags = _selectorFlagReferenceCounter.Keys.ToList(); + _selectorFlags.AddRange( additionalSelectorFlags ); var changed = numFlagsBefore != _selectorFlags.Count; @@ -357,6 +451,49 @@ namespace Rokojori // AcceptEvent(); // Optional: stop propagation } + if ( inputEvent is InputEventMouseButton lmb ) + { + if ( lmb.IsPressed() ) + { + AddUISelectorFlag( UISelectorFlag.Dragging ); + + if ( focusControl != null ) + { + focusControl.GrabFocus(); + } + } + + if ( lmb.IsReleased() ) + { + RemoveUISelectorFlag( UISelectorFlag.Dragging ); + } + + + if ( lmb.Pressed && lmb.ButtonIndex == MouseButton.Left ) + { + if ( ConfirmClick.MouseDown == confirmClickMode || ConfirmClick.Focused_MouseDown == confirmClickMode ) + { + if ( HasFocus() || ConfirmClick.MouseDown == confirmClickMode ) + { + onUIConfirm?.Trigger(); + } + } + } + else if ( + lmb.IsReleased() && lmb.ButtonIndex == MouseButton.Left && + _selectorFlags != null && _selectorFlags.Contains( UISelectorFlag.Hover ) + ) + { + if ( ConfirmClick.MouseRelease == confirmClickMode || ConfirmClick.Focused_MouseRelease == confirmClickMode ) + { + if ( HasFocus() || ConfirmClick.MouseRelease == confirmClickMode ) + { + onUIConfirm?.Trigger(); + } + } + } + } + if ( ! handleMouseEvents ) { return; @@ -447,41 +584,7 @@ namespace Rokojori } } - [ExportGroup( "Interactivity" )] - [Export] - public UICursor hoverCursor; - - public UICursor GetHoverCursor( UIStylePropertyContainer container ) - { - return hoverCursor; - } - - - [Export] - public Action onUIConfirm; - - [Export] - public Action onFocusEntered; - - [Export] - public Action onFocusExited; - - [Export] - public Control[] setActiveWhenFocused = []; - - [Export] - public bool handleMouseEvents = false; - - [Export] - public Action onLeftClick; - - [Export] - public Action onMiddleClick; - - [Export] - public Action onRightClick; - [ExportGroup( "Sound" )] [Export] public UISoundData onFocusSound; diff --git a/Runtime/UI/Presets/Rule Sets/Active-Hover-Idle.tres b/Runtime/UI/Presets/Rule Sets/Active-Hover-Idle.tres new file mode 100644 index 0000000..396b7a1 --- /dev/null +++ b/Runtime/UI/Presets/Rule Sets/Active-Hover-Idle.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="UIRuleSet" load_steps=5 format=3 uid="uid://csu6y67o56730"] + +[ext_resource type="Resource" uid="uid://cxq4cfdnk7c25" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Rules/Active Rule.tres" id="1_gtued"] +[ext_resource type="Script" uid="uid://cyr5imepel4p0" path="res://addons/rokojori_action_library/Runtime/UI/UIRuleSet.cs" id="1_srg4n"] +[ext_resource type="Resource" uid="uid://d15wkkwgtlh0n" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Rules/Hover Rule.tres" id="2_gbvkv"] +[ext_resource type="Resource" uid="uid://30j7mqgncetr" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Rules/Idle Rule.tres" id="3_0nafc"] + +[resource] +script = ExtResource("1_srg4n") +rules = [ExtResource("1_gtued"), ExtResource("2_gbvkv"), ExtResource("3_0nafc")] +metadata/_custom_type_script = "uid://cyr5imepel4p0" diff --git a/Runtime/UI/Presets/Rule Sets/Focus-Hover-Idle.tres b/Runtime/UI/Presets/Rule Sets/Focus-Hover-Idle.tres new file mode 100644 index 0000000..08de35d --- /dev/null +++ b/Runtime/UI/Presets/Rule Sets/Focus-Hover-Idle.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="UIRuleSet" load_steps=5 format=3 uid="uid://43ns132td8o2"] + +[ext_resource type="Resource" uid="uid://cvc0wabrro18q" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Rules/Focus Rule.tres" id="1_j2gkj"] +[ext_resource type="Resource" uid="uid://d15wkkwgtlh0n" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Rules/Hover Rule.tres" id="2_vdm4c"] +[ext_resource type="Resource" uid="uid://30j7mqgncetr" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Rules/Idle Rule.tres" id="3_h8s7b"] +[ext_resource type="Script" uid="uid://cyr5imepel4p0" path="res://addons/rokojori_action_library/Runtime/UI/UIRuleSet.cs" id="4_3aead"] + +[resource] +script = ExtResource("4_3aead") +rules = [ExtResource("1_j2gkj"), ExtResource("2_vdm4c"), ExtResource("3_h8s7b")] +metadata/_custom_type_script = "uid://cyr5imepel4p0" diff --git a/Runtime/UI/Presets/Rules/Active Rule.tres b/Runtime/UI/Presets/Rules/Active Rule.tres new file mode 100644 index 0000000..76ccaae --- /dev/null +++ b/Runtime/UI/Presets/Rules/Active Rule.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="UIRule" load_steps=4 format=3 uid="uid://cxq4cfdnk7c25"] + +[ext_resource type="Script" uid="uid://8eihwfc2acp1" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIRule.cs" id="1_mfnwy"] +[ext_resource type="Resource" uid="uid://do3q5tipotyn3" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Selectors/Active Selector.tres" id="2_rlfk3"] +[ext_resource type="Resource" uid="uid://brjq22uvnpxuv" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Styles/Mod 100% Style.tres" id="3_ejfkw"] + +[resource] +script = ExtResource("1_mfnwy") +selector = ExtResource("2_rlfk3") +style = ExtResource("3_ejfkw") +metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/Presets/Rules/Focus Rule.tres b/Runtime/UI/Presets/Rules/Focus Rule.tres new file mode 100644 index 0000000..876b1e0 --- /dev/null +++ b/Runtime/UI/Presets/Rules/Focus Rule.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="UIRule" load_steps=4 format=3 uid="uid://cvc0wabrro18q"] + +[ext_resource type="Script" uid="uid://8eihwfc2acp1" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIRule.cs" id="1_80s54"] +[ext_resource type="Resource" uid="uid://dgx4ue1pvvltj" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Selectors/Focus Selector.tres" id="2_blydg"] +[ext_resource type="Resource" uid="uid://brjq22uvnpxuv" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Styles/Mod 100% Style.tres" id="3_qrr7u"] + +[resource] +script = ExtResource("1_80s54") +selector = ExtResource("2_blydg") +style = ExtResource("3_qrr7u") +metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/Presets/Rules/Hover Rule.tres b/Runtime/UI/Presets/Rules/Hover Rule.tres new file mode 100644 index 0000000..8c4b17d --- /dev/null +++ b/Runtime/UI/Presets/Rules/Hover Rule.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="UIRule" load_steps=4 format=3 uid="uid://d15wkkwgtlh0n"] + +[ext_resource type="Script" uid="uid://8eihwfc2acp1" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIRule.cs" id="1_405us"] +[ext_resource type="Resource" uid="uid://cfctpa7mv11nj" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Selectors/Hover Selector.tres" id="2_o7p03"] +[ext_resource type="Resource" uid="uid://cy7m6e0be3mqw" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Styles/Mod 80% Style.tres" id="3_35xig"] + +[resource] +script = ExtResource("1_405us") +selector = ExtResource("2_o7p03") +style = ExtResource("3_35xig") +metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/Presets/Rules/Idle Rule.tres b/Runtime/UI/Presets/Rules/Idle Rule.tres new file mode 100644 index 0000000..8cb3ba5 --- /dev/null +++ b/Runtime/UI/Presets/Rules/Idle Rule.tres @@ -0,0 +1,9 @@ +[gd_resource type="Resource" script_class="UIRule" load_steps=3 format=3 uid="uid://30j7mqgncetr"] + +[ext_resource type="Script" uid="uid://8eihwfc2acp1" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIRule.cs" id="1_r8ebf"] +[ext_resource type="Resource" uid="uid://buoilu1x43rnx" path="res://addons/rokojori_action_library/Runtime/UI/Presets/Styles/Mod 65% Style.tres" id="2_3o1e1"] + +[resource] +script = ExtResource("1_r8ebf") +style = ExtResource("2_3o1e1") +metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/UI-Selectors/Presets/Active Selector.tres b/Runtime/UI/Presets/Selectors/Active Selector.tres similarity index 100% rename from Runtime/UI/UI-Selectors/Presets/Active Selector.tres rename to Runtime/UI/Presets/Selectors/Active Selector.tres diff --git a/Runtime/UI/UI-Selectors/Presets/Focus Selector.tres b/Runtime/UI/Presets/Selectors/Focus Selector.tres similarity index 100% rename from Runtime/UI/UI-Selectors/Presets/Focus Selector.tres rename to Runtime/UI/Presets/Selectors/Focus Selector.tres diff --git a/Runtime/UI/UI-Selectors/Presets/Hover Selector.tres b/Runtime/UI/Presets/Selectors/Hover Selector.tres similarity index 100% rename from Runtime/UI/UI-Selectors/Presets/Hover Selector.tres rename to Runtime/UI/Presets/Selectors/Hover Selector.tres diff --git a/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres b/Runtime/UI/Presets/Styles/Mod 100% Style.tres similarity index 86% rename from Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres rename to Runtime/UI/Presets/Styles/Mod 100% Style.tres index 012b433..f767662 100644 --- a/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres +++ b/Runtime/UI/Presets/Styles/Mod 100% Style.tres @@ -1,13 +1,13 @@ [gd_resource type="Resource" script_class="UIStyle" load_steps=4 format=3 uid="uid://brjq22uvnpxuv"] -[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_bdlk7"] -[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_p68sf"] +[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_4h2q2"] +[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_uob0o"] [sub_resource type="Resource" id="Resource_7s7su"] -script = ExtResource("1_bdlk7") +script = ExtResource("1_4h2q2") metadata/_custom_type_script = "uid://drqb0pm5ub64g" [resource] -script = ExtResource("2_p68sf") +script = ExtResource("2_uob0o") modulationColor = SubResource("Resource_7s7su") metadata/_custom_type_script = "uid://chmcc71dvu4vj" diff --git a/Runtime/UI/Presets/Styles/Mod 65% Style.tres b/Runtime/UI/Presets/Styles/Mod 65% Style.tres new file mode 100644 index 0000000..fed827f --- /dev/null +++ b/Runtime/UI/Presets/Styles/Mod 65% Style.tres @@ -0,0 +1,14 @@ +[gd_resource type="Resource" script_class="UIStyle" load_steps=4 format=3 uid="uid://buoilu1x43rnx"] + +[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_26sog"] +[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_tgj76"] + +[sub_resource type="Resource" id="Resource_nam1h"] +script = ExtResource("1_26sog") +color = Color(1, 1, 1, 0.7019608) +metadata/_custom_type_script = "uid://drqb0pm5ub64g" + +[resource] +script = ExtResource("2_tgj76") +modulationColor = SubResource("Resource_nam1h") +metadata/_custom_type_script = "uid://chmcc71dvu4vj" diff --git a/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres b/Runtime/UI/Presets/Styles/Mod 80% Style.tres similarity index 86% rename from Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres rename to Runtime/UI/Presets/Styles/Mod 80% Style.tres index 0b03ac5..4824395 100644 --- a/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres +++ b/Runtime/UI/Presets/Styles/Mod 80% Style.tres @@ -1,14 +1,14 @@ [gd_resource type="Resource" script_class="UIStyle" load_steps=4 format=3 uid="uid://cy7m6e0be3mqw"] -[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_5k4i7"] -[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_qkfun"] +[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_0vahf"] +[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_rh1lc"] [sub_resource type="Resource" id="Resource_wxaam"] -script = ExtResource("1_5k4i7") +script = ExtResource("1_0vahf") color = Color(1, 1, 1, 0.80784315) metadata/_custom_type_script = "uid://drqb0pm5ub64g" [resource] -script = ExtResource("2_qkfun") +script = ExtResource("2_rh1lc") modulationColor = SubResource("Resource_wxaam") metadata/_custom_type_script = "uid://chmcc71dvu4vj" diff --git a/Runtime/UI/Styling/UINumber.cs b/Runtime/UI/Styling/UINumber.cs index b748582..df371f6 100644 --- a/Runtime/UI/Styling/UINumber.cs +++ b/Runtime/UI/Styling/UINumber.cs @@ -690,7 +690,7 @@ namespace Rokojori return false; } - var lexer = new CSharpLexer(); + var lexer = new CSLexer(); var list = lexer.LexToList( expressionText ); diff --git a/Runtime/UI/Styling/UISelectorStyle.cs b/Runtime/UI/Styling/UIRule.cs similarity index 62% rename from Runtime/UI/Styling/UISelectorStyle.cs rename to Runtime/UI/Styling/UIRule.cs index 78f8ecc..e616db9 100644 --- a/Runtime/UI/Styling/UISelectorStyle.cs +++ b/Runtime/UI/Styling/UIRule.cs @@ -7,8 +7,8 @@ namespace Rokojori { [Tool] - [GlobalClass] - public partial class UISelectorStyle:Resource + [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIRule.svg")] + public partial class UIRule:Resource { [Export] public UISelector selector; diff --git a/Runtime/UI/Styling/UIRule.cs.uid b/Runtime/UI/Styling/UIRule.cs.uid new file mode 100644 index 0000000..5342e39 --- /dev/null +++ b/Runtime/UI/Styling/UIRule.cs.uid @@ -0,0 +1 @@ +uid://8eihwfc2acp1 diff --git a/Runtime/UI/Styling/UISelector.cs b/Runtime/UI/Styling/UISelector.cs index c4803de..06423e5 100644 --- a/Runtime/UI/Styling/UISelector.cs +++ b/Runtime/UI/Styling/UISelector.cs @@ -8,7 +8,7 @@ namespace Rokojori { [Tool] - [GlobalClass] + [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UISelector.svg")] public partial class UISelector:Resource { public enum Value @@ -46,9 +46,25 @@ namespace Rokojori return true; } + var containsFlag = container.GetUISelectorFlags().Contains( flag ); + var needsFlag = ( Value.True == value ); + + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( + // "Checking for flag", + // "container:", container, + // "value:",value, + // "flag:", flag, + // "containsFlag:", containsFlag, + // "needsFlag:", needsFlag + // ); + // } + + if ( Value.True == value || Value.False == value ) { - return container.GetUISelectorFlags().Contains( flag ) == ( Value.True == value ); + return containsFlag == needsFlag; } // if ( Value.True_For_Any_Parent == value || Value.False_For_All_Parents == value ) @@ -63,39 +79,93 @@ namespace Rokojori public bool Selects( UIStylePropertyContainer container ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( + + // "Context:", context, + + // "Hover:", hover, container.GetUISelectorFlags().Contains( UISelectorFlag.Hover ), + // "Dragging:", dragging, container.GetUISelectorFlags().Contains( UISelectorFlag.Dragging ), + // "Scrolling:", scrolling, container.GetUISelectorFlags().Contains( UISelectorFlag.Scrolling ), + // "Focus:", focus, container.GetUISelectorFlags().Contains( UISelectorFlag.Focus ), + // "Active:", active, container.GetUISelectorFlags().Contains( UISelectorFlag.Active ) + // ); + // } + if ( ! Matches( container, hover, UISelectorFlag.Hover ) ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "Hover not matching" ); + // } + return false; } if ( ! Matches( container, dragging, UISelectorFlag.Dragging ) ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context,"Dragging not matching" ); + // } return false; } if ( ! Matches( container, scrolling, UISelectorFlag.Scrolling ) ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "Scrolling not matching" ); + // } return false; } if ( ! Matches( container, focus, UISelectorFlag.Focus ) ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "Focus not matching" ); + // } return false; } + if ( ! Matches( container, active, UISelectorFlag.Active ) ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "Active not matching" ); + // } return false; } + if ( selectors == null || selectors.Length == 0 ) + { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "No selectors, everthing matched" ); + // } + return true; + } + foreach ( var entry in selectors ) { - if ( ! Matches( container, entry.value, entry.selectorFlag ) ) + if ( entry == null || ! Matches( container, entry.value, entry.selectorFlag ) ) { + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "flag selector not matching", entry.value, entry.selectorFlag ); + // } + return false; } } + // if ( container.HasDebugFlag() ) + // { + // this.LogInfo( context, "Flag Selectors matched" ); + // } return true; } diff --git a/Runtime/UI/Styling/UISelectorStyle.cs.uid b/Runtime/UI/Styling/UISelectorStyle.cs.uid deleted file mode 100644 index 5b85974..0000000 --- a/Runtime/UI/Styling/UISelectorStyle.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bqypmtxqo5rnf diff --git a/Runtime/UI/Styling/UIStyle.cs b/Runtime/UI/Styling/UIStyle.cs index bf8e515..f32bb38 100644 --- a/Runtime/UI/Styling/UIStyle.cs +++ b/Runtime/UI/Styling/UIStyle.cs @@ -9,9 +9,17 @@ namespace Rokojori { [Tool] - [GlobalClass] + [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIStyle.svg")] public partial class UIStyle:Resource, UIStylePropertyContainer { + [Export] + public bool activateDebugging = false; + + public bool HasDebugFlag() + { + return activateDebugging; + } + [ExportGroup( "Layout" )] [Export] public UILayout layout; @@ -201,11 +209,15 @@ namespace Rokojori public UICursor hoverCursor; - [ExportGroup( "Selectors & Parent " )] - + [ExportGroup( "Rules" )] [Export] - public UISelectorStyle[] selectorStyles = []; + public UIRuleSet[] ruleSets = []; + [Export] + public UIRule[] rules = []; + + + [ExportGroup( "Parent" )] [Export] public UIStyle parentStyle; @@ -216,16 +228,39 @@ namespace Rokojori public UICursor GetHoverCursor( UIStylePropertyContainer container ) { - for ( int i = 0; i < selectorStyles.Length; i++ ) + var uiCursor = GetHoverCursor( rules, container ); + + if ( uiCursor != null ) { - if ( selectorStyles[ i ] == null || selectorStyles[ i ].style == null ) + return uiCursor; + } + + for ( int j =0; j < ruleSets.Length; j++ ) + { + uiCursor = GetHoverCursor( ruleSets[ j ].rules, container ); + + if ( uiCursor != null ) + { + return uiCursor; + } + + } + + return hoverCursor; + } + + public UICursor GetHoverCursor( UIRule[] rules, UIStylePropertyContainer container ) + { + for ( int i = 0; i < rules.Length; i++ ) + { + if ( rules[ i ] == null || rules[ i ].style == null ) { continue; } - if ( selectorStyles[ i ].selector == null || selectorStyles[ i ].selector.Selects( container ) ) + if ( rules[ i ].selector == null || rules[ i ].selector.Selects( container ) ) { - var uiCursor = selectorStyles[ i ].style.GetHoverCursor( container ); + var uiCursor = rules[ i ].style.GetHoverCursor( container ); if ( uiCursor != null ) { @@ -234,7 +269,7 @@ namespace Rokojori } } - return hoverCursor; + return null; } @@ -296,16 +331,38 @@ namespace Rokojori public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property, string shaderPropertyName, UIStylePropertyContainer source ) { - for ( int i = 0; i < selectorStyles.Length; i++ ) + var uiNumber = GetUIStyleNumberProperty( rules, property, shaderPropertyName, source ); + + if ( uiNumber != null ) { - if ( selectorStyles[ i ] == null || selectorStyles[ i ].style == null ) + return uiNumber; + } + + for ( int i = 0; i < ruleSets.Length; i++ ) + { + uiNumber = GetUIStyleNumberProperty( ruleSets[ i ].rules, property, shaderPropertyName, source ); + + if ( uiNumber != null ) + { + return uiNumber; + } + } + + return GetUIStyleNumberProperty( property, shaderPropertyName ); + } + + public UINumber GetUIStyleNumberProperty( UIRule[] rules, UIStyleNumberProperty property, string shaderPropertyName, UIStylePropertyContainer source ) + { + for ( int i = 0; i < rules.Length; i++ ) + { + if ( rules[ i ] == null || rules[ i ].style == null ) { continue; } - if ( selectorStyles[ i ].selector == null || selectorStyles[ i ].selector.Selects( source ) ) + if ( rules[ i ].selector == null || rules[ i ].selector.Selects( source ) ) { - var selectedProperty = selectorStyles[ i ].style.GetUIStyleNumberProperty( property, shaderPropertyName ); + var selectedProperty = rules[ i ].style.GetUIStyleNumberProperty( property, shaderPropertyName ); if ( selectedProperty != null ) { @@ -314,7 +371,7 @@ namespace Rokojori } } - return GetUIStyleNumberProperty( property, shaderPropertyName ); + return null; } public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property, string shaderPropertyName ) @@ -445,17 +502,62 @@ namespace Rokojori public UIColor GetUIStyleColorProperty( UIStyleColorProperty property, string shaderPropertyName, UIStylePropertyContainer source ) { + var uiColor = UIColorFromRules( rules, property, shaderPropertyName, source ); - for ( int i = 0; i < selectorStyles.Length; i++ ) + if ( uiColor != null ) { - if ( selectorStyles[ i ] == null || selectorStyles[ i ].style == null ) + return uiColor; + } + + foreach ( var r in ruleSets ) + { + if ( r.rules == null ) { continue; } - if ( selectorStyles[ i ].selector == null || selectorStyles[ i ].selector.Selects( source ) ) + uiColor = UIColorFromRules( r.rules, property, shaderPropertyName, source ); + + if ( uiColor != null ) { - var selectedProperty = selectorStyles[ i ].style.GetUIStyleColorProperty( property, shaderPropertyName ); + return uiColor; + } + } + + + // for ( int i = 0; i < rules.Length; i++ ) + // { + // if ( rules[ i ] == null || rules[ i ].style == null ) + // { + // continue; + // } + + // if ( rules[ i ].selector == null || rules[ i ].selector.Selects( source, "color " + property ) ) + // { + // var selectedProperty = rules[ i ].style.GetUIStyleColorProperty( property, shaderPropertyName ); + + // if ( selectedProperty != null ) + // { + // return selectedProperty; + // } + // } + // } + + return GetUIStyleColorProperty( property, shaderPropertyName ); + } + + UIColor UIColorFromRules( UIRule[] rules, UIStyleColorProperty property, string shaderPropertyName, UIStylePropertyContainer source ) + { + for ( int i = 0; i < rules.Length; i++ ) + { + if ( rules[ i ] == null || rules[ i ].style == null ) + { + continue; + } + + if ( rules[ i ].selector == null || rules[ i ].selector.Selects( source ) ) + { + var selectedProperty = rules[ i ].style.GetUIStyleColorProperty( property, shaderPropertyName ); if ( selectedProperty != null ) { @@ -464,7 +566,7 @@ namespace Rokojori } } - return GetUIStyleColorProperty( property, shaderPropertyName ); + return null; } public UIColor GetUIStyleColorProperty( UIStyleColorProperty property, string shaderPropertyName ) diff --git a/Runtime/UI/Styling/UIStylePropertyContainer.cs b/Runtime/UI/Styling/UIStylePropertyContainer.cs index 53541b0..46425b5 100644 --- a/Runtime/UI/Styling/UIStylePropertyContainer.cs +++ b/Runtime/UI/Styling/UIStylePropertyContainer.cs @@ -7,6 +7,8 @@ namespace Rokojori { public interface UIStylePropertyContainer { + bool HasDebugFlag(); + UIStyle GetUIStyleParent(); void SetUIStyleParent( UIStyle uiStyle ); diff --git a/Runtime/UI/UI-Selectors/Presets/Active 100% Selector Style.tres b/Runtime/UI/UI-Selectors/Presets/Active 100% Selector Style.tres deleted file mode 100644 index 7152b35..0000000 --- a/Runtime/UI/UI-Selectors/Presets/Active 100% Selector Style.tres +++ /dev/null @@ -1,11 +0,0 @@ -[gd_resource type="Resource" script_class="UISelectorStyle" load_steps=4 format=3 uid="uid://cxq4cfdnk7c25"] - -[ext_resource type="Script" uid="uid://bqypmtxqo5rnf" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelectorStyle.cs" id="1_ytj2f"] -[ext_resource type="Resource" uid="uid://do3q5tipotyn3" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Active Selector.tres" id="2_r7shh"] -[ext_resource type="Resource" uid="uid://brjq22uvnpxuv" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres" id="3_x1wpc"] - -[resource] -script = ExtResource("1_ytj2f") -selector = ExtResource("2_r7shh") -style = ExtResource("3_x1wpc") -metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/UI-Selectors/Presets/Focus 100% Selector Style.tres b/Runtime/UI/UI-Selectors/Presets/Focus 100% Selector Style.tres deleted file mode 100644 index 5b42c62..0000000 --- a/Runtime/UI/UI-Selectors/Presets/Focus 100% Selector Style.tres +++ /dev/null @@ -1,11 +0,0 @@ -[gd_resource type="Resource" script_class="UISelectorStyle" load_steps=4 format=3 uid="uid://cvc0wabrro18q"] - -[ext_resource type="Script" uid="uid://bqypmtxqo5rnf" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelectorStyle.cs" id="1_2joc3"] -[ext_resource type="Resource" uid="uid://dgx4ue1pvvltj" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Focus Selector.tres" id="2_351ev"] -[ext_resource type="Resource" uid="uid://brjq22uvnpxuv" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres" id="3_46vc8"] - -[resource] -script = ExtResource("1_2joc3") -selector = ExtResource("2_351ev") -style = ExtResource("3_46vc8") -metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/UI-Selectors/Presets/Hover 80% Selector Style.tres b/Runtime/UI/UI-Selectors/Presets/Hover 80% Selector Style.tres deleted file mode 100644 index ba36786..0000000 --- a/Runtime/UI/UI-Selectors/Presets/Hover 80% Selector Style.tres +++ /dev/null @@ -1,11 +0,0 @@ -[gd_resource type="Resource" script_class="UISelectorStyle" load_steps=4 format=3 uid="uid://d15wkkwgtlh0n"] - -[ext_resource type="Script" uid="uid://bqypmtxqo5rnf" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelectorStyle.cs" id="1_a0wuj"] -[ext_resource type="Resource" uid="uid://cfctpa7mv11nj" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Hover Selector.tres" id="2_dm1hb"] -[ext_resource type="Resource" uid="uid://cy7m6e0be3mqw" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres" id="3_e4mab"] - -[resource] -script = ExtResource("1_a0wuj") -selector = ExtResource("2_dm1hb") -style = ExtResource("3_e4mab") -metadata/_custom_type_script = "uid://bqypmtxqo5rnf" diff --git a/Runtime/UI/UI.cs b/Runtime/UI/UI.cs index ab3dad0..e24d927 100644 --- a/Runtime/UI/UI.cs +++ b/Runtime/UI/UI.cs @@ -137,6 +137,18 @@ namespace Rokojori [Export] public Vector2 uiSize = Vector2.Zero; + + [ExportGroup("Actions")] + + [Export] + public Action onVisible; + + [Export] + public Action onInvisible; + + [Export] + public Action onVisibilityChanged; + [ExportGroup("Functions")] [ExportToolButton( "Mouse:Stop => Pass")] @@ -429,6 +441,22 @@ namespace Rokojori } UpdateUIInputs(); + + VisibilityChanged += ()=> + { + var visible = IsVisibleInTree(); + + if ( visible ) + { + onVisible?.Trigger(); + } + else + { + onInvisible?.Trigger(); + } + + onVisibilityChanged?.Trigger(); + }; } void UpdateUIInputs() @@ -661,13 +689,54 @@ namespace Rokojori player.Playing = true; } - - // public void Focus( Control control ) - // { - // var focusParent = - // while ( control ) - // } + public enum FocusOrderType + { + Vertical_List, + Horizontal_List, + Vertical_List_Wrapped, + Horizontal_List_Wrapped + } + + public static void SetChildFocusOrder( Node node, FocusOrderType type, List controls = null, FocusModeEnum focuseMode = FocusModeEnum.All ) + { + controls = controls ?? node.GetDirectChildren(); + + if ( FocusOrderType.Vertical_List == type || + FocusOrderType.Horizontal_List == type || + FocusOrderType.Vertical_List_Wrapped == type || + FocusOrderType.Horizontal_List_Wrapped == type + ) + { + var isHorizontal = FocusOrderType.Horizontal_List == type || FocusOrderType.Horizontal_List_Wrapped == type; + var wrap = FocusOrderType.Vertical_List_Wrapped == type || FocusOrderType.Horizontal_List_Wrapped == type; + + + for ( int i = 0; i < controls.Count; i++ ) + { + controls[ i ].FocusMode = focuseMode; + + var previousIndex = wrap ? MathX.Repeat( i - 1, controls.Count ) : Mathf.Clamp( i - 1, 0, controls.Count - 1 ); + var nextIndex = wrap ? MathX.Repeat( i + 1, controls.Count ) : Mathf.Clamp( i + 1, 0, controls.Count - 1 ); + + if ( isHorizontal ) + { + controls[ i ].FocusNeighborLeft = controls[ i ].GetPathTo( controls[ previousIndex ] ); + controls[ i ].FocusNeighborRight = controls[ i ].GetPathTo( controls[ nextIndex ] ); + controls[ i ].FocusNeighborTop = controls[ i ].GetPathTo( controls[ i ] ); + controls[ i ].FocusNeighborBottom = controls[ i ].GetPathTo( controls[ i ] ); + } + else + { + controls[ i ].FocusNeighborTop = controls[ i ].GetPathTo( controls[ previousIndex ] ); + controls[ i ].FocusNeighborBottom = controls[ i ].GetPathTo( controls[ nextIndex ] ); + controls[ i ].FocusNeighborLeft = controls[ i ].GetPathTo( controls[ i ] ); + controls[ i ].FocusNeighborRight = controls[ i ].GetPathTo( controls[ i ] ); + } + } + } + + } } } \ No newline at end of file diff --git a/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs b/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs index 9f4a7f6..50ef9c9 100644 --- a/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs +++ b/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs @@ -66,10 +66,12 @@ public partial class MinimalisticCategoryPagesGenerator:UIAppSettingsCategoryPag var scrollArea = page.CreateChild( "Scroll Area" ); scrollArea.parentStyle = scrollAreaStyle; + var focusControls = new List(); + category.settings.ForEach( ( setting )=> { - + var name = "- " + setting.title.currentValue; UIAppSettingHandler handler = null; @@ -98,12 +100,23 @@ public partial class MinimalisticCategoryPagesGenerator:UIAppSettingsCategoryPag label.locale = setting.title; label.parentStyle = appSettingLabelStyle; + Control focusControl = null; if ( setting is NumberAppSetting ) { var numberHandler = (UINumberAppSettingHandler) handler; - var numberController = handler.CreateChild( appSettingNumberController, "Number Handler" ); + var numberController = handler.CreateChild( appSettingNumberController, name + " Number Handler" ); numberHandler.slider = numberController.Get(); - numberHandler.slider.setActiveWhenFocused = [ handler ]; + numberHandler.slider.setActiveWhenFocused = [ handler, handlerBG, label, labelRegion ]; + + var setFocusedAction = handler.CreateChild( "Set Focused UI Setting" ); + numberHandler.slider.onFocusEntered = setFocusedAction; + + setFocusedAction.uiAppSettings = uiAppSettings; + setFocusedAction.appSettingHandler = numberHandler; + + focusControl = numberHandler.slider; + // focusControls.Add( numberHandler.slider ); + // handler.focusControl = numberHandler.slider; } @@ -112,11 +125,50 @@ public partial class MinimalisticCategoryPagesGenerator:UIAppSettingsCategoryPag var listHandler = (UIListAppSettingHandler) handler; var listController = handler.CreateChild( appSettingNumberController, "List Handler" ); listHandler.list = listController.Get(); - listHandler.list.setActiveWhenFocused = [ handler ]; + listHandler.list.setActiveWhenFocused = [ handler, handlerBG, label, labelRegion ]; + + var setFocusedAction = listHandler.list.CreateChild( "Set Focused UI Setting" ); + listHandler.list.onFocusEntered = setFocusedAction; + + setFocusedAction.uiAppSettings = uiAppSettings; + setFocusedAction.appSettingHandler = listHandler; + + focusControl = listHandler.list; + // focusControls.Add( listHandler.list ); + // handler.focusControl = listHandler.list; } + + focusControls.Add( focusControl ); + + handler.ForEach( + ( c )=> + { + if ( c == focusControl ) + { + return; + } + + if ( c is UIRegion r ) + { + r.focusControl = focusControl; + } + + if ( c is UIImage i ) + { + i.focusControl = focusControl; + } + + if ( c is UIText t ) + { + t.focusControl = focusControl; + } + } + ); } ); + UI.SetChildFocusOrder( page, UI.FocusOrderType.Vertical_List, focusControls, Control.FocusModeEnum.Click ); + var slider = page.CreateChild( "Scroll Area Slider" ); slider.scrollArea = scrollArea; slider.scrollContainer = page; diff --git a/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn b/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn index caca557..5f72c01 100644 --- a/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn +++ b/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=19 format=3 uid="uid://blvco0pityhm1"] +[gd_scene load_steps=18 format=3 uid="uid://blvco0pityhm1"] [ext_resource type="Script" uid="uid://c2hicupu28nbi" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIRegion.cs" id="1_1w55f"] [ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="2_xupgh"] @@ -7,7 +7,6 @@ [ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="5_v6jyw"] [ext_resource type="Script" uid="uid://b50yldymrhply" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs" id="6_28vtr"] [ext_resource type="Script" uid="uid://2ftd0bt6rrgo" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs" id="7_4f0b5"] -[ext_resource type="Script" uid="uid://b4yjsis2fh64c" path="res://addons/rokojori_action_library/Runtime/Actions/ActionList.cs" id="8_001d7"] [sub_resource type="Resource" id="Resource_7e4fb"] script = ExtResource("2_xupgh") @@ -15,7 +14,7 @@ value = 2.0 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="LabelSettings" id="LabelSettings_qiba2"] +[sub_resource type="LabelSettings" id="LabelSettings_ksam2"] [sub_resource type="Resource" id="Resource_o8r6f"] script = ExtResource("4_nso1f") @@ -32,7 +31,7 @@ value = 25.0 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="LabelSettings" id="LabelSettings_eoac7"] +[sub_resource type="LabelSettings" id="LabelSettings_001d7"] [sub_resource type="Resource" id="Resource_ewl2f"] script = ExtResource("4_nso1f") @@ -44,7 +43,7 @@ script = ExtResource("4_nso1f") en = "Other Value" metadata/_custom_type_script = "uid://bvj322mokkq63" -[sub_resource type="LabelSettings" id="LabelSettings_iajf2"] +[sub_resource type="LabelSettings" id="LabelSettings_qiba2"] [sub_resource type="Resource" id="Resource_jgo2j"] script = ExtResource("4_nso1f") @@ -79,11 +78,11 @@ offset_right = 17.02 offset_bottom = 17.0 pivot_offset = Vector2(5.5, 8.5) mouse_filter = 1 -label_settings = SubResource("LabelSettings_qiba2") +label_settings = SubResource("LabelSettings_ksam2") script = ExtResource("3_emuhf") locale = SubResource("Resource_o8r6f") -parentStyle = SubResource("Resource_4wsps") handleMouseEvents = true +parentStyle = SubResource("Resource_4wsps") [node name="ChangeUIListSelection" type="Node" parent="UIRegion2" node_paths=PackedStringArray("selection")] script = ExtResource("6_28vtr") @@ -109,13 +108,13 @@ offset_left = 97.48001 offset_right = 167.48001 offset_bottom = 17.0 pivot_offset = Vector2(35, 8.5) -label_settings = SubResource("LabelSettings_eoac7") +label_settings = SubResource("LabelSettings_001d7") script = ExtResource("7_4f0b5") values = [SubResource("Resource_ewl2f"), SubResource("Resource_swro7")] locale = SubResource("Resource_swro7") +onFocusEntered = NodePath("") +onFocusExited = NodePath("") parentStyle = SubResource("Resource_4wsps") -onFocusEntered = NodePath("../../On Focus Entered") -onFocusExited = NodePath("../../On Focus Exited") metadata/_custom_type_script = "uid://2ftd0bt6rrgo" [node name="UIRegion4" type="Control" parent="."] @@ -136,11 +135,11 @@ offset_right = 17.02 offset_bottom = 17.0 pivot_offset = Vector2(5.5, 8.5) mouse_filter = 1 -label_settings = SubResource("LabelSettings_iajf2") +label_settings = SubResource("LabelSettings_qiba2") script = ExtResource("3_emuhf") locale = SubResource("Resource_jgo2j") -parentStyle = SubResource("Resource_4wsps") handleMouseEvents = true +parentStyle = SubResource("Resource_4wsps") [node name="ChangeUIListSelection2" type="Node" parent="UIRegion4" node_paths=PackedStringArray("selection")] script = ExtResource("6_28vtr") @@ -148,11 +147,3 @@ selection = NodePath("../../UIRegion/UIListSelection") mode = 1 value = 1 metadata/_custom_type_script = "uid://b50yldymrhply" - -[node name="On Focus Entered" type="Node" parent="."] -script = ExtResource("8_001d7") -metadata/_custom_type_script = "uid://b4yjsis2fh64c" - -[node name="On Focus Exited" type="Node" parent="."] -script = ExtResource("8_001d7") -metadata/_custom_type_script = "uid://b4yjsis2fh64c" diff --git a/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn b/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn index 3b67bda..ab294fc 100644 --- a/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn +++ b/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=39 format=3 uid="uid://58yaanrblnvj"] +[gd_scene load_steps=38 format=3 uid="uid://58yaanrblnvj"] [ext_resource type="Script" uid="uid://c2hicupu28nbi" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIRegion.cs" id="1_ucjfr"] [ext_resource type="Script" uid="uid://1pymvcckklic" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/Slider/SliderMaterial.cs" id="2_rckb5"] @@ -14,9 +14,8 @@ [ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="11_dmue3"] [ext_resource type="Script" uid="uid://cdsqunj017b7y" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UICursor.cs" id="11_gdfkg"] [ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="12_obxtq"] -[ext_resource type="Script" uid="uid://b4yjsis2fh64c" path="res://addons/rokojori_action_library/Runtime/Actions/ActionList.cs" id="15_v3vxy"] -[sub_resource type="ShaderMaterial" id="ShaderMaterial_op7xn"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_7abrn"] shader = ExtResource("3_ca53k") shader_parameter/opacity = 1.0 shader_parameter/blendLinear = false @@ -44,28 +43,29 @@ shader_parameter/sliderStrokeColor = Color(0, 0, 0, 1) shader_parameter/sliderStrokeSize = 2.0 script = ExtResource("2_rckb5") -[sub_resource type="Resource" id="Resource_ebf7l"] +[sub_resource type="Resource" id="Resource_vh1c2"] script = ExtResource("6_1gbfa") max = 100.0 metadata/_custom_type_script = "uid://bsonpc71ochpe" -[sub_resource type="Resource" id="Resource_gdfkg"] +[sub_resource type="Resource" id="Resource_v3vxy"] +resource_local_to_scene = true script = ExtResource("7_pjx5d") frames = 20.0 metadata/_custom_type_script = "uid://lhuuedx87rem" -[sub_resource type="Resource" id="Resource_pv02u"] +[sub_resource type="Resource" id="Resource_7e4fb"] script = ExtResource("7_sr7fn") value = 1.0 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="Resource" id="Resource_412gp"] +[sub_resource type="Resource" id="Resource_o8r6f"] script = ExtResource("8_74lu0") color = Color(0.3090081, 0.3473884, 0.40495878, 1) metadata/_custom_type_script = "uid://drqb0pm5ub64g" -[sub_resource type="Resource" id="Resource_pp0bs"] +[sub_resource type="Resource" id="Resource_73e3n"] script = ExtResource("7_sr7fn") value = 0.334 unit = "em" @@ -75,25 +75,25 @@ metadata/_custom_type_script = "uid://cnkyynboxg1qg" script = ExtResource("8_74lu0") metadata/_custom_type_script = "uid://drqb0pm5ub64g" -[sub_resource type="Resource" id="Resource_ubijs"] +[sub_resource type="Resource" id="Resource_t0qj0"] script = ExtResource("7_sr7fn") value = 0.598 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="Resource" id="Resource_dq7d0"] +[sub_resource type="Resource" id="Resource_tl71m"] script = ExtResource("7_sr7fn") value = 1.2525 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="Resource" id="Resource_tdk3c"] +[sub_resource type="Resource" id="Resource_y37jp"] script = ExtResource("7_sr7fn") value = 0.6355 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="Resource" id="Resource_p7jqt"] +[sub_resource type="Resource" id="Resource_7e1wh"] script = ExtResource("8_74lu0") color = Color(1, 1, 1, 0) metadata/_custom_type_script = "uid://drqb0pm5ub64g" @@ -103,64 +103,64 @@ script = ExtResource("8_74lu0") color = Color(1, 1, 1, 0) metadata/_custom_type_script = "uid://drqb0pm5ub64g" -[sub_resource type="Resource" id="Resource_q8n2a"] +[sub_resource type="Resource" id="Resource_n64ds"] script = ExtResource("7_sr7fn") unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="Resource" id="Resource_loqre"] +[sub_resource type="Resource" id="Resource_oxa7j"] script = ExtResource("9_jpqb0") -fillColor = SubResource("Resource_412gp") +fillColor = SubResource("Resource_o8r6f") strokeColor = SubResource("Resource_ioimv") -borderRadius = SubResource("Resource_pv02u") -strokeSize = SubResource("Resource_q8n2a") -sliderSizeX = SubResource("Resource_dq7d0") -sliderSizeY = SubResource("Resource_tdk3c") -sliderSizeMarginX = SubResource("Resource_ubijs") -sliderBorderRadius = SubResource("Resource_pp0bs") +borderRadius = SubResource("Resource_7e4fb") +strokeSize = SubResource("Resource_n64ds") +sliderSizeX = SubResource("Resource_tl71m") +sliderSizeY = SubResource("Resource_y37jp") +sliderSizeMarginX = SubResource("Resource_t0qj0") +sliderBorderRadius = SubResource("Resource_73e3n") sliderFillColor = SubResource("Resource_t2h31") -sliderStrokeColor = SubResource("Resource_p7jqt") - -[sub_resource type="Resource" id="Resource_jhmds"] -script = ExtResource("7_sr7fn") -value = 20.0 -unit = "em" -metadata/_custom_type_script = "uid://cnkyynboxg1qg" - -[sub_resource type="Resource" id="Resource_mseeg"] -script = ExtResource("7_sr7fn") -value = 1.0 -unit = "em" -metadata/_custom_type_script = "uid://cnkyynboxg1qg" +sliderStrokeColor = SubResource("Resource_7e1wh") [sub_resource type="Resource" id="Resource_44lr4"] script = ExtResource("11_gdfkg") metadata/_custom_type_script = "uid://cdsqunj017b7y" -[sub_resource type="Resource" id="Resource_drk6d"] +[sub_resource type="Resource" id="Resource_oluvp"] script = ExtResource("7_sr7fn") -value = 100.0 -unit = "%" +value = 20.0 +unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="Resource" id="Resource_jtfq4"] +[sub_resource type="Resource" id="Resource_vi7gu"] +script = ExtResource("7_sr7fn") +value = 1.0 +unit = "em" +metadata/_custom_type_script = "uid://cnkyynboxg1qg" + +[sub_resource type="Resource" id="Resource_5kble"] script = ExtResource("7_sr7fn") value = 10.0 unit = "em" metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="LabelSettings" id="LabelSettings_to3ck"] +[sub_resource type="Resource" id="Resource_swm2d"] +script = ExtResource("7_sr7fn") +value = 100.0 +unit = "%" +metadata/_custom_type_script = "uid://cnkyynboxg1qg" + +[sub_resource type="LabelSettings" id="LabelSettings_gdfkg"] [sub_resource type="Resource" id="Resource_r7l7h"] script = ExtResource("11_dmue3") en = "Test" metadata/_custom_type_script = "uid://bvj322mokkq63" -[sub_resource type="Resource" id="Resource_4wsps"] +[sub_resource type="Resource" id="Resource_8imgn"] script = ExtResource("12_obxtq") metadata/_custom_type_script = "uid://chmcc71dvu4vj" -[sub_resource type="Resource" id="Resource_mk81p"] +[sub_resource type="Resource" id="Resource_4mpx2"] script = ExtResource("7_sr7fn") value = 10.0 unit = "vw" @@ -178,27 +178,28 @@ script = ExtResource("1_ucjfr") metadata/_custom_type_script = "uid://c2hicupu28nbi" [node name="UIValueSlider" type="TextureRect" parent="." node_paths=PackedStringArray("valueText", "onFocusEntered", "onFocusExited")] -material = SubResource("ShaderMaterial_op7xn") +material = SubResource("ShaderMaterial_7abrn") layout_mode = 0 offset_top = 2.7399998 offset_right = 230.40001 offset_bottom = 14.26 pivot_offset = Vector2(115.200005, 5.76) -focus_mode = 2 +focus_mode = 1 +mouse_default_cursor_shape = 10 texture = ExtResource("4_vb488") expand_mode = 1 script = ExtResource("5_p2b8g") valueText = NodePath("../UIRegion2/Value") -mode = SubResource("Resource_ebf7l") +mode = SubResource("Resource_vh1c2") direction = 1 -smoothing = SubResource("Resource_gdfkg") +smoothing = SubResource("Resource_v3vxy") sliderValue = Vector2(0.5, 0.5) -imageType = SubResource("Resource_loqre") -width = SubResource("Resource_jhmds") -height = SubResource("Resource_mseeg") +imageType = SubResource("Resource_oxa7j") hoverCursor = SubResource("Resource_44lr4") -onFocusEntered = NodePath("../On Focus Entered") -onFocusExited = NodePath("../On Focus Exited") +onFocusEntered = NodePath("") +onFocusExited = NodePath("") +width = SubResource("Resource_oluvp") +height = SubResource("Resource_vi7gu") metadata/_custom_type_script = "uid://cqi3jitprf7o0" [node name="UIRegion2" type="Control" parent="."] @@ -209,8 +210,8 @@ offset_bottom = 17.0 pivot_offset = Vector2(40.32, 8.5) mouse_filter = 1 script = ExtResource("1_ucjfr") -horizontalAlignment = SubResource("Resource_drk6d") -width = SubResource("Resource_jtfq4") +width = SubResource("Resource_5kble") +horizontalAlignment = SubResource("Resource_swm2d") metadata/_custom_type_script = "uid://c2hicupu28nbi" [node name="Value" type="Label" parent="UIRegion2"] @@ -219,17 +220,8 @@ offset_left = 55.64 offset_right = 80.64 offset_bottom = 17.0 pivot_offset = Vector2(12.5, 8.5) -text = "Test" -label_settings = SubResource("LabelSettings_to3ck") +label_settings = SubResource("LabelSettings_gdfkg") script = ExtResource("10_58ifk") locale = SubResource("Resource_r7l7h") -parentStyle = SubResource("Resource_4wsps") -width = SubResource("Resource_mk81p") - -[node name="On Focus Entered" type="Node" parent="."] -script = ExtResource("15_v3vxy") -metadata/_custom_type_script = "uid://b4yjsis2fh64c" - -[node name="On Focus Exited" type="Node" parent="."] -script = ExtResource("15_v3vxy") -metadata/_custom_type_script = "uid://b4yjsis2fh64c" +parentStyle = SubResource("Resource_8imgn") +width = SubResource("Resource_4mpx2") diff --git a/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs b/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs index 2cca47d..0b18571 100644 --- a/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs +++ b/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs @@ -9,8 +9,7 @@ namespace Rokojori; [Tool] [GlobalClass] public partial class MinimalisticHeaderGenerator:UIAppSettingsHeaderGenerator -{ - +{ [Export] public UIStyle headerStyle; @@ -36,6 +35,33 @@ public partial class MinimalisticHeaderGenerator:UIAppSettingsHeaderGenerator [Export] public UIStyle categoryLabelStyle; + [Export] + public UIStyle footerStyle; + + [Export] + public UIStyle footerBackgroundStyle; + + [Export] + public UIImageType footerBackgroundImageType; + + [Export] + public UIStyle footerSeperatorStyle; + + [Export] + public bool showSettingsInfo = true; + + [Export] + public SensorIcon[] confirmIcons; + + [Export] + public LocalizedString confirmLocale; + + [Export] + public SensorIcon[] cancelIcons; + + [Export] + public LocalizedString cancelLocale; + public override UIAppSettingsHeader GenerateHeader( UIAppSettings uiAppSettings, AppSettings appSettings ) { @@ -79,6 +105,7 @@ public partial class MinimalisticHeaderGenerator:UIAppSettingsHeaderGenerator selector.uiStylable = categoryRegion; selector.uiAppSettings = uiAppSettings; selector.category = category; + selector.triggerMode = Action.ActionTriggerMode.Always; label.handleMouseEvents = true; label.onLeftClick = selector; @@ -94,6 +121,47 @@ public partial class MinimalisticHeaderGenerator:UIAppSettingsHeaderGenerator rightInfo.inputIcons = [ rightIcon ]; rightInfo.deviceFilter = new LastActiveDeviceFilter(); + var footer = uiAppSettings.CreateChild( "Footer"); + footer.parentStyle = footerStyle; + + ignores.Add( footer ); + + var footerBackground = footer.CreateChild( "Footer Background" ); + footerBackground.parentStyle = footerBackgroundStyle; + footerBackground.imageType = footerBackgroundImageType; + footerBackground.Texture = UI.whiteTexture.Get(); + + if ( showSettingsInfo ) + { + var uiSettings = uiAppSettings.GetUI().settings; + var settingsInfo = footer.CreateChild( "Settings Input "); + settingsInfo.inputIcons = [ + SensorIcon.Create( uiSettings.uiLeft ), + SensorIcon.Create( uiSettings.uiRight ) + ]; + + settingsInfo.locale = LocaleText.Create( "Change setting" ); + settingsInfo.deviceFilter = new LastActiveDeviceFilter(); + header.settingsInputInfo = settingsInfo; + + var separatorSettings = footer.CreateChild( "Separator (Settings and Confirm)" ); + separatorSettings.parentStyle = footerSeperatorStyle; + + } + + var confirmInfo = footer.CreateChild( "Confirm Input "); + confirmInfo.inputIcons = confirmIcons; + confirmInfo.locale = confirmLocale; + confirmInfo.deviceFilter = new LastActiveDeviceFilter(); + + var confirmSettings = footer.CreateChild( "Separator (Confirm and Cancel)" ); + confirmSettings.parentStyle = footerSeperatorStyle; + + var cancelInfo = footer.CreateChild( "Cancel Input "); + cancelInfo.inputIcons = cancelIcons; + cancelInfo.locale = cancelLocale; + cancelInfo.deviceFilter = new LastActiveDeviceFilter(); + return header; } diff --git a/Runtime/UI/UIAppSettings/Headers/SetFocusedUIAppSettings.cs b/Runtime/UI/UIAppSettings/Headers/SetFocusedUIAppSettings.cs new file mode 100644 index 0000000..58b2372 --- /dev/null +++ b/Runtime/UI/UIAppSettings/Headers/SetFocusedUIAppSettings.cs @@ -0,0 +1,39 @@ + +using Godot; +using Rokojori; +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +[Tool] +[GlobalClass] +public partial class SetFocusedUIAppSettings:Action +{ + [Export] + public UIAppSettings uiAppSettings; + + [Export] + public UIAppSettingHandler appSettingHandler; + + protected override void _OnTrigger() + { + if ( uiAppSettings == null || appSettingHandler == null ) + { + return; + } + + var header = uiAppSettings.header; + + if ( header.settingsInputInfo == null || + appSettingHandler.appSetting == null || + appSettingHandler.appSetting.title == null + ) + { + return; + } + + header.settingsInputInfo.locale = appSettingHandler.appSetting.title; + header.settingsInputInfo.UpdateInfo(); + } +} diff --git a/Runtime/UI/UIAppSettings/Headers/SetFocusedUIAppSettings.cs.uid b/Runtime/UI/UIAppSettings/Headers/SetFocusedUIAppSettings.cs.uid new file mode 100644 index 0000000..9d8d886 --- /dev/null +++ b/Runtime/UI/UIAppSettings/Headers/SetFocusedUIAppSettings.cs.uid @@ -0,0 +1 @@ +uid://bd0j3solon12a diff --git a/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs index ca632ca..68c5251 100644 --- a/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs +++ b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs @@ -12,4 +12,7 @@ public partial class UIAppSettingsHeader:UIRegion { [Export] public SelectSettingsPage[] pageSelectors = []; + + [Export] + public UIInputInfo settingsInputInfo; } diff --git a/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs b/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs index 3b0da67..b16efb6 100644 --- a/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs +++ b/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs @@ -22,5 +22,6 @@ public partial class SetUIAppSettingsReady : Action } uiAppSettings.onReady = newReadyAction; + uiAppSettings.SelectFirstPage(); } } diff --git a/Runtime/UI/UIAppSettings/UIAppSettings.cs b/Runtime/UI/UIAppSettings/UIAppSettings.cs index 091ff1c..1e15f48 100644 --- a/Runtime/UI/UIAppSettings/UIAppSettings.cs +++ b/Runtime/UI/UIAppSettings/UIAppSettings.cs @@ -63,6 +63,26 @@ public partial class UIAppSettings:UIRegion ProcessMainInputs(); } + public void SelectFirstPage() + { + if ( header == null ) + { + this.LogInfo( "No header" ); + return; + } + + + var selector = header.Get(); + + if ( selector == null ) + { + this.LogInfo( "No SelectSettingsPage in header found" ); + return; + } + + selector.Trigger(); + } + void ProcessMenuInputs() { if ( MenuChangeMode.None == menuChangeMode ) diff --git a/Runtime/UI/UIRuleSet.cs b/Runtime/UI/UIRuleSet.cs new file mode 100644 index 0000000..9d73249 --- /dev/null +++ b/Runtime/UI/UIRuleSet.cs @@ -0,0 +1,16 @@ + +using Godot; +using Rokojori; +using System.Collections.Generic; + +namespace Rokojori +{ + + [Tool] + [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIRuleSet.svg")] + public partial class UIRuleSet:Resource + { + [Export] + public UIRule[] rules = []; + } +} \ No newline at end of file diff --git a/Runtime/UI/UIRuleSet.cs.uid b/Runtime/UI/UIRuleSet.cs.uid new file mode 100644 index 0000000..58af4d9 --- /dev/null +++ b/Runtime/UI/UIRuleSet.cs.uid @@ -0,0 +1 @@ +uid://cyr5imepel4p0 diff --git a/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs b/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs index 24d39c6..a56e45c 100644 --- a/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs +++ b/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs @@ -6,6 +6,9 @@ namespace Rokojori; [Tool,GlobalClass] public partial class CustomLineMaterialPreset:LineMaterialPreset { + [Export( PropertyHint.Range, "0.001,128")] + public float lodBias = 1; + [Export] public Material material; @@ -17,7 +20,12 @@ public partial class CustomLineMaterialPreset:LineMaterialPreset public override void CreateMaterial( LineVFX lineVFX, MeshInstance3D mi ) { - mi.SetSurfaceOverrideMaterial( 0, material ); + for ( int i = 0; i < mi.GetSurfaceOverrideMaterialCount(); i++ ) + { + mi.SetSurfaceOverrideMaterial( i, material ); + } + + mi.LodBias = lodBias; mi.CastShadow = shadows; } @@ -32,4 +40,9 @@ public partial class CustomLineMaterialPreset:LineMaterialPreset shaderSetup.end.Set( mi, data ); } } + + public override void SetLineLength( LineVFX lineVFX, MeshInstance3D mi, float length ) + { + shaderSetup.lineLength.SetInstance( mi, length ); + } } diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs b/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs index cefde77..cef0883 100644 --- a/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs +++ b/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs @@ -8,4 +8,5 @@ public abstract partial class LineMaterialPreset:Resource { public abstract void CreateMaterial( LineVFX lineVFX, MeshInstance3D mi ); public abstract void SetPointData( LineVFX lineVFX, MeshInstance3D mi, LinePointData data, bool start ); + public abstract void SetLineLength( LineVFX lineVFX, MeshInstance3D mi, float length ); } diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs index 92dfb1a..c4d3c6d 100644 --- a/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs +++ b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs @@ -13,6 +13,9 @@ public partial class LineVFXShaderSetup:Resource [Export] public LineVFXShaderPointProperties end; + [Export] + public FloatPropertyName lineLength; + } \ No newline at end of file diff --git a/Runtime/VFX/LineVFX/LineMaterial/Shaders/PBR/LineVFX-PBR.gdshader b/Runtime/VFX/LineVFX/LineMaterial/Shaders/PBR/LineVFX-PBR.gdshader new file mode 100644 index 0000000..5e9b03f --- /dev/null +++ b/Runtime/VFX/LineVFX/LineMaterial/Shaders/PBR/LineVFX-PBR.gdshader @@ -0,0 +1,60 @@ +shader_type spatial; +render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx; + +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc" + +uniform sampler2D albedoTexture : source_color, filter_linear_mipmap, repeat_enable; +uniform vec4 albedo : source_color; + +uniform sampler2D occlusionTexture : hint_roughness_r, filter_linear_mipmap, repeat_enable; +uniform float occlusion : hint_range(0.0, 1.0); + +uniform sampler2D roughnessTexture : hint_roughness_r, filter_linear_mipmap, repeat_enable; +uniform float roughness : hint_range(0.0, 1.0); + +uniform sampler2D metallicTexture : hint_default_white, filter_linear_mipmap, repeat_enable; +uniform float metallic : hint_range(0.0, 1.0, 0.01); +uniform float specular : hint_range(0.0, 1.0, 0.01); + + +uniform sampler2D normalTexture : hint_roughness_normal, filter_linear_mipmap, repeat_enable; +uniform float normalScale : hint_range(-16.0, 16.0); + +uniform vec2 uvScale; +uniform vec2 uvOffset; + +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc" + +void vertex() +{ + t = VERTEX.z; + normalizedDistance = mix( startNormalizedDistance, endNormalizedDistance, t ); + VERTEX.z = 0.0; + + VERTEX *= scaling; + + UV = UV * uvScale + uvOffset; + + #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc" + +} + +void fragment() +{ + vec4 sampledAlbedo = texture( albedoTexture, UV ); + ALBEDO = sampledAlbedo.rgb * albedo.rgb; + + float sampledOcclusion = texture( occlusionTexture, UV ).r; + AO = mix( 1.0, sampledOcclusion, occlusion ); + + float sampledRoughness = texture( roughnessTexture, UV ).g; + ROUGHNESS = sampledRoughness * roughness; + + + float sampledMetallic = texture( metallicTexture, UV ).b; + METALLIC = sampledMetallic * metallic; + SPECULAR = specular; + + NORMAL_MAP = texture( normalTexture, UV ).rgb; + NORMAL_MAP_DEPTH = normalScale; +} \ No newline at end of file diff --git a/Runtime/VFX/LineVFX/LineMaterial/Shaders/PBR/LineVFX-PBR.gdshader.uid b/Runtime/VFX/LineVFX/LineMaterial/Shaders/PBR/LineVFX-PBR.gdshader.uid new file mode 100644 index 0000000..ac19770 --- /dev/null +++ b/Runtime/VFX/LineVFX/LineMaterial/Shaders/PBR/LineVFX-PBR.gdshader.uid @@ -0,0 +1 @@ +uid://by77we1xqapem diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshEntry.cs b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshEntry.cs new file mode 100644 index 0000000..d6e4886 --- /dev/null +++ b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshEntry.cs @@ -0,0 +1,16 @@ +using Godot; +using System.Collections.Generic; + +namespace Rokojori; + +[Tool,GlobalClass] +public partial class RandomLineMeshEntry:Resource +{ + [Export] + public Mesh mesh; + + [Export] + public float probability = 1f; + + +} \ No newline at end of file diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshEntry.cs.uid b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshEntry.cs.uid new file mode 100644 index 0000000..1ba5649 --- /dev/null +++ b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshEntry.cs.uid @@ -0,0 +1 @@ +uid://dkyyo6mocdwd7 diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshGenerator.cs b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshGenerator.cs new file mode 100644 index 0000000..0597200 --- /dev/null +++ b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshGenerator.cs @@ -0,0 +1,19 @@ +using Godot; +using System.Collections.Generic; +using System.Linq; + +namespace Rokojori; + +[Tool,GlobalClass] +public partial class RandomLineMeshGenerator:LineMeshGenerator +{ + [Export] + public RandomLineMeshEntry[] entries = []; + + public override Mesh GetMesh( LineVFX lineVFX, MeshInstance3D mi ) + { + var entry = GodotRandom.Get().FromWeightedElements( entries, e => e.probability ); + return entry.mesh; + } + +} \ No newline at end of file diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshGenerator.cs.uid b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshGenerator.cs.uid new file mode 100644 index 0000000..1257aad --- /dev/null +++ b/Runtime/VFX/LineVFX/LineMeshGenerator/RandomLineMeshGenerator.cs.uid @@ -0,0 +1 @@ +uid://4wenko3thpc1 diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs index 0945d4d..90289ec 100644 --- a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs +++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs @@ -3,14 +3,17 @@ using System.Collections.Generic; namespace Rokojori; + [Tool] [GlobalClass ] public abstract partial class AutoLinePointList:LinePointDataGenerator { + [Export] + public bool computeUp = true; [Export] - public Vector3 up = Vector3.Up; + public SplineUpGeneratorStrategy upGeneratorStrategy; [Export( PropertyHint.Range, "0,1")] public float symmetricTangents = 0; @@ -30,6 +33,9 @@ public abstract partial class AutoLinePointList:LinePointDataGenerator [Export] public float changeTreshold = 0.000001f; + [Export] + public float currentLineLength = 0; + List _cachedPoints = []; protected abstract void _UpdatePoints( LineVFX lineVFX, double delta ); @@ -99,11 +105,34 @@ public abstract partial class AutoLinePointList:LinePointDataGenerator } + data.lineLength = length; + + currentLineLength = length; + for ( int i = 1; i < data.points.Length; i++ ) { data.points[ i ].normalizedDistance /= length; } + var strategy = upGeneratorStrategy ?? WorldUp_SplineUpGen.instance; + + var currentIndex = 0; + + System.Func getPosition = ( offset ) => + { + return data.points[ currentIndex - offset ].position; + }; + + System.Func getForward = ( offset ) => + { + return data.points[ currentIndex - offset ].forward; + }; + + System.Func getUp = ( offset ) => + { + return data.points[ currentIndex - offset ].up; + }; + for ( int i = 0; i < data.points.Length && data.points.Length > 1 ; i++ ) { if ( i == data.points.Length - 1 ) @@ -136,8 +165,12 @@ public abstract partial class AutoLinePointList:LinePointDataGenerator data.points[ i ].forward = ( before + after ) * 0.5f; } - - data.points[ i ].up = up; + + if ( computeUp ) + { + currentIndex = i; + data.points[ i ].up = strategy.ComputeUp( i, getPosition, getForward, getUp ); + } } _symmetricTangents = symmetricTangents; diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs index 4a7b15b..34d4940 100644 --- a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs +++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs @@ -9,6 +9,11 @@ public class AutoLineVFXData:LineVFXData public List pointsCacheList = []; public int customUpdateID = -1; + public float lineLength = 0f; + public override float GetLineLength() + { + return lineLength; + } public override int GetUpdateID(){ return customUpdateID; } public override IEnumerable GetPointData(){ return points; } diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs index 4902317..0f277bc 100644 --- a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs +++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs @@ -26,6 +26,8 @@ public partial class CustomLinePointList:LinePointDataGenerator cd.points = points; cd.customUpdateID = customUpdateID; + + cd.lineLength = Math3D.ComputeLineDistance( points, p => p.position ); } } diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs index 74a9e7d..d9bd2e5 100644 --- a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs +++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs @@ -9,6 +9,13 @@ public class CustomLineVFXData:LineVFXData public int customUpdateID = -1; + public float lineLength = 0f; + public override float GetLineLength() + { + return lineLength; + } + + public override int GetUpdateID(){ return customUpdateID; } public override IEnumerable GetPointData(){ return points; } public override int GetNumSegments() diff --git a/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs index 89899c1..daf0817 100644 --- a/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs +++ b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs @@ -30,12 +30,14 @@ public partial class FollowAutoLine:AutoLinePointList var newPosition = lineVFX.followSource.GlobalPosition; + var newUp = lineVFX.followSource.GlobalUp(); var needsNewPoint = NotEnoughPoints( points ) || Moved( newPosition, points ); if ( ! needsNewPoint ) { points[ points.Length -1 ].position = newPosition + Vector3.One * 0.00001f; + points[ points.Length -1 ].up = newUp; return; } @@ -44,7 +46,9 @@ public partial class FollowAutoLine:AutoLinePointList var p1 = new AutoLinePointData(); var p2 = new AutoLinePointData(); p1.position = newPosition; + p1.up = newUp; p2.position = newPosition + Vector3.One * 0.00001f; + p2.up = newUp; data.points = [ p1, p2 ]; @@ -53,12 +57,14 @@ public partial class FollowAutoLine:AutoLinePointList var p = new AutoLinePointData(); p.position = newPosition; + p.up = newUp; var pos2 = points[ points.Length - 2 ].position; var dir = newPosition - pos2; points[ points.Length - 1 ].position = pos2 + dir.Normalized() * distanceTreshold; + points[ points.Length - 1 ].up = newUp; if ( points.Length == maxPoints ) { diff --git a/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs b/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs index 04295de..5fe6da9 100644 --- a/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs +++ b/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs @@ -15,6 +15,8 @@ public abstract class LineVFXData } public abstract Vector3 GetPositionAt( int index ); + + public abstract float GetLineLength(); public Vector3 LerpPositionAt( float normalizedIndex ) { if ( GetNumPoints() == 0 ) diff --git a/Runtime/VFX/LineVFX/LineVFX.cs b/Runtime/VFX/LineVFX/LineVFX.cs index f1334d0..b9b8bb7 100644 --- a/Runtime/VFX/LineVFX/LineVFX.cs +++ b/Runtime/VFX/LineVFX/LineVFX.cs @@ -132,6 +132,7 @@ public partial class LineVFX:Node3D preset.materialPreset.SetPointData( this, mi, start, true ); preset.materialPreset.SetPointData( this, mi, end, false ); + preset.materialPreset.SetLineLength( this, mi, _data.GetLineLength() ); // AssignPointData( mi, start, startPositionName, startForwardName, startUpName ); // AssignPointData( mi, end, endPositionName, endForwardName, endUpName ); diff --git a/Tools/FFmpeg/FFmpeg.cs b/Tools/FFmpeg/FFmpeg.cs new file mode 100644 index 0000000..6da025c --- /dev/null +++ b/Tools/FFmpeg/FFmpeg.cs @@ -0,0 +1,129 @@ +#if TOOLS +using Godot; +using Rokojori; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading.Tasks; +using System; + +namespace Rokojori.Tools; + + +public class FFmpegResponse +{ + public int exitCode; + public string rawResponse; +} + +public class FFmpeg +{ + public static async Task Run( List arguments, string workingDirectory = null, string ffmpegPath = "ffmpeg" ) + { + var response = new FFmpegResponse(); + + var joinedArgs = arguments.Join( " "); + + RJLog.Log( "FFmpeg at", ffmpegPath, ">>", joinedArgs ); + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = ffmpegPath, + Arguments = joinedArgs, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + } + + }; + + if ( workingDirectory != null ) + { + process.StartInfo.WorkingDirectory = workingDirectory; + } + + process.Start(); + + var outputResult = new List(); + var errorResult = new List(); + + process.OutputDataReceived += (sender, e) => + { + if ( e.Data == null ) + { + return; + } + + RJLog.Log( e.Data ); + outputResult.Add( e.Data ); + }; + + process.ErrorDataReceived += (sender, e) => + { + if ( e.Data == null ) + { + return; + } + + RJLog.Error( e.Data ); + errorResult.Add( e.Data ); + }; + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + + await process.WaitForExitAsync(); + + + response.exitCode = process.ExitCode; + + if ( process.ExitCode == 0 ) + { + response.rawResponse = outputResult.Join( "" ); + } + else + { + response.rawResponse = errorResult.Join( "" ); + } + + return response; + } + + public static Task Convert_MP4_to_OGV( + string path, string ffmpegPath = "ffmpeg", + FFmpegQuality videoQuality = FFmpegQuality._8_Good, + FFmpegQuality audioQuality = FFmpegQuality._8_Good, + int keyFrames = 64, + int w = -1, int h = -1 + ) + { + // ffmpeg -i input.mp4 -vf "scale=-1:720" -q:v 6 -q:a 6 -g:v 64 output.ogv + + var args = new List(); + + args.Add( "-i " + path ); + + if ( ! ( w == -1 && h == -1 ) ) + { + args.Add( "-vf " + "\"scale=" + w + ":" + h + "\"" ); + } + + args.Add( "-q:v " + FFmpegQualityTool.ToInt( videoQuality ) ); + args.Add( "-q:a " + FFmpegQualityTool.ToInt( audioQuality ) ); + args.Add( "-g:v " + keyFrames ); + + var filePath = FilePath.Absolute( path ); + var outputPath = filePath.WithExtension( ".ogv" ); + args.Add( outputPath.absolutePath ); + + + return Run( args, null, ffmpegPath ); + } +} + + + +#endif \ No newline at end of file diff --git a/Tools/FFmpeg/FFmpeg.cs.uid b/Tools/FFmpeg/FFmpeg.cs.uid new file mode 100644 index 0000000..78296df --- /dev/null +++ b/Tools/FFmpeg/FFmpeg.cs.uid @@ -0,0 +1 @@ +uid://qsaa07g58o5t diff --git a/Tools/FFmpeg/FFmpegQuality.cs b/Tools/FFmpeg/FFmpegQuality.cs new file mode 100644 index 0000000..8d92c9e --- /dev/null +++ b/Tools/FFmpeg/FFmpegQuality.cs @@ -0,0 +1,37 @@ +#if TOOLS +using Godot; +using Rokojori; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading.Tasks; +using System; + +namespace Rokojori.Tools; + + + +public enum FFmpegQuality +{ + _1_Worst, + _2, + _3_Not_Good, + _4, + _5, + _6_Average, + _7, + _8_Good, + _9, + _10_Best +} + +public static class FFmpegQualityTool +{ + public static int ToInt( FFmpegQuality fFmpegQuality ) + { + return (int) fFmpegQuality + 1; + } +} + + + +#endif \ No newline at end of file diff --git a/Tools/FFmpeg/FFmpegQuality.cs.uid b/Tools/FFmpeg/FFmpegQuality.cs.uid new file mode 100644 index 0000000..149cf91 --- /dev/null +++ b/Tools/FFmpeg/FFmpegQuality.cs.uid @@ -0,0 +1 @@ +uid://dmkdmxwvbmx1e diff --git a/Tools/FFmpeg/FFmpegTool.cs b/Tools/FFmpeg/FFmpegTool.cs new file mode 100644 index 0000000..af7bd99 --- /dev/null +++ b/Tools/FFmpeg/FFmpegTool.cs @@ -0,0 +1,86 @@ +#if TOOLS +using Godot; +using Rokojori; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading.Tasks; +using System; + +namespace Rokojori.Tools; + +[Tool] +[GlobalClass] +public partial class FFmpegTool:Node +{ + [ExportToolButton("Download FFmpeg")] + public Callable downloadButton => Callable.From( + ()=> + { + var downloadPath = "https://ffmpeg.org/download.html"; + OS.ShellOpen( downloadPath ); + } + ); + + [Export( PropertyHint.GlobalFile, "exe" ) ] + public string ffmpegPath = ""; + + [Export] + public string result = ""; + + [ExportGroup("Convert MP4 to OGV")] + + [Export( PropertyHint.GlobalFile, "mp4" ) ] + public string mp4Path; + + [Export] + public FFmpegQuality videoQuality = FFmpegQuality._8_Good; + + [Export] + public FFmpegQuality audioQuality = FFmpegQuality._8_Good; + + [Export] + public int keyFrames = 64; + + [ExportToolButton("Convert")] + public Callable convert_MP4_to_OGV_Button => Callable.From( + ()=> + { + result = "Converting"; + Convert(); + } + ); + + async Task Convert() + { + var response = await FFmpeg.Convert_MP4_to_OGV( + mp4Path, ffmpegPath, + videoQuality, audioQuality, keyFrames + ); + + result = response.exitCode + ">> " + response.rawResponse; + } + + + // [ExportGroup("Show Video Info")] + + // [Export( PropertyHint.GlobalFile, "mp4" ) ] + // public string videoPath; + + // [ExportToolButton("Convert")] + // public Callable showVideoInfoButton => Callable.From( + // ()=> + // { + // ShowInfo(); + // } + // ); + + // async Task ShowInfo() + // { + // var response = await FFmpeg.Convert_MP4_to_OGV( mp4Path, ffmpegPath ); + + // result = response.exitCode + ">> " + response.rawResponse; + // } + +} + +#endif \ No newline at end of file diff --git a/Tools/FFmpeg/FFmpegTool.cs.uid b/Tools/FFmpeg/FFmpegTool.cs.uid new file mode 100644 index 0000000..7c09ba8 --- /dev/null +++ b/Tools/FFmpeg/FFmpegTool.cs.uid @@ -0,0 +1 @@ +uid://c1kb735pjfrf8 diff --git a/Tools/docs/ClassDocEditing/ClassDocParser.cs b/Tools/docs/ClassDocEditing/ClassDocParser.cs index e7dcd5e..304dbae 100644 --- a/Tools/docs/ClassDocEditing/ClassDocParser.cs +++ b/Tools/docs/ClassDocEditing/ClassDocParser.cs @@ -117,7 +117,7 @@ namespace Rokojori.DocGenerator } ); - var innerObjects = CSharpLexer.GetAllObjectDefinitions( innerTokens.events ); + var innerObjects = CSLexer.GetAllObjectDefinitions( innerTokens.events ); var objectRanges = innerObjects.Map( ( io )=> diff --git a/Tools/docs/CreateDoc.cs b/Tools/docs/CreateDoc.cs index 4d83eab..2dd3ad4 100644 --- a/Tools/docs/CreateDoc.cs +++ b/Tools/docs/CreateDoc.cs @@ -140,8 +140,8 @@ namespace Rokojori.DocGenerator var editor = new ClassDocEditor(); var source = found[ 0 ].LoadUTF8(); - editor.originalTokens = LexerList.Create( CSharpLexer.Lex( source ), LexerMatcherLibrary.Ignore ); - var objects = CSharpLexer.GetAllObjectDefinitions( editor.originalTokens.events ); + editor.originalTokens = LexerList.Create( CSLexer.Lex( source ), LexerMatcherLibrary.Ignore ); + var objects = CSLexer.GetAllObjectDefinitions( editor.originalTokens.events ); var classObject = objects.Find( obj => obj.type.Is( LexerMatcherLibrary.ClassMatcher ) ); editor.source = source; diff --git a/Tools/docs/DocComments.cs b/Tools/docs/DocComments.cs index 5362e08..13caf2f 100644 --- a/Tools/docs/DocComments.cs +++ b/Tools/docs/DocComments.cs @@ -32,7 +32,7 @@ namespace Rokojori.DocGenerator public void Grab( string data ) { - var lexEvents = CSharpLexer.Lex( data ); + var lexEvents = CSLexer.Lex( data ); //RJLog.Log( "Num lex events:", lexEvents.Count ); lexEvents.ForEach( diff --git a/Tools/docs/DocGenerator.cs b/Tools/docs/DocGenerator.cs index a25f54b..ec8cadd 100644 --- a/Tools/docs/DocGenerator.cs +++ b/Tools/docs/DocGenerator.cs @@ -119,7 +119,7 @@ namespace Rokojori.DocGenerator if ( cf.fileExtension == ".cs" ) { var fileContent = FilesSync.LoadUTF8( cf.fullPath ); - var definitions = CSharpLexer.GetAllObjectDefinitions( fileContent ); + var definitions = CSLexer.GetAllObjectDefinitions( fileContent ); // RJLog.Log( cf.fileName, ">>", definitions.Join( "," ) );