godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.14k stars 21.19k forks source link

Loading a GDScript script from outside of Godot using GodotSharp #78231

Closed TranquilMarmot closed 1 year ago

TranquilMarmot commented 1 year ago

Godot version

v4.0.3.stable.mono.official [5222a99f5]

System information

Windows 11 - net7.0

Issue description

This might not even be possible, but I figured I would ask!

I have a game that's written in GDScript. I'd like to run a server and call out to some of the validation functions that I've written in GDScript.

I noticed that Godotsharp is published to nuget here: https://www.nuget.org/packages/GodotSharp

So, I figured why not try and use GD.Load<GDScript>(...) as outlined in the Cross-language scripting docs.

But, this fails with the following error:

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Godot.NativeInterop.NativeFuncs.godotsharp_string_new_with_utf16_chars(Godot.NativeInterop.godot_string ByRef, Char*)
   at Godot.NativeInterop.Marshaling.ConvertStringToNative(System.String)
   at Godot.NativeInterop.NativeFuncs.godotsharp_string_name_new_from_string(System.String)
   at Godot.StringName..ctor(System.String)
   at Godot.StringName.op_Implicit(System.String)
   at Godot.ResourceLoader..cctor()
   at Godot.ResourceLoader.Load(System.String, System.String, CacheMode)
   at Godot.GD.Load(System.String)
   at Program+<<Main>$>d__0.MoveNext()

Steps to reproduce

Instantiate a C# project. Here is my sample .csproj file:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RootNamespace>GodotTestServer</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="GodotSharp" Version="4.0.3" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="../scripts-shared/server-test.gd">
      <Link>%(Filename)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

</Project>

At the path above where this is, I have a scripts-shared/server-test.gd file that has the same code as the example in the Cross-language scripting docs. This is copied to the server's build directory by the CopyToOutputDirectory above.

extends Node

var my_field: String = "foo"

func print_node_name(node: Node) -> void:
    print(node.get_name())

func print_array(arr: Array) -> void:
    for element in arr:
        print(element)

func print_n_times(msg: String, n: int) -> void:
    for i in range(n):
        print(msg)

I then try to instantiate that script:

using Godot;

// this is an absolute path to the file, I verified that it exists here
GDScript MyGDScript = (GDScript)GD.Load(AppDomain.CurrentDomain.BaseDirectory + "\\server-test.gd");

// won't get past here; the above throws the error mentioned in the description

Minimal reproduction project

N/A

idbrii commented 1 year ago

I have a game that's written in GDScript. I'd like to run a server and call out to some of the validation functions that I've written in GDScript.

Is your goal to have a standalone server executable that can evaluate gdscript (like a testrunner)? Or a server that talks to the game client and requests evaluation of godot code?

For a testrunner, you could look at how Gut works. It supports running from the command line so it can run tests without human interaction. And godot 4 has a --headless option to avoid it popping up when tests run or to run from CI. That might be enough to accomplish the same end goal.

TranquilMarmot commented 1 year ago

The goal is for a standalone server to be running mostly C# (ASP.NET) but with some shared GDScript code between the server and the client. This is a turn-based game, so I don't need real-time multiplayer.

I've considered writing the server entirely in GDScript, but that seems like a bit of a pain. I have it working with shared C# code between an ASP.NET server and Godot Mono, but I was hoping to keep it all in GDScript on the client side so that I can deploy the game to Android, iOS, and web which aren't supported by Godot 4 Mono (yet...)

RedworkDE commented 1 year ago

outside of Godot

This is fundamentally not supported and no godot functions work in this scenario.

Use a godot project and export it in dedicated server mode and run it in headless mode if you don't need any UI. If you need ASP.NET for the server, you will also either need to use a custom build that includes #72333 or wait for that to get merged.

TranquilMarmot commented 1 year ago

Oh, that's an idea that I hadn't thought of- running the server itself using Godot Sharp to get access to the shared code. Brilliant!

I'll close this issue since I really didn't expect it to work 😅 thanks for the pointer to that PR!