This commit is contained in:
MaidOpi
2026-05-10 22:29:56 +08:00
commit 0428927f5f
54 changed files with 15200 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<LangVersion>latest</LangVersion>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
<AssemblyName>Game</AssemblyName>
<RootNamespace>Game</RootNamespace>
<NoStandardLib>true</NoStandardLib>
<NoConfig>true</NoConfig>
<DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType>
<OutputPath>leanclr\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="scripts\**\*.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="mscorlib">
<HintPath>../thirdparty/leanclr/src/libraries/dotnetframework4.x-linux/mscorlib.dll</HintPath>
</Reference>
<Reference Include="System">
<HintPath>../thirdparty/leanclr/src/libraries/dotnetframework4.x-linux/System.dll</HintPath>
</Reference>
<Reference Include="GodotSharpCompat">
<HintPath>leanclr\GodotSharpCompat.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+21
View File
@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game.csproj", "{6CE2F047-6391-4EE7-87A3-4AD33A189355}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6CE2F047-6391-4EE7-87A3-4AD33A189355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CE2F047-6391-4EE7-87A3-4AD33A189355}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CE2F047-6391-4EE7-87A3-4AD33A189355}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CE2F047-6391-4EE7-87A3-4AD33A189355}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 995 B

+43
View File
@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://i0yc5j7xuf21"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
+14
View File
@@ -0,0 +1,14 @@
[configuration]
entry_symbol = "leanclr_godot_library_init"
compatibility_minimum = "4.4"
reloadable = true
[libraries]
windows.debug.x86_64 = "res://bin/Debug/leanclr_godot.dll"
windows.release.x86_64 = "res://bin/Release/leanclr_godot.dll"
linux.debug.x86_64 = "res://bin/Debug/libleanclr_godot.so"
linux.release.x86_64 = "res://bin/Release/libleanclr_godot.so"
macos.debug = "res://bin/Debug/libleanclr_godot.dylib"
macos.release = "res://bin/Release/libleanclr_godot.dylib"
+1
View File
@@ -0,0 +1 @@
uid://sbyqrdhnol0s
+11
View File
@@ -0,0 +1,11 @@
extends Node
func _ready() -> void:
var script := ResourceLoader.load("res://hello.lcs")
if script == null:
push_error("Failed to load LeanCLR hello.lcs")
get_tree().quit(1)
return
print("Loaded LeanCLR script: ", script.get_type_name())
get_tree().quit()
+1
View File
@@ -0,0 +1 @@
uid://bkcd2d6cuaxfs
+20
View File
@@ -0,0 +1,20 @@
[gd_scene load_steps=2 format=3 uid="uid://leanclr_godot_main"]
[ext_resource type="Script" path="res://scripts/ScriptMain.cs" id="1_leanclr"]
[node name="Main" type="LeanCLRMain"]
[node name="ScriptLanguageDemo" type="Node2D" parent="."]
script = ExtResource("1_leanclr")
[node name="Child" type="Node" parent="ScriptLanguageDemo"]
[node name="UiLabel" type="Label" parent="ScriptLanguageDemo"]
[node name="SpriteDemo" type="Sprite2D" parent="ScriptLanguageDemo"]
[node name="Node3DDemo" type="Node3D" parent="ScriptLanguageDemo"]
[node name="CpuParticles3DDemo" type="CPUParticles3D" parent="ScriptLanguageDemo"]
[node name="Camera3DDemo" type="Camera3D" parent="ScriptLanguageDemo"]
+19
View File
@@ -0,0 +1,19 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[animation]
compatibility/default_parent_skeleton_in_mesh_instance_3d=true
[application]
config/name="LeanCLR Godot"
run/main_scene="res://runtime_hot_reload_demo.tscn"
config/features=PackedStringArray("4.6")
+39
View File
@@ -0,0 +1,39 @@
[gd_scene format=3 uid="uid://dynd0csycincd"]
[ext_resource type="Script" uid="uid://b626vql61yl6r" path="res://scripts/RuntimeCSharpEditor.gd" id="1_editor_script"]
[node name="RuntimeCSharpEditor" type="Window" unique_id=440944382]
oversampling_override = 1.0
title = "LeanCLR Runtime C# Editor"
position = Vector2i(560, 36)
size = Vector2i(760, 560)
visible = false
always_on_top = true
script = ExtResource("1_editor_script")
[node name="RuntimeCSharpEditorPanel" type="VBoxContainer" parent="." unique_id=48727115]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="RuntimeCSharpTitle" type="Label" parent="RuntimeCSharpEditorPanel" unique_id=1798922565]
layout_mode = 2
text = "HotReloadSmoke.cs"
[node name="RuntimeCSharpCodeEdit" type="CodeEdit" parent="RuntimeCSharpEditorPanel" unique_id=2041813682]
unique_name_in_owner = true
custom_minimum_size = Vector2(720, 390)
layout_mode = 2
size_flags_vertical = 3
[node name="RuntimeCSharpRunButton" type="Button" parent="RuntimeCSharpEditorPanel" unique_id=1963029537]
unique_name_in_owner = true
layout_mode = 2
text = "Build + Execute Without Restart"
[node name="RuntimeCSharpStatus" type="Label" parent="RuntimeCSharpEditorPanel" unique_id=32725415]
unique_name_in_owner = true
layout_mode = 2
text = "Ready"
+78
View File
@@ -0,0 +1,78 @@
[gd_scene format=3 uid="uid://dom55c3dsfsh6"]
[ext_resource type="Script" uid="uid://bo2r8gbx576k6" path="res://scripts/HotReloadSmoke.cs" id="1_flappy"]
[ext_resource type="Texture2D" uid="uid://i0yc5j7xuf21" path="res://icon.svg" id="2_icon"]
[ext_resource type="PackedScene" uid="uid://dynd0csycincd" path="res://runtime_csharp_editor.tscn" id="3_editor_scene"]
[ext_resource type="Script" uid="uid://dca5khgessig" path="res://scripts/HotReloadInputRelay.gd" id="4_input_relay"]
[node name="RuntimeHotReloadDemo" type="Node2D" unique_id=1212946146]
[node name="GameWorld" type="Node2D" parent="." unique_id=914199522]
[node name="Sky" type="ColorRect" parent="GameWorld" unique_id=90320198]
offset_right = 540.0
offset_bottom = 360.0
color = Color(0.42, 0.78, 0.95, 1)
[node name="CloudA" type="ColorRect" parent="GameWorld" unique_id=1619648798]
offset_left = 76.0
offset_top = 44.0
offset_right = 168.0
offset_bottom = 66.0
color = Color(0.92, 0.97, 1, 1)
[node name="CloudB" type="ColorRect" parent="GameWorld" unique_id=329244074]
offset_left = 318.0
offset_top = 74.0
offset_right = 442.0
offset_bottom = 98.0
color = Color(0.92, 0.97, 1, 1)
[node name="PipeTop" type="ColorRect" parent="GameWorld" unique_id=1793488116]
offset_left = 420.0
offset_right = 480.0
offset_bottom = 92.0
color = Color(0.07, 0.63, 0.23, 1)
[node name="PipeBottom" type="ColorRect" parent="GameWorld" unique_id=422849216]
offset_left = 420.0
offset_top = 208.0
offset_right = 480.0
offset_bottom = 320.0
color = Color(0.07, 0.63, 0.23, 1)
[node name="Ground" type="ColorRect" parent="GameWorld" unique_id=581381780]
offset_top = 320.0
offset_right = 540.0
offset_bottom = 360.0
color = Color(0.68, 0.48, 0.22, 1)
[node name="Bird" type="TextureRect" parent="GameWorld" unique_id=225012823]
offset_left = 108.0
offset_top = 130.0
offset_right = 148.0
offset_bottom = 170.0
pivot_offset = Vector2(20, 20)
texture = ExtResource("2_icon")
expand_mode = 1
[node name="Hud" type="Node" parent="GameWorld" unique_id=441089907]
[node name="DemoStatus" type="Label" parent="GameWorld/Hud" unique_id=204759433]
offset_left = 15.0
offset_top = 328.0
offset_right = 517.0
offset_bottom = 374.0
text = "Running flappy-physics-v1 | score=0 | y=146 | vy=0 | pipeX=420"
[node name="FlappyScript" type="Node" parent="." unique_id=1458328663]
script = ExtResource("1_flappy")
FlapPower = 5
Name = &"FlappyScript"
[node name="LiveHotReloadHost" type="LeanCLRHotReloadHost" parent="." unique_id=465275025]
[node name="HotReloadInputRelay" type="Node" parent="." unique_id=394620894]
script = ExtResource("4_input_relay")
[node name="RuntimeCSharpEditor" parent="." unique_id=56462960 instance=ExtResource("3_editor_scene")]
+11
View File
@@ -0,0 +1,11 @@
using Godot;
namespace Game;
public partial class ClassDbMain : Node
{
public override void _Ready()
{
GD.Print("LeanCLR demo: ClassDB host owner name = " + Name);
}
}
+1
View File
@@ -0,0 +1 @@
uid://b5rn1ql6ugvjj
+10
View File
@@ -0,0 +1,10 @@
extends Node
@onready var hot_reload_host: Node = get_node("../LiveHotReloadHost")
func _ready() -> void:
set_process_input(true)
func _input(event: InputEvent) -> void:
if hot_reload_host != null:
hot_reload_host.forward_input(event)
@@ -0,0 +1 @@
uid://dca5khgessig
+270
View File
@@ -0,0 +1,270 @@
using Godot;
namespace Game;
public partial class HotReloadSmoke : Node
{
private const string Version = "flappy-physics-v1";
private const float WorldWidth = 540.0f;
private const float WorldHeight = 360.0f;
private const float GroundY = 320.0f;
private const float BirdX = 108.0f;
private const float BirdSize = 40.0f;
private const float Gravity = 960.0f;
private const float FlapVelocity = -330.0f;
private const float PipeSpeed = 170.0f;
private const float PipeWidth = 60.0f;
private const float GapHeight = 160.0f;
private const float ResetPipeX = 560.0f;
private const float PipeRecycleX = -80.0f;
private const int MinGapCenter = 118;
private const int MaxGapCenter = 235;
private static readonly Color AliveBirdColor = new Color(1.0f, 0.95f, 0.18f, 1.0f);
private static readonly Color GameOverBirdColor = new Color(1.0f, 0.32f, 0.22f, 1.0f);
[Export(PropertyHint.Range, "1,10,1")]
public int FlapPower { get; set; } = 5;
private float elapsed;
private float birdY;
private float velocityY;
private float pipeX;
private int gapCenter;
private int score;
private bool gameOver;
private bool passedPipe;
private bool processLogged;
private bool runtimeReloadedObject;
public override void _Ready()
{
if (birdY <= 0.0f || pipeX <= 0.0f)
{
ResetGame();
}
ApplyGameState();
GD.Print("LeanCLR flappy reload: version = " + Version);
GD.Print("LeanCLR flappy reload: score = " + score.ToString());
GD.Print("LeanCLR flappy reload: bird y = " + ((int)birdY).ToString());
GD.Print("LeanCLR flappy reload: velocity y = " + ((int)velocityY).ToString());
GD.Print("LeanCLR flappy reload: active marker = " + FileAccess.GetFileAsString("res://leanclr/live_reload.txt").Trim());
}
public override void _Input(InputEvent event_)
{
if (!IsGameplayObjectActive())
{
return;
}
if (event_ != null && event_.IsPressed() && !event_.IsEcho())
{
ForceFlap();
}
}
public void ForceFlap()
{
if (gameOver)
{
ResetGame();
GD.Print("LeanCLR flappy input: restart");
return;
}
velocityY = FlapVelocity - FlapPower * 10.0f;
GD.Print("LeanCLR flappy input: flap velocity = " + ((int)velocityY).ToString());
}
public Variant CaptureHotReloadState()
{
Dictionary state = new Dictionary();
state[new Variant("elapsed")] = new Variant(elapsed);
state[new Variant("birdY")] = new Variant(birdY);
state[new Variant("velocityY")] = new Variant(velocityY);
state[new Variant("pipeX")] = new Variant(pipeX);
state[new Variant("gapCenter")] = new Variant(gapCenter);
state[new Variant("score")] = new Variant(score);
state[new Variant("gameOver")] = new Variant(gameOver);
state[new Variant("passedPipe")] = new Variant(passedPipe);
state[new Variant("processLogged")] = new Variant(processLogged);
GD.Print("LeanCLR hot reload state: captured score = " + score.ToString() + " y = " + ((int)birdY).ToString());
return new Variant(state);
}
public void RestoreHotReloadState(Variant stateVariant)
{
runtimeReloadedObject = true;
Dictionary state = stateVariant.AsDictionary();
if (state != null)
{
elapsed = ReadFloat(state, "elapsed", elapsed);
birdY = ReadFloat(state, "birdY", birdY);
velocityY = ReadFloat(state, "velocityY", velocityY);
pipeX = ReadFloat(state, "pipeX", pipeX);
gapCenter = ReadInt(state, "gapCenter", gapCenter);
score = ReadInt(state, "score", score);
gameOver = ReadBool(state, "gameOver", gameOver);
passedPipe = ReadBool(state, "passedPipe", passedPipe);
processLogged = ReadBool(state, "processLogged", processLogged);
}
GD.Print("LeanCLR hot reload state: restored score = " + score.ToString() + " y = " + ((int)birdY).ToString());
}
public void OnHotReloaded()
{
runtimeReloadedObject = true;
ApplyGameState();
GD.Print("LeanCLR hot reload state: active score after reload = " + score.ToString() + " y = " + ((int)birdY).ToString());
}
public override void _Process(double delta)
{
if (!IsGameplayObjectActive())
{
return;
}
float dt = Clamp((float)delta, 0.0f, 0.033f);
elapsed += dt;
if (!gameOver)
{
velocityY += Gravity * dt;
birdY += velocityY * dt;
pipeX -= PipeSpeed * dt;
if (pipeX < PipeRecycleX)
{
pipeX = ResetPipeX;
gapCenter = NextGapCenter();
passedPipe = false;
}
if (!passedPipe && pipeX + PipeWidth < BirdX)
{
passedPipe = true;
score++;
GD.Print("LeanCLR flappy score: " + score.ToString());
}
if (CheckCollision())
{
gameOver = true;
GD.Print("LeanCLR flappy collision: game over score = " + score.ToString());
}
}
ApplyGameState();
if (!processLogged)
{
processLogged = true;
GD.Print("LeanCLR flappy process: playable physics tick delta = " + delta.ToString());
}
}
private void ResetGame()
{
elapsed = 0.0f;
birdY = 146.0f;
velocityY = 0.0f;
pipeX = 420.0f;
gapCenter = 172;
score = 0;
gameOver = false;
passedPipe = false;
processLogged = false;
}
private bool CheckCollision()
{
if (birdY < 0.0f || birdY + BirdSize > GroundY)
{
return true;
}
bool overlapsPipeX = BirdX + BirdSize > pipeX && BirdX < pipeX + PipeWidth;
if (!overlapsPipeX)
{
return false;
}
float gapTop = gapCenter - GapHeight * 0.5f;
float gapBottom = gapCenter + GapHeight * 0.5f;
return birdY < gapTop || birdY + BirdSize > gapBottom;
}
private void ApplyGameState()
{
TextureRect bird = GetNodeOrNull<TextureRect>("../GameWorld/Bird");
ColorRect pipeTop = GetNodeOrNull<ColorRect>("../GameWorld/PipeTop");
ColorRect pipeBottom = GetNodeOrNull<ColorRect>("../GameWorld/PipeBottom");
Label title = GetNodeOrNull<Label>("../GameWorld/Hud/Title");
Label status = GetNodeOrNull<Label>("../GameWorld/Hud/DemoStatus");
if (bird != null)
{
bird.Position = new Vector2(BirdX, birdY);
bird.Size = new Vector2(BirdSize, BirdSize);
bird.SetModulate(gameOver ? GameOverBirdColor : AliveBirdColor);
bird.SetRotationDegrees(Clamp(velocityY / 18.0f, -24.0f, 58.0f));
}
float gapTop = gapCenter - GapHeight * 0.5f;
float gapBottom = gapCenter + GapHeight * 0.5f;
if (pipeTop != null)
{
pipeTop.Position = new Vector2(pipeX, 0.0f);
pipeTop.Size = new Vector2(PipeWidth, gapTop);
}
if (pipeBottom != null)
{
pipeBottom.Position = new Vector2(pipeX, gapBottom);
pipeBottom.Size = new Vector2(PipeWidth, GroundY - gapBottom);
}
if (title != null)
{
title.Text = gameOver ? "Game Over - press any key/click to restart" : "Flap: any key or mouse click";
}
if (status != null)
{
status.Text = "Running " + Version + " | score=" + score.ToString() + " | y=" + ((int)birdY).ToString() + " | vy=" + ((int)velocityY).ToString() + " | pipeX=" + ((int)pipeX).ToString();
}
}
private int NextGapCenter()
{
int cycle = ((score * 47) + 31) % (MaxGapCenter - MinGapCenter);
return MinGapCenter + cycle;
}
private bool IsGameplayObjectActive()
{
string marker = FileAccess.GetFileAsString("res://leanclr/live_reload.txt").Trim();
return marker == "Game" || runtimeReloadedObject;
}
private float ReadFloat(Dictionary state, string key, float fallback)
{
Variant variantKey = new Variant(key);
return state.ContainsKey(variantKey) ? (float)state[variantKey].AsDouble() : fallback;
}
private int ReadInt(Dictionary state, string key, int fallback)
{
Variant variantKey = new Variant(key);
return state.ContainsKey(variantKey) ? (int)state[variantKey].AsInt64() : fallback;
}
private bool ReadBool(Dictionary state, string key, bool fallback)
{
Variant variantKey = new Variant(key);
return state.ContainsKey(variantKey) ? state[variantKey].AsBool() : fallback;
}
private float Clamp(float value, float min, float max)
{
return value < min ? min : (value > max ? max : value);
}
}
+1
View File
@@ -0,0 +1 @@
uid://bo2r8gbx576k6
+162
View File
@@ -0,0 +1,162 @@
extends Window
const EDIT_SOURCE_PATH := "res://scripts/HotReloadSmoke.cs"
const RELOAD_MARKER_PATH := "res://leanclr/live_reload.txt"
const FRAMEWORK_RELATIVE_PATH := "../thirdparty/leanclr/src/libraries/dotnetframework4.x-linux"
const AUTORUN_ENVIRONMENT := "LEANCLR_RUNTIME_EDITOR_AUTORUN"
@onready var editor: CodeEdit = %RuntimeCSharpCodeEdit
@onready var run_button: Button = %RuntimeCSharpRunButton
@onready var status_label: Label = %RuntimeCSharpStatus
var autorun_started := false
func _ready() -> void:
if _is_editor_scene_context():
hide()
return
editor.syntax_highlighter = _create_csharp_highlighter()
editor.text = FileAccess.get_file_as_string(EDIT_SOURCE_PATH)
run_button.pressed.connect(compile_and_reload)
show()
if OS.has_environment(AUTORUN_ENVIRONMENT) and not autorun_started:
autorun_started = true
var code := editor.text
code = code.replace('private const string Version = "flappy-v1";', 'private const string Version = "flappy-v2";')
code = code.replace('private static readonly Color BirdColor = new Color(1.0f, 0.83f, 0.18f, 1.0f);', 'private static readonly Color BirdColor = new Color(1.0f, 0.35f, 0.18f, 1.0f);')
code = code.replace('private const int GapCenter = 170;', 'private const int GapCenter = 130;')
code = code.replace('public int FlapPower { get; set; } = 4;', 'public int FlapPower { get; set; } = 7;')
editor.text = code
compile_and_reload()
func _exit_tree() -> void:
hide()
func _create_csharp_highlighter() -> CodeHighlighter:
var highlighter := CodeHighlighter.new()
highlighter.number_color = Color(0.72, 0.86, 1.0)
highlighter.symbol_color = Color(0.86, 0.86, 0.82)
highlighter.function_color = Color(0.55, 0.82, 1.0)
highlighter.member_variable_color = Color(0.95, 0.75, 0.45)
for keyword in [
"abstract", "as", "base", "break", "case", "catch", "checked", "class", "const", "continue",
"default", "delegate", "do", "else", "enum", "event", "explicit", "extern", "false", "finally",
"fixed", "for", "foreach", "goto", "if", "implicit", "in", "interface", "internal", "is",
"lock", "namespace", "new", "null", "operator", "out", "override", "params", "private", "protected",
"public", "readonly", "ref", "return", "sealed", "sizeof", "stackalloc", "static", "struct", "switch",
"this", "throw", "true", "try", "typeof", "unchecked", "unsafe", "using", "virtual", "void",
"volatile", "while", "partial", "get", "set", "value", "async", "await", "yield",
]:
highlighter.add_keyword_color(keyword, Color(0.95, 0.48, 0.72))
for type_keyword in [
"bool", "byte", "char", "decimal", "double", "float", "int", "long", "object", "sbyte",
"short", "string", "uint", "ulong", "ushort", "var", "dynamic", "Node", "Color", "Vector2",
"Vector3", "TextureRect", "ColorRect", "Label", "FileAccess", "GD", "System",
]:
highlighter.add_member_keyword_color(type_keyword, Color(0.45, 0.9, 0.7))
highlighter.add_color_region("//", "", Color(0.45, 0.55, 0.48), true)
highlighter.add_color_region("/*", "*/", Color(0.45, 0.55, 0.48), false)
highlighter.add_color_region("\"", "\"", Color(0.98, 0.82, 0.52), false)
highlighter.add_color_region("'", "'", Color(0.98, 0.82, 0.52), false)
return highlighter
func compile_and_reload() -> void:
if editor == null:
_set_status("Editor is not ready.")
return
if not _write_text_file(EDIT_SOURCE_PATH, editor.text):
_set_status("Failed to write HotReloadSmoke.cs")
return
var project_root := ProjectSettings.globalize_path("res://").trim_suffix("/")
var assembly_name := "GameRuntimeEdit" + str(Time.get_unix_time_from_system()).replace(".", "")
var project_file := project_root.path_join("Game.csproj")
var framework_path := project_root.path_join(FRAMEWORK_RELATIVE_PATH).simplify_path()
_set_status("Building " + assembly_name + "...")
if not _build_assembly(project_file, assembly_name, framework_path):
return
var leanclr_dir := project_root.path_join("leanclr")
var versioned_path := leanclr_dir.path_join(assembly_name + ".dll")
var cached_versioned_path := OS.get_user_data_dir().path_join(assembly_name + ".dll")
if not _copy_file(versioned_path, cached_versioned_path):
_set_status("Built " + assembly_name + ", but failed to preserve the reload assembly.")
return
if not _build_assembly(project_file, "Game", framework_path):
return
if not _copy_file(cached_versioned_path, versioned_path):
_set_status("Built Game, but failed to restore " + assembly_name + ".")
return
if not _write_text_file(RELOAD_MARKER_PATH, assembly_name + "\n"):
_set_status("Built " + assembly_name + ", but failed to update reload marker.")
return
_set_status("Loaded marker for " + assembly_name)
print("LeanCLR runtime editor: requested assembly = ", assembly_name)
func _build_assembly(project_file: String, assembly_name: String, framework_path: String) -> bool:
var build_args := [
"msbuild",
project_file,
"/p:Configuration=Debug",
"/p:AssemblyName=" + assembly_name,
"/p:OutputPath=leanclr/",
"/p:FrameworkPathOverride=" + framework_path,
]
print("LeanCLR runtime editor: build command = dotnet ", " ".join(build_args))
var output: Array = []
var exit_code := OS.execute("dotnet", build_args, output, true, false)
if exit_code != 0:
_set_status("Build failed: exit code " + str(exit_code))
printerr("LeanCLR runtime editor: build failed with exit code ", exit_code)
for line in output:
printerr(line)
return false
return true
func _copy_file(source_path: String, target_path: String) -> bool:
var source := FileAccess.open(source_path, FileAccess.READ)
if source == null:
printerr("LeanCLR runtime editor: failed to open copy source ", source_path, " error = ", FileAccess.get_open_error())
return false
var bytes := source.get_buffer(source.get_length())
source.close()
var target := FileAccess.open(target_path, FileAccess.WRITE)
if target == null:
printerr("LeanCLR runtime editor: failed to open copy target ", target_path, " error = ", FileAccess.get_open_error())
return false
target.store_buffer(bytes)
target.flush()
target.close()
return true
func _write_text_file(path: String, text: String) -> bool:
var file := FileAccess.open(path, FileAccess.WRITE)
if file == null:
printerr("LeanCLR runtime editor: failed to open ", path, " error = ", FileAccess.get_open_error())
return false
file.store_string(text)
file.flush()
file.close()
return true
func _set_status(status: String) -> void:
if status_label != null:
status_label.text = status
print("LeanCLR runtime editor: ", status)
func _is_editor_scene_context() -> bool:
if Engine.is_editor_hint():
return true
var tree := get_tree()
return tree != null and tree.edited_scene_root != null
@@ -0,0 +1 @@
uid://b626vql61yl6r
+546
View File
@@ -0,0 +1,546 @@
using Godot;
namespace Game;
public partial class ScriptMain : Node2D
{
[Export(PropertyHint.Range, "0,1000,1")]
public int InspectorNumber { get; set; } = 7;
private bool processPrinted;
private bool physicsProcessPrinted;
private bool inputPrinted;
private bool guiInputPrinted;
public override void _EnterTree()
{
GD.Print("LeanCLR demo: _EnterTree owner name = " + Name);
}
public override void _ExitTree()
{
GD.Print("LeanCLR demo: _ExitTree owner name = " + Name);
}
public override void _Ready()
{
StringName ownerName = Name;
GD.Print("LeanCLR demo: ScriptLanguage owner name = " + ownerName.ToString());
Position = new Vector2(12.0f, 34.0f);
Scale = new Vector2(2.0f, 3.0f);
SetModulate(new Color(0.25f, 0.5f, 0.75f, 1.0f));
Color modulate = GetModulate();
GD.Print("LeanCLR demo: position = " + Position.ToString());
GD.Print("LeanCLR demo: scale = " + Scale.ToString());
GD.Print("LeanCLR demo: modulate color = " + modulate.ToString());
Label label = GetNode<Label>(new NodePath("UiLabel"));
label.Text = "LeanCLR Label";
label.Position = new Vector2(7.0f, 8.0f);
label.Size = new Vector2(120.0f, 24.0f);
label.SetHorizontalAlignment(HorizontalAlignment.Center);
label.SetHSizeFlags(Control.SizeFlags.SizeExpandFill);
label.SetJustificationFlags(TextServer.JustificationFlag.JustificationWordBound | TextServer.JustificationFlag.JustificationTrimEdgeSpaces);
label.Hide();
label.Show();
GD.Print("LeanCLR demo: label text = " + label.Text);
GD.Print("LeanCLR demo: label position = " + label.Position.ToString());
GD.Print("LeanCLR demo: label h alignment = " + label.GetHorizontalAlignment().ToString());
GD.Print("LeanCLR demo: label h size flags = " + label.GetHSizeFlags().ToString());
GD.Print("LeanCLR demo: label justification flags = " + label.GetJustificationFlags().ToString());
GD.Print("LeanCLR demo: label rect = " + label.GetRect().ToString());
GD.Print("LeanCLR demo: node2d transform = " + GetTransform().ToString());
GD.Print("LeanCLR demo: label canvas RID valid = " + label.GetCanvasItem().IsValid().ToString());
Font defaultFont = label.GetThemeDefaultFont();
GD.Print("LeanCLR demo: label default font exists = " + (defaultFont != null).ToString());
Font defaultFontAgain = label.GetThemeDefaultFont();
GD.Print("LeanCLR demo: wrapper identity cache = " + object.ReferenceEquals(defaultFont, defaultFontAgain).ToString());
if (defaultFont != null)
{
defaultFont.Dispose();
}
GD.Print("LeanCLR demo: label visible = " + label.IsVisible().ToString());
GD.Print("LeanCLR demo: script property initial = " + Get(new StringName("InspectorNumber")).AsInt64().ToString());
Set(new StringName("InspectorNumber"), new Variant(314));
GD.Print("LeanCLR demo: script property updated = " + InspectorNumber.ToString());
GodotArray scriptProperties = GetPropertyList();
GD.Print("LeanCLR demo: script property list exists = " + (scriptProperties != null).ToString());
if (scriptProperties != null)
{
for (int i = 0; i < scriptProperties.Count; ++i)
{
Dictionary propertyInfo = scriptProperties[i].AsDictionary();
if (propertyInfo[new Variant("name")].ToString() == "InspectorNumber")
{
GD.Print("LeanCLR demo: script property hint = " + propertyInfo[new Variant("hint")].ToString());
GD.Print("LeanCLR demo: script property hint string = " + propertyInfo[new Variant("hint_string")].ToString());
}
}
scriptProperties.Dispose();
}
string sceneUniqueId = Resource.GenerateSceneUniqueId();
GD.Print("LeanCLR demo: resource id length > 0 = " + (sceneUniqueId.Length > 0).ToString());
Variant metaValue = new Variant("LeanCLR Variant");
SetMeta(new StringName("leanclr_meta"), metaValue);
GD.Print("LeanCLR demo: variant meta exists = " + HasMeta(new StringName("leanclr_meta")).ToString());
Variant metaRoundtrip = GetMeta(new StringName("leanclr_meta"));
GD.Print("LeanCLR demo: variant meta = " + metaRoundtrip.ToString());
metaRoundtrip.Dispose();
metaValue.Dispose();
Variant callMetaKey = new Variant("leanclr_call_meta");
Variant callMetaValue = new Variant("LeanCLR Call Variant");
Call(new StringName("set_meta"), callMetaKey, callMetaValue).Dispose();
Variant callMetaRoundtrip = Call(new StringName("get_meta"), callMetaKey);
GD.Print("LeanCLR demo: object call variant meta = " + callMetaRoundtrip.ToString());
callMetaRoundtrip.Dispose();
callMetaValue.Dispose();
callMetaKey.Dispose();
AddToGroup(new StringName("leanclr_vararg_group"));
Variant groupMetaKey = new Variant("leanclr_group_meta");
Variant groupMetaValue = new Variant("LeanCLR Group Variant");
GetTree().CallGroup(new StringName("leanclr_vararg_group"), new StringName("set_meta"), groupMetaKey, groupMetaValue);
Variant groupMetaRoundtrip = GetMeta(new StringName("leanclr_group_meta"));
GD.Print("LeanCLR demo: call group variant meta = " + groupMetaRoundtrip.ToString());
groupMetaRoundtrip.Dispose();
groupMetaValue.Dispose();
groupMetaKey.Dispose();
Variant jsonValue = new Variant("LeanCLR JSON");
string jsonText = JSON.Stringify(jsonValue);
GD.Print("LeanCLR demo: variant json = " + jsonText);
jsonValue.Dispose();
Variant parsedJson = JSON.ParseString("123");
GD.Print("LeanCLR demo: parsed variant = " + parsedJson.ToString());
parsedJson.Dispose();
GD.Print("LeanCLR demo: project file exists = " + FileAccess.FileExists("res://project.godot").ToString());
GD.Print("LeanCLR demo: project file text length > 0 = " + (FileAccess.GetFileAsString("res://project.godot").Length > 0).ToString());
PackedByteArray projectBytes = FileAccess.GetFileAsBytes("res://project.godot");
Variant packedByteVariant = new Variant(projectBytes);
GD.Print("LeanCLR demo: variant packed byte array type = " + packedByteVariant.VariantType.ToString());
GD.Print("LeanCLR demo: packed byte array wrapper exists = " + (packedByteVariant.AsPackedByteArray() != null).ToString());
packedByteVariant.Dispose();
PackedByteArray manualBytes = new PackedByteArray();
manualBytes.Add(1);
manualBytes.Add(2);
manualBytes[1] = 3;
GD.Print("LeanCLR demo: packed byte manual count = " + manualBytes.Count.ToString());
GD.Print("LeanCLR demo: packed byte manual second = " + manualBytes[1].ToString());
manualBytes.Clear();
GD.Print("LeanCLR demo: packed byte manual cleared = " + manualBytes.Count.ToString());
manualBytes.Dispose();
projectBytes.Dispose();
DirAccess projectDir = DirAccess.Open("res://");
GD.Print("LeanCLR demo: dir access open = " + (projectDir != null).ToString());
GD.Print("LeanCLR demo: dir open error = " + DirAccess.GetOpenError().ToString());
GD.Print("LeanCLR demo: dir drive count >= 0 = " + (DirAccess.GetDriveCount() >= 0).ToString());
if (projectDir != null)
{
projectDir.Dispose();
}
PackedStringArray projectFiles = DirAccess.GetFilesAt("res://");
bool foundProjectFile = false;
for (int i = 0; i < projectFiles.Count; ++i)
{
if (projectFiles[i] == "project.godot")
{
foundProjectFile = true;
}
}
GD.Print("LeanCLR demo: packed files count > 0 = " + (projectFiles.Count > 0).ToString());
GD.Print("LeanCLR demo: packed files include project = " + foundProjectFile.ToString());
projectFiles.Dispose();
PackedInt32Array packedInts = new PackedInt32Array();
packedInts.Add(4);
packedInts[0] = 5;
GD.Print("LeanCLR demo: packed int32 first = " + packedInts[0].ToString());
packedInts.Dispose();
PackedInt64Array packedLongs = new PackedInt64Array();
packedLongs.Add(6L);
GD.Print("LeanCLR demo: packed int64 count = " + packedLongs.Count.ToString());
packedLongs.Dispose();
PackedFloat32Array packedFloats = new PackedFloat32Array();
packedFloats.Add(1.25f);
GD.Print("LeanCLR demo: packed float32 first = " + packedFloats[0].ToString());
packedFloats.Dispose();
PackedFloat64Array packedDoubles = new PackedFloat64Array();
packedDoubles.Add(2.5);
GD.Print("LeanCLR demo: packed float64 first = " + packedDoubles[0].ToString());
packedDoubles.Dispose();
PackedVector2Array packedVector2s = new PackedVector2Array();
packedVector2s.Add(new Vector2(1.0f, 2.0f));
GD.Print("LeanCLR demo: packed vector2 first = " + packedVector2s[0].ToString());
packedVector2s.Dispose();
PackedVector3Array packedVector3s = new PackedVector3Array();
packedVector3s.Add(new Vector3(3.0f, 4.0f, 5.0f));
GD.Print("LeanCLR demo: packed vector3 first = " + packedVector3s[0].ToString());
packedVector3s.Dispose();
PackedColorArray packedColors = new PackedColorArray();
packedColors.Add(new Color(0.6f, 0.7f, 0.8f, 1.0f));
GD.Print("LeanCLR demo: packed color first = " + packedColors[0].ToString());
packedColors.Dispose();
PackedStringArray csvValues = new PackedStringArray(new string[] { "alpha", "beta" });
GD.Print("LeanCLR demo: packed manual first = " + csvValues[0]);
FileAccess csvFile = FileAccess.Open("user://leanclr_packed.csv", FileAccess.ModeFlags.Write);
bool csvStored = csvFile != null && csvFile.StoreCsvLine(csvValues);
GD.Print("LeanCLR demo: packed csv stored = " + csvStored.ToString());
if (csvFile != null)
{
csvFile.Dispose();
}
csvValues.Dispose();
Image image = Image.CreateEmpty(4, 4, false, Image.Format.Rgba8);
image.SetPixel(2, 1, new Color(1.0f, 0.0f, 0.0f, 1.0f));
GD.Print("LeanCLR demo: image used rect = " + image.GetUsedRect().ToString());
image.Dispose();
PhysicsRayQueryParameters3D rayQuery = PhysicsRayQueryParameters3D.Create(new Vector3(1.0f, 2.0f, 3.0f), new Vector3(4.0f, 5.0f, 6.0f));
GD.Print("LeanCLR demo: physics ray 3d query exists = " + (rayQuery != null).ToString());
if (rayQuery != null)
{
GD.Print("LeanCLR demo: physics ray 3d from = " + rayQuery.GetFrom().ToString());
GD.Print("LeanCLR demo: physics ray 3d to = " + rayQuery.GetTo().ToString());
rayQuery.Dispose();
}
Node3D node3D = GetNode<Node3D>(new NodePath("Node3DDemo"));
node3D.SetPosition(new Vector3(7.0f, 8.0f, 9.0f));
node3D.SetQuaternion(Quaternion.Identity);
node3D.SetBasis(Basis.Identity);
node3D.SetTransform(new Transform3D(Basis.Identity, new Vector3(10.0f, 11.0f, 12.0f)));
GD.Print("LeanCLR demo: node3d position = " + node3D.GetPosition().ToString());
GD.Print("LeanCLR demo: node3d quaternion = " + node3D.GetQuaternion().ToString());
GD.Print("LeanCLR demo: node3d basis = " + node3D.GetBasis().ToString());
GD.Print("LeanCLR demo: node3d transform = " + node3D.GetTransform().ToString());
CPUParticles3D particles3D = GetNode<CPUParticles3D>(new NodePath("CpuParticles3DDemo"));
particles3D.SetVisibilityAabb(new Aabb(new Vector3(1.0f, 2.0f, 3.0f), new Vector3(4.0f, 5.0f, 6.0f)));
GD.Print("LeanCLR demo: particles visibility aabb = " + particles3D.GetVisibilityAabb().ToString());
Camera3D camera3D = GetNode<Camera3D>(new NodePath("Camera3DDemo"));
GD.Print("LeanCLR demo: camera transform = " + camera3D.GetCameraTransform().ToString());
Projection cameraProjection = camera3D.GetCameraProjection();
GD.Print("LeanCLR demo: camera projection = " + cameraProjection.ToString());
Variant projectionVariant = new Variant(cameraProjection);
GD.Print("LeanCLR demo: variant projection type = " + projectionVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant projection = " + projectionVariant.AsProjection().ToString());
projectionVariant.Dispose();
Plane demoPlane = new Plane(new Vector3(0.0f, 1.0f, 0.0f), 2.0f);
Variant planeVariant = new Variant(demoPlane);
GD.Print("LeanCLR demo: variant plane type = " + planeVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant plane = " + planeVariant.AsPlane().ToString());
planeVariant.Dispose();
Sprite2D sprite = GetNode<Sprite2D>(new NodePath("SpriteDemo"));
Texture2D spriteTexture = sprite.GetTexture();
sprite.Centered = false;
sprite.Offset = new Vector2(5.0f, 6.0f);
sprite.FlipH = true;
sprite.SetHframes(2);
sprite.SetVframes(2);
sprite.SetFrameCoords(new Vector2i(1, 1));
SetRotationDegrees(15.0f);
GD.Print("LeanCLR demo: sprite centered = " + sprite.Centered.ToString());
GD.Print("LeanCLR demo: sprite texture is null = " + (spriteTexture == null).ToString());
GD.Print("LeanCLR demo: sprite offset = " + sprite.Offset.ToString());
GD.Print("LeanCLR demo: sprite flip h = " + sprite.FlipH.ToString());
GD.Print("LeanCLR demo: sprite frame coords = " + sprite.GetFrameCoords().ToString());
GD.Print("LeanCLR demo: rotation degrees = " + GetRotationDegrees().ToString());
NodePath childPath = new NodePath("Child");
Node child = GetNode<Node>(childPath);
GD.Print("LeanCLR demo: child before QueueFree = " + child.Name);
GD.Print("LeanCLR demo: child parent = " + child.GetParent().Name);
GD.Print("LeanCLR demo: child count = " + GetChildCount().ToString());
GD.Print("LeanCLR demo: inside tree = " + IsInsideTree().ToString());
GD.Print("LeanCLR demo: tree node count > 0 = " + (GetTree().GetNodeCount() > 0).ToString());
SetProcessMode(Node.ProcessMode.Always);
GD.Print("LeanCLR demo: process mode = " + GetProcessMode().ToString());
Variant selfVariant = new Variant(this);
Node2D selfObject = selfVariant.AsObject<Node2D>();
GD.Print("LeanCLR demo: variant object name = " + selfObject.Name.ToString());
selfVariant.Dispose();
Variant vector2Variant = new Variant(new Vector2(3.0f, 4.0f));
GD.Print("LeanCLR demo: variant vector2 = " + vector2Variant.AsVector2().ToString());
GD.Print("LeanCLR demo: variant vector2 stringify = " + vector2Variant.ToString());
vector2Variant.Dispose();
Variant vector3Variant = new Variant(new Vector3(5.0f, 6.0f, 7.0f));
GD.Print("LeanCLR demo: variant vector3 = " + vector3Variant.AsVector3().ToString());
vector3Variant.Dispose();
Variant stringNameVariant = new Variant(new StringName("leanclr_name"));
GD.Print("LeanCLR demo: variant string name type = " + stringNameVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant string name = " + stringNameVariant.AsStringName().ToString());
stringNameVariant.Dispose();
Variant nodePathVariant = new Variant(new NodePath("Child"));
GD.Print("LeanCLR demo: variant node path type = " + nodePathVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant node path = " + nodePathVariant.AsNodePath().ToString());
nodePathVariant.Dispose();
Variant ridVariant = new Variant(new RID(0));
GD.Print("LeanCLR demo: variant rid type = " + ridVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant rid valid = " + ridVariant.AsRID().IsValid().ToString());
ridVariant.Dispose();
PackedStringArray packedStrings = new PackedStringArray(new string[] { "alpha", "beta" });
Variant packedStringArrayVariant = new Variant(packedStrings);
PackedStringArray packedStringsRoundtrip = packedStringArrayVariant.AsPackedStringArray();
GD.Print("LeanCLR demo: variant packed string array type = " + packedStringArrayVariant.VariantType.ToString());
GD.Print("LeanCLR demo: packed string array count = " + packedStringsRoundtrip.Count.ToString());
GD.Print("LeanCLR demo: packed string array first = " + packedStringsRoundtrip[0]);
packedStringsRoundtrip.Dispose();
packedStringArrayVariant.Dispose();
packedStrings.Dispose();
Array demoArray = new Array();
demoArray.Add(new Variant("array first"));
demoArray.Add(new Variant(new Vector2(8.0f, 9.0f)));
Variant arrayVariant = new Variant(demoArray);
GD.Print("LeanCLR demo: variant array type = " + arrayVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant array wrapper exists = " + (arrayVariant.AsArray() != null).ToString());
GD.Print("LeanCLR demo: array count = " + demoArray.Count.ToString());
GD.Print("LeanCLR demo: array first = " + demoArray[0].ToString());
GD.Print("LeanCLR demo: array second = " + demoArray[1].AsVector2().ToString());
Variant arrayInserted = new Variant("array inserted");
demoArray.Insert(1, arrayInserted);
GD.Print("LeanCLR demo: array inserted = " + demoArray[1].ToString());
GD.Print("LeanCLR demo: array contains inserted = " + demoArray.Contains(arrayInserted).ToString());
GD.Print("LeanCLR demo: array inserted index = " + demoArray.IndexOf(arrayInserted).ToString());
int arrayEnumerated = 0;
foreach (Variant item in demoArray)
{
arrayEnumerated++;
}
GD.Print("LeanCLR demo: array enumerated = " + arrayEnumerated.ToString());
demoArray.RemoveAt(1);
GD.Print("LeanCLR demo: array count after remove = " + demoArray.Count.ToString());
demoArray.Clear();
GD.Print("LeanCLR demo: array count after clear = " + demoArray.Count.ToString());
arrayInserted.Dispose();
arrayVariant.Dispose();
demoArray.Dispose();
Dictionary demoDictionary = new Dictionary();
Variant dictionaryKey = new Variant("answer");
demoDictionary[dictionaryKey] = new Variant(42);
Variant dictionaryVariant = new Variant(demoDictionary);
GD.Print("LeanCLR demo: variant dictionary type = " + dictionaryVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant dictionary wrapper exists = " + (dictionaryVariant.AsDictionary() != null).ToString());
GD.Print("LeanCLR demo: dictionary count = " + demoDictionary.Count.ToString());
GD.Print("LeanCLR demo: dictionary has key = " + demoDictionary.ContainsKey(dictionaryKey).ToString());
Variant dictionaryValue = demoDictionary[dictionaryKey];
GD.Print("LeanCLR demo: dictionary value type = " + dictionaryValue.VariantType.ToString());
GD.Print("LeanCLR demo: dictionary value = " + dictionaryValue.ToString());
GD.Print("LeanCLR demo: dictionary value int = " + dictionaryValue.AsInt64().ToString());
Array dictionaryKeys = demoDictionary.Keys;
Array dictionaryValues = demoDictionary.Values;
GD.Print("LeanCLR demo: dictionary keys count = " + dictionaryKeys.Count.ToString());
GD.Print("LeanCLR demo: dictionary values first = " + dictionaryValues[0].ToString());
int dictionaryEnumerated = 0;
foreach (var entry in demoDictionary)
{
if (entry.Key.ToString() == "answer" && entry.Value.AsInt64() == 42)
{
dictionaryEnumerated++;
}
}
GD.Print("LeanCLR demo: dictionary enumerated = " + dictionaryEnumerated.ToString());
GD.Print("LeanCLR demo: dictionary removed = " + demoDictionary.Remove(dictionaryKey).ToString());
GD.Print("LeanCLR demo: dictionary count after remove = " + demoDictionary.Count.ToString());
demoDictionary[dictionaryKey] = new Variant(7);
demoDictionary.Clear();
GD.Print("LeanCLR demo: dictionary count after clear = " + demoDictionary.Count.ToString());
dictionaryKeys.Dispose();
dictionaryValues.Dispose();
dictionaryValue.Dispose();
dictionaryKey.Dispose();
dictionaryVariant.Dispose();
demoDictionary.Dispose();
Callable setMetaCallable = new Callable(this, new StringName("set_meta"));
Variant callableMetaKey = new Variant("leanclr_callable_meta");
Variant callableMetaValue = new Variant("LeanCLR Callable Variant");
setMetaCallable.Call(callableMetaKey, callableMetaValue).Dispose();
Variant callableMetaRoundtrip = GetMeta(new StringName("leanclr_callable_meta"));
GD.Print("LeanCLR demo: callable valid = " + setMetaCallable.IsValid().ToString());
GD.Print("LeanCLR demo: callable method = " + setMetaCallable.GetMethod().ToString());
GD.Print("LeanCLR demo: callable call meta = " + callableMetaRoundtrip.ToString());
callableMetaRoundtrip.Dispose();
callableMetaValue.Dispose();
callableMetaKey.Dispose();
AddUserSignal("leanclr_user_signal");
Signal userSignal = new Signal(this, new StringName("leanclr_user_signal"));
Variant signalMetaKey = new Variant("leanclr_signal_meta");
Variant signalMetaValue = new Variant("LeanCLR Signal Variant");
Callable signalCallable = setMetaCallable.Bind(signalMetaKey, signalMetaValue);
GD.Print("LeanCLR demo: signal name = " + userSignal.GetName().ToString());
GD.Print("LeanCLR demo: signal connect = " + userSignal.Connect(signalCallable, 0).ToString());
userSignal.Emit();
Variant signalMetaRoundtrip = GetMeta(new StringName("leanclr_signal_meta"));
GD.Print("LeanCLR demo: signal emitted meta = " + signalMetaRoundtrip.ToString());
Variant callableVariant = new Variant(signalCallable);
Variant signalVariant = new Variant(userSignal);
GD.Print("LeanCLR demo: variant callable type = " + callableVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant callable valid = " + callableVariant.AsCallable().IsValid().ToString());
GD.Print("LeanCLR demo: variant signal type = " + signalVariant.VariantType.ToString());
GD.Print("LeanCLR demo: variant signal name = " + signalVariant.AsSignal().GetName().ToString());
AddUserSignal("leanclr_managed_signal");
Signal managedSignal = new Signal(this, new StringName("leanclr_managed_signal"));
Callable managedCallable = new Callable(this, new StringName("OnLeanClrManagedSignal"));
GD.Print("LeanCLR demo: managed callable valid = " + managedCallable.IsValid().ToString());
GD.Print("LeanCLR demo: managed signal connect = " + managedSignal.Connect(managedCallable, 0).ToString());
managedSignal.Emit();
Variant managedSignalRoundtrip = GetMeta(new StringName("leanclr_managed_signal_meta"));
GD.Print("LeanCLR demo: managed signal emitted meta = " + managedSignalRoundtrip.ToString());
managedSignalRoundtrip.Dispose();
AddUserSignal("leanclr_managed_arg_signal");
Signal managedArgSignal = new Signal(this, new StringName("leanclr_managed_arg_signal"));
Callable managedArgCallable = new Callable(this, new StringName("OnLeanClrManagedSignalWithArg"));
GD.Print("LeanCLR demo: managed arg callable valid = " + managedArgCallable.IsValid().ToString());
GD.Print("LeanCLR demo: managed arg signal connect = " + managedArgSignal.Connect(managedArgCallable, 0).ToString());
Variant managedArgPayload = new Variant("LeanCLR Managed Signal Payload");
managedArgSignal.Emit(managedArgPayload);
Variant managedArgSignalRoundtrip = GetMeta(new StringName("leanclr_managed_arg_signal_meta"));
GD.Print("LeanCLR demo: managed arg signal emitted meta = " + managedArgSignalRoundtrip.ToString());
managedArgSignalRoundtrip.Dispose();
AddUserSignal("leanclr_managed_multi_signal");
Signal managedMultiSignal = new Signal(this, new StringName("leanclr_managed_multi_signal"));
Callable managedMultiCallable = new Callable(this, new StringName("OnLeanClrManagedSignalWithArgs"));
GD.Print("LeanCLR demo: managed multi callable valid = " + managedMultiCallable.IsValid().ToString());
GD.Print("LeanCLR demo: managed multi signal connect = " + managedMultiSignal.Connect(managedMultiCallable, 0).ToString());
Variant managedMultiFirst = new Variant("LeanCLR");
Variant managedMultiSecond = new Variant("Multi Signal Payload");
managedMultiSignal.Emit(managedMultiFirst, managedMultiSecond);
Variant managedMultiSignalRoundtrip = GetMeta(new StringName("leanclr_managed_multi_signal_meta"));
GD.Print("LeanCLR demo: managed multi signal emitted meta = " + managedMultiSignalRoundtrip.ToString());
managedMultiSignalRoundtrip.Dispose();
Callable typedCallable = new Callable(this, new StringName("OnLeanClrTypedCallable"));
Variant typedCallResult = typedCallable.Call(new Variant("LeanCLR Typed"), new Variant(41), new Variant(1.5), new Variant(new Vector2(2.0f, 3.0f)), new Variant(this));
GD.Print("LeanCLR demo: typed callable result = " + typedCallResult.ToString());
typedCallResult.Dispose();
Callable returnIntCallable = new Callable(this, new StringName("OnLeanClrReturnInt"));
Variant returnIntResult = returnIntCallable.Call(new Variant(41));
GD.Print("LeanCLR demo: return int callable result = " + returnIntResult.ToString());
returnIntResult.Dispose();
returnIntCallable.Dispose();
Callable structCallable = new Callable(this, new StringName("OnLeanClrStructCallable"));
Variant structCallResult = structCallable.Call(new Variant(new StringName("struct_name")), new Variant(new NodePath("Child")), new Variant(new RID(0)), new Variant(new Color(0.1f, 0.2f, 0.3f, 1.0f)), new Variant(Quaternion.Identity), new Variant(Basis.Identity), new Variant(Transform3D.Identity));
GD.Print("LeanCLR demo: struct callable result = " + structCallResult.ToString());
structCallResult.Dispose();
structCallable.Dispose();
Callable returnColorCallable = new Callable(this, new StringName("OnLeanClrReturnColor"));
Variant returnColorResult = returnColorCallable.Call(new Variant(new Color(0.2f, 0.3f, 0.4f, 1.0f)));
GD.Print("LeanCLR demo: return color callable result = " + returnColorResult.AsColor().ToString());
returnColorResult.Dispose();
returnColorCallable.Dispose();
int delegateSignalCount = 0;
Callable delegateCallable = Callable.From(() => { delegateSignalCount = 42; });
AddUserSignal("leanclr_delegate_signal");
Signal delegateSignal = new Signal(this, new StringName("leanclr_delegate_signal"));
GD.Print("LeanCLR demo: delegate callable valid = " + delegateCallable.IsValid().ToString());
GD.Print("LeanCLR demo: delegate signal connect = " + delegateSignal.Connect(delegateCallable, 0).ToString());
delegateSignal.Emit();
GD.Print("LeanCLR demo: delegate signal count = " + delegateSignalCount.ToString());
Callable delegateArgCallable = Callable.From<Variant>((payload) => { SetMeta(new StringName("leanclr_delegate_arg_meta"), payload); });
AddUserSignal("leanclr_delegate_arg_signal");
Signal delegateArgSignal = new Signal(this, new StringName("leanclr_delegate_arg_signal"));
GD.Print("LeanCLR demo: delegate arg signal connect = " + delegateArgSignal.Connect(delegateArgCallable, 0).ToString());
delegateArgSignal.Emit(new Variant("LeanCLR Delegate Payload"));
Variant delegateArgRoundtrip = GetMeta(new StringName("leanclr_delegate_arg_meta"));
GD.Print("LeanCLR demo: delegate arg meta = " + delegateArgRoundtrip.ToString());
delegateArgRoundtrip.Dispose();
delegateArgCallable.Dispose();
delegateArgSignal.Dispose();
delegateCallable.Dispose();
delegateSignal.Emit();
GD.Print("LeanCLR demo: delegate signal count after dispose = " + delegateSignalCount.ToString());
delegateSignal.Dispose();
typedCallable.Dispose();
managedMultiSecond.Dispose();
managedMultiFirst.Dispose();
managedMultiCallable.Dispose();
managedMultiSignal.Dispose();
managedArgPayload.Dispose();
managedArgCallable.Dispose();
managedArgSignal.Dispose();
managedCallable.Dispose();
managedSignal.Dispose();
callableVariant.Dispose();
signalVariant.Dispose();
signalMetaRoundtrip.Dispose();
signalMetaValue.Dispose();
signalMetaKey.Dispose();
signalCallable.Dispose();
userSignal.Dispose();
setMetaCallable.Dispose();
SetPhysicsProcess(true);
SetProcessInput(true);
Call(new StringName("_input"), new Variant((GodotObject)null)).Dispose();
Call(new StringName("_gui_input"), new Variant((GodotObject)null)).Dispose();
child.QueueFree();
}
public void OnLeanClrManagedSignal()
{
SetMeta(new StringName("leanclr_managed_signal_meta"), new Variant("LeanCLR Managed Signal Variant"));
}
public void OnLeanClrManagedSignalWithArg(Variant payload)
{
SetMeta(new StringName("leanclr_managed_arg_signal_meta"), payload);
}
public void OnLeanClrManagedSignalWithArgs(Variant[] payloads)
{
SetMeta(new StringName("leanclr_managed_multi_signal_meta"), new Variant(payloads[0].ToString() + " " + payloads[1].ToString()));
}
public string OnLeanClrTypedCallable(string label, int count, double amount, Vector2 point, Node node)
{
return label + " " + (count + 1).ToString() + " " + amount.ToString() + " " + point.ToString() + " " + node.Name.ToString();
}
public int OnLeanClrReturnInt(int value)
{
return value + 1;
}
public string OnLeanClrStructCallable(StringName name, NodePath path, RID rid, Color color, Quaternion quaternion, Basis basis, Transform3D transform)
{
return name.ToString() + " " + path.ToString() + " " + rid.IsValid().ToString() + " " + color.ToString() + " " + quaternion.ToString() + " " + basis.ToString() + " " + transform.ToString();
}
public Color OnLeanClrReturnColor(Color value)
{
return value;
}
public override void _Process(double delta)
{
if (processPrinted)
{
return;
}
processPrinted = true;
GD.Print("LeanCLR demo: _Process delta > 0 = " + (delta > 0.0).ToString());
}
public override void _PhysicsProcess(float delta)
{
if (physicsProcessPrinted)
{
return;
}
physicsProcessPrinted = true;
GD.Print("LeanCLR demo: _PhysicsProcess delta > 0 = " + (delta > 0.0f).ToString());
}
public override void _Input(InputEvent event_)
{
if (inputPrinted)
{
return;
}
inputPrinted = true;
GD.Print("LeanCLR demo: _Input event wrapper exists = " + (event_ != null).ToString());
}
public void _GuiInput(InputEvent event_)
{
if (guiInputPrinted)
{
return;
}
guiInputPrinted = true;
GD.Print("LeanCLR demo: _GuiInput event wrapper exists = " + (event_ != null).ToString());
}
}
+1
View File
@@ -0,0 +1 @@
uid://c0duyyvvovu5x