feat: init

This commit is contained in:
2026-04-10 18:59:27 -04:00
commit d9dfa44a22
41 changed files with 1993 additions and 0 deletions

415
.editorconfig Normal file
View File

@@ -0,0 +1,415 @@
# --------------------------------------------------------------------------- #
# Chickensoft C# Style — .editorconfig #
# --------------------------------------------------------------------------- #
# Godot-friendly coding style with a bit of Dart-style flair thrown in. #
# --------------------------------------------------------------------------- #
# #
# #
# ╓╗_▄╗_╓▄_ #
# ▄▄╟▓▓▓▓▓▓▓▓ #
# ╙▓▓▓▀▀╠╠╦╦╓,_ #
# ,φ╠╠╠╠╠╠╠╠╠╠▒╥ #
# φ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╦ #
# @╠╠╫▌╠╟▌╠╠╠╠╠╠╠╠╠ #
# ╠╠╠▄▄▄▒╠╠╠╠╠╠╠╠╠╠b #
# ╠╠╨███▌╠╠╠╠╠╠╠▒╠╠▒_ ç╓ #
# ╠╠╠╠▒▒╠╠╠╠╠╠╠╠▒Å▄╠╬▒φ╩ε #
# ╚╠╠╠╠╠╠╠╠╠╠╠▒█▒╫█Å╠╠╩ #
# ╠╠╠╠╠╠╠╠╠╠╠╠╠╟╫▒╠╠╩ #
# ╙╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╜ #
# ╙╚╠╠╠╠╠╠╠╠╩╙ #
# ╒ µ #
# ▌ ▓ #
# ^▀▀ "▀ª #
# #
# #
# --------------------------------------------------------------------------- #
#
# Based on:
# - https://github.com/RehanSaeed/EditorConfig/blob/main/.editorconfig
# - https://gist.github.com/FaronBracy/155d8d7ad98b4ceeb526b9f47543db1b
# - various other gists floating around :)
#
# Have a problem? Encounter an issue?
# Come visit our Discord and let us know! https://discord.gg/MjA6HUzzAE
#
# Based on https://github.com/RehanSaeed/EditorConfig/blob/main/.editorconfig
# and https://gist.github.com/FaronBracy/155d8d7ad98b4ceeb526b9f47543db1b
# This file is the top-most EditorConfig file
root = true
# All Files
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
##########################################
# File Extension Settings
##########################################
# GDScript Files
[*.{gd,gdshader,gdshaderinc}]
indent_style = tab
# Visual Studio Solution Files
[*.sln]
indent_style = tab
# Visual Studio XML Project Files
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML Configuration Files
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
indent_size = 2
# JSON Files
[*.{json,json5,webmanifest}]
indent_size = 2
# YAML Files
[*.{yml,yaml}]
indent_size = 2
# Markdown Files
[*.{md,mdx}]
trim_trailing_whitespace = false
# Web Files
[*.{htm,html,js,jsm,ts,tsx,cjs,cts,ctsx,mjs,mts,mtsx,css,sass,scss,less,pcss,svg,vue}]
indent_size = 2
# Batch Files
[*.{cmd,bat}]
end_of_line = crlf
# Makefiles
[Makefile]
indent_style = tab
[*{_Generated.cs,.g.cs,.generated.cs}]
# Ignore a lack of documentation for generated code. Doesn't apply to builds,
# just to viewing generation output.
dotnet_diagnostic.CS1591.severity = none
##########################################
# Default .NET Code Style Severities
##########################################
[*.cs]
# Default Severity for all .NET Code Style rules below
dotnet_analyzer_diagnostic.severity = warning
##########################################
# Language Rules
##########################################
# .NET Style Rules
# "this." and "Me." qualifiers
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_property = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_event = false
# Language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
dotnet_style_readonly_field = true:warning
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning
# Expression-level preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
dotnet_diagnostic.IDE0045.severity = suggestion
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
dotnet_diagnostic.IDE0046.severity = suggestion
dotnet_style_prefer_compound_assignment = true:warning
dotnet_style_prefer_simplified_interpolation = true:warning
dotnet_style_prefer_simplified_boolean_expressions = true:warning
# Null-checking preferences
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
# Unused parameters and methods
dotnet_diagnostic.IDE0060.severity = warn
dotnet_diagnostic.IDE0051.severity = warn
# File header preferences
# Keep operators at end of line when wrapping.
dotnet_style_operator_placement_when_wrapping = end_of_line
csharp_style_prefer_null_check_over_type_check = true:warning
# Code block preferences
csharp_prefer_braces = true:warning
csharp_prefer_simple_using_statement = true:suggestion
dotnet_diagnostic.IDE0063.severity = suggestion
# C# Style Rules
# 'var' preferences
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning
# Expression-bodied members
csharp_style_expression_bodied_methods = when_on_single_line:warning
csharp_style_expression_bodied_constructors = false:warning
csharp_style_expression_bodied_operators = true:warning
csharp_style_expression_bodied_properties = true:warning
csharp_style_expression_bodied_indexers = true:warning
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_lambdas = true:warning
csharp_style_expression_bodied_local_functions = true:warning
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
csharp_style_prefer_switch_expression = true:warning
csharp_style_prefer_pattern_matching = true:warning
csharp_style_prefer_not_pattern = true:warning
# Expression-level preferences
csharp_style_inlined_variable_declaration = true:warning
csharp_prefer_simple_default_expression = true:warning
csharp_style_pattern_local_over_anonymous_function = true:warning
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
# "Null" checking preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# 'using' directive preferences
csharp_using_directive_placement = inside_namespace:warning
# Use discard variable for unused expression values.
csharp_style_unused_value_expression_statement_preference = discard_variable
csharp_style_unused_value_assignment_preference = discard_variable
##########################################
# Formatting Rules
##########################################
# .NET formatting rules
# Organize using directives
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
# Dotnet namespace options
#
# We don't care about namespaces matching folder structure. Games and apps
# are complicated and you are free to organize them however you like. Change
# this if you want to enforce it.
dotnet_style_namespace_match_folder = false
dotnet_diagnostic.IDE0130.severity = none
# C# formatting rules
# Newline options
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation options
csharp_indent_switch_labels = true
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = no_change
csharp_indent_block_contents = true
csharp_indent_braces = false
# Spacing options
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_after_comma = true
csharp_space_before_comma = false
csharp_space_after_dot = false
csharp_space_before_dot = false
csharp_space_after_semicolon_in_for_statement = true
csharp_space_before_semicolon_in_for_statement = false
csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
# Wrap options
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
# Namespace options
csharp_style_namespace_declarations = file_scoped:warning
##########################################
# Unnecessary Code Rules
##########################################
# .NET Unnecessary code rules
dotnet_code_quality_unused_parameters = non_public:suggestion
dotnet_remove_unnecessary_suppression_exclusions = none
##########################################
# .NET Naming Rules
##########################################
##########################################
# Chickensoft Naming Conventions & Styles
# These deviate heavily from Microsoft's Official Naming Conventions.
##########################################
# Allow underscores in names.
dotnet_diagnostic.CA1707.severity = none
# Styles
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
dotnet_naming_style.upper_case_style.capitalization = all_upper
dotnet_naming_style.upper_case_style.word_separator = _
dotnet_naming_style.camel_case_style.capitalization = camel_case
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# Use uppercase for all constant fields.
dotnet_naming_rule.constants_uppercase.severity = suggestion
dotnet_naming_rule.constants_uppercase.symbols = constant_fields
dotnet_naming_rule.constants_uppercase.style = upper_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
# Non-public fields should be _camelCase
dotnet_naming_rule.non_public_fields_under_camel.severity = suggestion
dotnet_naming_rule.non_public_fields_under_camel.symbols = non_public_fields
dotnet_naming_rule.non_public_fields_under_camel.style = camel_case_underscore_style
dotnet_naming_symbols.non_public_fields.applicable_kinds = field
dotnet_naming_symbols.non_public_fields.required_modifiers =
dotnet_naming_symbols.non_public_fields.applicable_accessibilities = private,private_protected,internal,protected,protected_internal
# Public fields should be PascalCase
dotnet_naming_rule.public_fields_pascal.severity = suggestion
dotnet_naming_rule.public_fields_pascal.symbols = public_fields
dotnet_naming_rule.public_fields_pascal.style = pascal_case_style
dotnet_naming_symbols.public_fields.applicable_kinds = field
dotnet_naming_symbols.public_fields.required_modifiers =
dotnet_naming_symbols.public_fields.applicable_accessibilities = public
# Async methods should have "Async" suffix.
# Disabled because it makes tests too verbose.
# dotnet_naming_style.end_in_async.required_suffix = Async
# dotnet_naming_style.end_in_async.capitalization = pascal_case
# dotnet_naming_rule.methods_end_in_async.symbols = methods_async
# dotnet_naming_rule.methods_end_in_async.style = end_in_async
# dotnet_naming_rule.methods_end_in_async.severity = warning
# dotnet_naming_symbols.methods_async.applicable_kinds = method
# dotnet_naming_symbols.methods_async.required_modifiers = async
# dotnet_naming_symbols.methods_async.applicable_accessibilities = *
##########################################
# Other Naming Rules
##########################################
# All of the following must be PascalCase:
dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
dotnet_naming_rule.element_rule.symbols = element_group
dotnet_naming_rule.element_rule.style = pascal_case_style
dotnet_naming_rule.element_rule.severity = warning
# Interfaces use PascalCase and are prefixed with uppercase 'I'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
dotnet_naming_symbols.interface_group.applicable_kinds = interface
dotnet_naming_rule.interface_rule.symbols = interface_group
dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
dotnet_naming_rule.interface_rule.severity = warning
# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
dotnet_naming_rule.type_parameter_rule.severity = warning
# Function parameters use camelCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
dotnet_naming_rule.parameters_rule.symbols = parameters_group
dotnet_naming_rule.parameters_rule.style = camel_case_style
dotnet_naming_rule.parameters_rule.severity = warning
# Anything not specified uses camel case.
dotnet_naming_rule.unspecified_naming.severity = warning
dotnet_naming_rule.unspecified_naming.symbols = unspecified
dotnet_naming_rule.unspecified_naming.style = camel_case_style
dotnet_naming_symbols.unspecified.applicable_kinds = *
dotnet_naming_symbols.unspecified.applicable_accessibilities = *
##########################################
# Chickensoft Rule Overrides
##########################################
# Allow protected fields.
dotnet_diagnostic.CA1051.severity = none
# Don't warn about checking values that are supposedly never null. Sometimes
# they are actually null.
dotnet_diagnostic.CS8073.severity = none
# Allow expression values to go unused, even without discard variable.
# Otherwise, using Moq would be way too verbose.
dotnet_diagnostic.IDE0058.severity = none
# Allow me to use the word Collection if I want.
dotnet_diagnostic.CA1711.severity = none
# Don't warn about using reserved keywords (e.g., methods named "On")
dotnet_diagnostic.CA1716.severity = none
# Don't warn about public methods that can be marked static
# (tests frequently don't access member data, and GoDotTest won't call static methods)
dotnet_code_quality.CA1822.api_surface = private
# No primary constructors — not supported well by tooling.
dotnet_diagnostic.IDE0290.severity = none
# Let me write dumb if statements for readability.
dotnet_diagnostic.IDE0046.severity = none
# DO make me populate a *switch expression*
dotnet_diagnostic.IDE0072.severity = warning
# Don't make me populate a *switch statement*
dotnet_diagnostic.IDE0010.severity = none
# Make local functions static
dotnet_diagnostic.IDE0062.severity = warning
# Don't make me use properties if I don't want to.
dotnet_diagnostic.IDE0032.severity = none

45
.gitattributes vendored Normal file
View File

@@ -0,0 +1,45 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
# Image formats
*.bmp filter=lfs diff=lfs merge=lfs -text
*.dds filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.hdr filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text
# Audio and Video formats
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.ogx filter=lfs diff=lfs merge=lfs -text
*.ogv filter=lfs diff=lfs merge=lfs -text
# 3D formats
*.gltf filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.blend1 filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.dae filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
# Build
*.dll filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.pdb filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
# Packaging
*.zip filter=lfs diff=lfs merge=lfs -text
*.7z filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.file filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text

81
.github/workflows/auto_release.yaml vendored Normal file
View File

@@ -0,0 +1,81 @@
# This workflow will run whenever tests finish running. If tests pass, it will
# look at the last commit message to see if it contains the phrase
# "chore(deps): update all dependencies".
#
# If it finds a commit with that phrase, and the testing workflow has passed,
# it will automatically release a new version of the project by running the
# publish workflow.
#
# The commit message phrase above is always used by renovatebot when opening
# PR's to update dependencies. If you have renovatebot enabled and set to
# automatically merge in dependency updates, this can automatically release and
# publish the updated version of the project.
#
# You can disable this action by setting the DISABLE_AUTO_RELEASE repository
# variable to true.
name: '🦾 Auto-Release'
on:
workflow_run:
workflows: ["🚥 Tests"]
branches:
- main
types:
- completed
jobs:
auto_release:
name: 🦾 Auto-Release
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.release.outputs.should_release }}
steps:
- name: 🧾 Checkout
uses: actions/checkout@v6
with:
# Use your GitHub Personal Access Token variable here.
token: ${{ secrets.GH_BASIC }}
lfs: true
submodules: 'recursive'
- name: 🧑‍🔬 Check Test Results
id: tests
run: |
echo "passed=${{ github.event.workflow_run.conclusion == 'success' }}" >> "$GITHUB_OUTPUT"
- name: 📄 Check If Dependencies Changed
id: deps
run: |
message=$(git log -1 --pretty=%B)
if [[ $message == *"chore(deps)"* ]]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
- name: 📝 Check Release Status
id: release
run: |
echo "Tests passed: ${{ steps.tests.outputs.passed }}"
echo "Dependencies changed: ${{ steps.deps.outputs.changed }}"
disable_auto_release='${{ vars.DISABLE_AUTO_RELEASE }}'
echo "DISABLE_AUTO_RELEASE=$disable_auto_release"
if [[ ${{ steps.tests.outputs.passed }} == "true" && ${{ steps.deps.outputs.changed }} == "true" && $disable_auto_release != "true" ]]; then
echo "should_release=true" >> "$GITHUB_OUTPUT"
echo "🦾 Creating a release!"
else
echo "should_release=false" >> "$GITHUB_OUTPUT"
echo "✋ Not creating a release."
fi
trigger_release:
uses: './.github/workflows/release.yaml'
needs: auto_release
if: needs.auto_release.outputs.should_release == 'true'
secrets:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
GH_BASIC: ${{ secrets.GH_BASIC }}
with:
bump: patch

99
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,99 @@
name: '📦 Release'
on:
# Make a release whenever the developer wants.
workflow_dispatch:
inputs:
bump:
type: string
description: "major, minor, or patch"
required: true
default: "patch"
# Make a release whenever we're told to by another workflow.
workflow_call:
secrets:
NUGET_API_KEY:
description: "API key for Nuget"
required: true
GH_BASIC:
description: "Personal access token (PAT) for GitHub"
required: true
# Input unifies with the workflow dispatch since it's identical.
inputs:
bump:
type: string
description: "major, minor, or patch"
required: true
default: "patch"
jobs:
release:
name: '📦 Release'
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
steps:
- name: 🧾 Checkout
uses: actions/checkout@v6
with:
token: ${{ secrets.GH_BASIC }}
lfs: true
submodules: 'recursive'
fetch-depth: 0 # So we can get all tags.
- name: 🔎 Read Current Project Version
id: current-version
uses: WyriHaximus/github-action-get-previous-tag@v2
with:
fallback: "0.0.0-devbuild"
- name: 🖨 Print Current Version
run: |
echo "Current Version: ${{ steps.current-version.outputs.tag }}"
- name: 🧮 Compute Next Version
uses: chickensoft-games/next-godot-csproj-version@v1
id: next-version
with:
project-version: ${{ steps.current-version.outputs.tag }}
godot-version: global.json
bump: ${{ inputs.bump }}
- uses: actions/setup-dotnet@v5
name: 💽 Setup .NET SDK
with:
# Use the .NET SDK from global.json in the root of the repository.
global-json-file: global.json
# Write version to file so .NET will build correct version.
- name: 📝 Write Version to File
uses: jacobtomlinson/gha-find-replace@v3
with:
find: "0.0.0-devbuild"
replace: ${{ steps.next-version.outputs.version }}
regex: false
include: GodotHelper/GodotHelper.csproj
- name: 📦 Build
working-directory: GodotHelper
run: dotnet build -c Release
- name: 🔎 Get Package Path
id: package-path
run: |
package=$(find ./GodotHelper/nupkg -name "*.nupkg")
echo "package=$package" >> "$GITHUB_OUTPUT"
echo "📦 Found package: $package"
- name: ✨ Create Release
env:
GITHUB_TOKEN: ${{ secrets.GH_BASIC }}
run: |
version="${{ steps.next-version.outputs.version }}"
gh release create --title "v$version" --generate-notes "$version" \
"${{ steps.package-path.outputs.package }}"
- name: 🛜 Publish to Nuget
run: |
dotnet nuget push "${{ steps.package-path.outputs.package }}" \
--api-key "${{ secrets.NUGET_API_KEY }}" \
--source "https://api.nuget.org/v3/index.json" --skip-duplicate

26
.github/workflows/spellcheck.yaml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: '🧑‍🏫 Spellcheck'
on:
push:
pull_request:
jobs:
spellcheck:
name: '🧑‍🏫 Spellcheck'
# Only run the workflow if it's not a PR or if it's a PR from a fork.
# This prevents duplicate workflows from running on PR's that originate
# from the repository itself.
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest
defaults:
run:
working-directory: '.'
steps:
- uses: actions/checkout@v6
name: 🧾 Checkout
- uses: streetsidesoftware/cspell-action@v8
name: 📝 Check Spelling
with:
config: './cspell.json'
incremental_files_only: false
root: '.'

64
.github/workflows/tests.yaml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: 🚥 Tests
on:
push:
pull_request:
jobs:
tests:
name: 🧪 Evaluate Tests on ${{ matrix.os }}
# Only run the workflow if it's not a PR or if it's a PR from a fork.
# This prevents duplicate workflows from running on PR's that originate
# from the repository itself.
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ${{ matrix.os }}
strategy:
# Don't cancel other OS runners if one fails.
fail-fast: false
matrix:
# Put the operating systems you want to run on here.
os: [ubuntu-latest, macos-latest, windows-2025]
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
defaults:
run:
# Use bash shells on all platforms.
shell: bash
steps:
- name: 🧾 Checkout
uses: actions/checkout@v6
with:
lfs: true
submodules: 'recursive'
- name: 💽 Setup .NET SDK
uses: actions/setup-dotnet@v5
with:
# Use the .NET SDK from global.json in the root of the repository.
global-json-file: global.json
- name: 📦 Restore Dependencies
run: dotnet restore
- name: 🤖 Setup Godot
uses: chickensoft-games/setup-godot@v2
with:
# Version must include major, minor, and patch, and be >= 4.0.0
# Pre-release label is optional.
#
# In this case, we are using the version from global.json.
#
# This allows checks on renovatebot PR's to succeed whenever
# renovatebot updates the Godot SDK version.
version: global.json
- name: 🧑‍🔬 Generate .NET Bindings
working-directory: GodotHelper.Tests
run: godot --headless --build-solutions --quit || exit 0
- name: 🦺 Build Projects
run: dotnet build
- name: 🧪 Run Tests
working-directory: GodotHelper.Tests
run: godot --headless --run-tests --quit-on-finish

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
**/coverage/*
!**/coverage/.gdignore
nupkg/
.godot/
bin/
obj/
.generated/
.vs/
.DS_Store
*.DotSettings.user
*.binlog

10
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"recommendations": [
"ms-dotnettools.csharp",
"selcukermaya.se-csproj-extensions",
"josefpihrt-vscode.roslynator",
"streetsidesoftware.code-spell-checker",
"VisualStudioExptTeam.vscodeintellicode",
"DavidAnson.vscode-markdownlint"
]
}

37
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"version": "0.2.0",
"configurations": [
// For these launch configurations to work, you need to setup a GODOT
// environment variable. On mac or linux, this can be done by adding
// the following to your .zshrc, .bashrc, or .bash_profile file:
// export GODOT="/Applications/Godot.app/Contents/MacOS/Godot"
{
"name": "🧪 Debug Tests",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${env:GODOT}",
"args": [
// These command line flags are used by GoDotTest to run tests.
"--run-tests",
"--quit-on-finish"
],
"cwd": "${workspaceFolder}/GodotHelper.Tests",
"stopAtEntry": false,
},
{
"name": "🔬 Debug Current Test",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${env:GODOT}",
"args": [
// These command line flags are used by GoDotTest to run tests.
"--run-tests=${fileBasenameNoExtension}",
"--quit-on-finish"
],
"cwd": "${workspaceFolder}/GodotHelper.Tests",
"stopAtEntry": false,
},
]
}

169
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,169 @@
{
"[csharp]": {
"editor.codeActionsOnSave": {
"source.addMissingImports": "explicit",
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.formatOnType": false
},
"csharp.semanticHighlighting.enabled": true,
"dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
// Required to keep the C# language server from getting confused about which
// solution to open.
"dotnet.defaultSolution": "GodotHelper.sln",
"dotnet.server.useOmnisharp": false,
"editor.semanticHighlighting.enabled": true,
// C# doc comment colorization gets lost with semantic highlighting, but we
// need semantic highlighting for proper syntax highlighting with record
// shorthand.
//
// Here's a workaround for doc comment highlighting from
// https://github.com/OmniSharp/omnisharp-vscode/issues/3816
"editor.tokenColorCustomizations": {
"[*]": {
// Themes that don't include the word "Dark" or "Light" in them.
// These are some bold colors that show up well against most dark and
// light themes.
//
// Change them to something that goes well with your preferred theme :)
"textMateRules": [
{
"scope": "comment.documentation",
"settings": {
"foreground": "#0091ff"
}
},
{
"scope": "comment.documentation.attribute",
"settings": {
"foreground": "#8480ff"
}
},
{
"scope": "comment.documentation.cdata",
"settings": {
"foreground": "#0091ff"
}
},
{
"scope": "comment.documentation.delimiter",
"settings": {
"foreground": "#aa00ff"
}
},
{
"scope": "comment.documentation.name",
"settings": {
"foreground": "#ef0074"
}
}
]
},
"[*Dark*]": {
// Themes that include the word "Dark" in them.
"textMateRules": [
{
"scope": "comment.documentation",
"settings": {
"foreground": "#608B4E"
}
},
{
"scope": "comment.documentation.attribute",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "comment.documentation.cdata",
"settings": {
"foreground": "#E9D585"
}
},
{
"scope": "comment.documentation.delimiter",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "comment.documentation.name",
"settings": {
"foreground": "#569CD6"
}
}
]
},
"[*Light*]": {
// Themes that include the word "Light" in them.
"textMateRules": [
{
"scope": "comment.documentation",
"settings": {
"foreground": "#008000"
}
},
{
"scope": "comment.documentation.attribute",
"settings": {
"foreground": "#282828"
}
},
{
"scope": "comment.documentation.cdata",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "comment.documentation.delimiter",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "comment.documentation.name",
"settings": {
"foreground": "#808080"
}
}
]
}
},
"markdownlint.config": {
// Allow non-unique heading names so we don't break the changelog.
"MD024": false,
// Allow html in markdown.
"MD033": false
},
"markdownlint.lintWorkspaceGlobs": [
"!**/LICENSE"
],
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableMsBuildLoadProjectsOnDemand": false,
"omnisharp.maxFindSymbolsItems": 3000,
"omnisharp.useModernNet": true,
// Remove these if you're happy with your terminal profiles.
"terminal.integrated.defaultProfile.windows": "Git Bash",
"terminal.integrated.profiles.windows": {
"Command Prompt": {
"icon": "terminal-cmd",
"path": [
"${env:windir}\\Sysnative\\cmd.exe",
"${env:windir}\\System32\\cmd.exe"
]
},
"Git Bash": {
"icon": "terminal",
"source": "Git Bash"
},
"PowerShell": {
"icon": "terminal-powershell",
"source": "PowerShell"
}
},
"dotnet.formatting.organizeImportsOnFormat": true
}

40
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,40 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"--no-restore"
],
"problemMatcher": "$msCompile",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": false,
"clear": false
}
},
{
"label": "coverage",
"group": "test",
"command": "${workspaceFolder}/GodotHelper.Tests/coverage.sh",
"type": "shell",
"options": {
"cwd": "${workspaceFolder}/GodotHelper.Tests"
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": false,
"clear": true
},
},
]
}

38
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,38 @@
# Contributing
Thank you for taking the time to read this contributing guide and for showing interest in helping this project!
## Getting Started
Need a helping hand to get started? Check out these resources!
- [Discord Server][discord]
- [Chickensoft Website][chickensoft]
Please read our [code of conduct](#code-of-conduct). We do our best to treat others fairly and foster a welcoming environment.
## Project Setup
This is a C# nuget package, for use with the .NET SDK 6 or 7. As such, the `dotnet` tool will allow you to restore packages and build projects.
The `GodotHelper.Tests` project must be built with the Godot editor at least once before `dotnet build` will succeed. Godot has to generate the .NET bindings for the project, since tests run in an actual game environment.
## Coding Guidelines
Your IDE should automatically adhere to the style guidelines in the provided `.editorconfig` file. Please try to keep lines under 80 characters long whenever possible.
We try to write tests for our projects to ensure a certain level of quality. We are willing to give you support and guidance if you need help!
## Code of Conduct
We follow the [Contributor Covenant][covenant].
In short:
> We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
<!-- Links -->
[discord]: https://discord.gg/gSjaPgMmYW
[chickensoft]: https://chickensoft.games
[covenant]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/

View File

@@ -0,0 +1,8 @@
# EditorConfig for the test project.
root = false
[*.{cs,csx,cake}]
# Not disposing of objects in a test is normal within Godot
dotnet_diagnostic.CA1001.severity = none

View File

@@ -0,0 +1,36 @@
<Project Sdk="Godot.NET.Sdk/4.6.2">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableDynamicLoading>true</EnableDynamicLoading>
<LangVersion>preview</LangVersion>
<RootNamespace>GodotHelper.Tests</RootNamespace>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<!-- Required for some nuget packages to work -->
<!-- godotengine/godot/issues/42271#issuecomment-751423827 -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- To show generated files -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>.generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<!-- Test executor. -->
<PackageReference Include="Chickensoft.GoDotTest" Version="2.0.32" />
<!-- Assertions library. -->
<PackageReference Include="Shouldly" Version="4.3.0" />
<!-- Generated mocks. -->
<PackageReference Include="LightMock.Generator" Version="1.2.3" />
<!-- Convenience wrapper around generated mocks. -->
<PackageReference Include="LightMoq" Version="0.1.0" />
</ItemGroup>
<ItemGroup>
<!-- Include the package to test. -->
<ProjectReference Include="../GodotHelper/GodotHelper.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,36 @@
<Project Sdk="Godot.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableDynamicLoading>true</EnableDynamicLoading>
<LangVersion>preview</LangVersion>
<RootNamespace>GodotHelper.Tests</RootNamespace>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<!-- Required for some nuget packages to work -->
<!-- godotengine/godot/issues/42271#issuecomment-751423827 -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- To show generated files -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>.generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<!-- Test executor. -->
<PackageReference Include="Chickensoft.GoDotTest" Version="2.0.32" />
<!-- Assertions library. -->
<PackageReference Include="Shouldly" Version="4.3.0" />
<!-- Generated mocks. -->
<PackageReference Include="LightMock.Generator" Version="1.2.3" />
<!-- Convenience wrapper around generated mocks. -->
<PackageReference Include="LightMoq" Version="0.1.0" />
</ItemGroup>
<ItemGroup>
<!-- Include the package to test. -->
<ProjectReference Include="../GodotHelper/GodotHelper.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotHelper.Tests", "GodotHelper.Tests.csproj", "{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{477F44D4-2CF2-4A5C-A0FE-070F090BF2D5}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal

View File

View File

@@ -0,0 +1,113 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="155" height="20">
<style type="text/css">
<![CDATA[
@keyframes fade1 {
0% { visibility: visible; opacity: 1; }
27% { visibility: visible; opacity: 1; }
33% { visibility: hidden; opacity: 0; }
60% { visibility: hidden; opacity: 0; }
66% { visibility: hidden; opacity: 0; }
93% { visibility: hidden; opacity: 0; }
100% { visibility: visible; opacity: 1; }
}
@keyframes fade2 {
0% { visibility: hidden; opacity: 0; }
27% { visibility: hidden; opacity: 0; }
33% { visibility: visible; opacity: 1; }
60% { visibility: visible; opacity: 1; }
66% { visibility: hidden; opacity: 0; }
93% { visibility: hidden; opacity: 0; }
100% { visibility: hidden; opacity: 0; }
}
@keyframes fade3 {
0% { visibility: hidden; opacity: 0; }
27% { visibility: hidden; opacity: 0; }
33% { visibility: hidden; opacity: 0; }
60% { visibility: hidden; opacity: 0; }
66% { visibility: visible; opacity: 1; }
93% { visibility: visible; opacity: 1; }
100% { visibility: hidden; opacity: 0; }
}
.linecoverage {
animation-duration: 15s;
animation-name: fade1;
animation-iteration-count: infinite;
}
.branchcoverage {
animation-duration: 15s;
animation-name: fade2;
animation-iteration-count: infinite;
}
.methodcoverage {
animation-duration: 15s;
animation-name: fade3;
animation-iteration-count: infinite;
}
]]>
</style>
<title>Code coverage</title>
<defs>
<linearGradient id="gradient" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<linearGradient id="c">
<stop offset="0" stop-color="#d40000"/>
<stop offset="1" stop-color="#ff2a2a"/>
</linearGradient>
<linearGradient id="a">
<stop offset="0" stop-color="#e0e0de"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
<linearGradient id="b">
<stop offset="0" stop-color="#37c837"/>
<stop offset="1" stop-color="#217821"/>
</linearGradient>
<linearGradient xlink:href="#a" id="e" x1="106.44" x2="69.96" y1="-11.96" y2="-46.84" gradientTransform="matrix(-.8426 -.00045 -.00045 -.8426 -94.27 -75.82)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#b" id="f" x1="56.19" x2="77.97" y1="-23.45" y2="10.62" gradientTransform="matrix(.8426 .00045 .00045 .8426 94.27 75.82)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#c" id="g" x1="79.98" x2="132.9" y1="10.79" y2="10.79" gradientTransform="matrix(.8426 .00045 .00045 .8426 94.27 75.82)" gradientUnits="userSpaceOnUse"/>
<mask id="mask">
<rect width="155" height="20" rx="3" fill="#fff"/>
</mask>
<g id="icon" transform="matrix(.04486 0 0 .04481 -.48 -.63)">
<rect width="52.92" height="52.92" x="-109.72" y="-27.13" fill="url(#e)" transform="rotate(-135)"/>
<rect width="52.92" height="52.92" x="70.19" y="-39.18" fill="url(#f)" transform="rotate(45)"/>
<rect width="52.92" height="52.92" x="80.05" y="-15.74" fill="url(#g)" transform="rotate(45)"/>
</g>
</defs>
<g mask="url(#mask)">
<rect x="0" y="0" width="90" height="20" fill="#444"/>
<rect x="90" y="0" width="20" height="20" fill="#c00"/>
<rect x="110" y="0" width="45" height="20" fill="#00B600"/>
<rect x="0" y="0" width="155" height="20" fill="url(#gradient)"/>
</g>
<g>
<path class="" fill="#fff" d="m 97.627847,15.246584 q 0,-0.36435 -0.255043,-0.619412 -0.255042,-0.254975 -0.619388,-0.254975 -0.364346,0 -0.619389,0.254975 -0.255042,0.255062 -0.255042,0.619412 0,0.36435 0.255042,0.619412 0.255043,0.254975 0.619389,0.254975 0.364346,0 0.619388,-0.254975 0.255043,-0.255062 0.255043,-0.619412 z m 0,-10.4931686 q 0,-0.3643498 -0.255043,-0.6194121 -0.255042,-0.2550624 -0.619388,-0.2550624 -0.364346,0 -0.619389,0.2550624 -0.255042,0.2550623 -0.255042,0.6194121 0,0.3643498 0.255042,0.6193246 0.255043,0.2551499 0.619389,0.2551499 0.364346,0 0.619388,-0.2551499 0.255043,-0.2549748 0.255043,-0.6193246 z m 5.829537,1.1659368 q 0,-0.3643498 -0.255042,-0.6194121 -0.255042,-0.2550624 -0.619388,-0.2550624 -0.364347,0 -0.619389,0.2550624 -0.255042,0.2550623 -0.255042,0.6194121 0,0.3643497 0.255042,0.6193246 0.255042,0.2550623 0.619389,0.2550623 0.364346,0 0.619388,-0.2550623 0.255042,-0.2549749 0.255042,-0.6193246 z m 0.874431,0 q 0,0.4736372 -0.236825,0.8789369 -0.236824,0.4052998 -0.637606,0.6330621 -0.01822,2.6142358 -2.058555,3.7709858 -0.619388,0.346149 -1.849057,0.737799 -1.165908,0.36435 -1.543916,0.646712 -0.378009,0.282363 -0.378009,0.910875 l 0,0.236862 q 0.40078,0.227675 0.637605,0.633062 0.236825,0.4053 0.236825,0.878937 0,0.7287 -0.510084,1.238824 -0.510085,0.510038 -1.238777,0.510038 -0.728692,0 -1.238777,-0.510038 -0.510085,-0.510124 -0.510085,-1.238824 0,-0.473637 0.236825,-0.878937 0.236826,-0.405387 0.637606,-0.633062 l 0,-7.469083 q -0.40078,-0.2277624 -0.637606,-0.6331496 -0.236825,-0.4052998 -0.236825,-0.878937 0,-0.7286996 0.510085,-1.2388242 0.510085,-0.5100372 1.238777,-0.5100372 0.728692,0 1.238777,0.5100372 0.510084,0.5101246 0.510084,1.2388242 0,0.4736372 -0.236825,0.878937 -0.236825,0.4053872 -0.637605,0.6331496 l 0,4.526985 q 0.491866,-0.236862 1.402732,-0.519225 0.500976,-0.154875 0.797007,-0.268712 0.296031,-0.1138373 0.64216,-0.2823623 0.346129,-0.168525 0.537411,-0.3598 0.191281,-0.191275 0.3689,-0.4645374 0.177619,-0.2732623 0.255042,-0.6330621 0.07742,-0.3597998 0.07742,-0.833437 -0.40078,-0.2277623 -0.637606,-0.6330621 -0.236824,-0.4052997 -0.236824,-0.8789369 0,-0.7286996 0.510084,-1.2388243 0.510085,-0.5101246 1.238777,-0.5101246 0.728693,0 1.238777,0.5101246 0.510084,0.5101247 0.510084,1.2388243 z"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="Verdana,Arial,Geneva,sans-serif" font-size="11">
<a xlink:href="https://github.com/danielpalme/ReportGenerator" target="_top">
<title>Generated by: ReportGenerator 5.1.26.0</title>
<use xlink:href="#icon" transform="translate(3,1) scale(3.5)"/>
</a>
<text x="53" y="15" fill="#010101" fill-opacity=".3">Coverage</text>
<text x="53" y="14" fill="#fff">Coverage</text>
<text class="" x="132.5" y="15" fill="#010101" fill-opacity=".3">N/A</text><text class="" x="132.5" y="14">N/A</text>
</g>
<g>
<rect class="" x="90" y="0" width="65" height="20" fill-opacity="0"><title>Branch coverage</title></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,113 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="155" height="20">
<style type="text/css">
<![CDATA[
@keyframes fade1 {
0% { visibility: visible; opacity: 1; }
27% { visibility: visible; opacity: 1; }
33% { visibility: hidden; opacity: 0; }
60% { visibility: hidden; opacity: 0; }
66% { visibility: hidden; opacity: 0; }
93% { visibility: hidden; opacity: 0; }
100% { visibility: visible; opacity: 1; }
}
@keyframes fade2 {
0% { visibility: hidden; opacity: 0; }
27% { visibility: hidden; opacity: 0; }
33% { visibility: visible; opacity: 1; }
60% { visibility: visible; opacity: 1; }
66% { visibility: hidden; opacity: 0; }
93% { visibility: hidden; opacity: 0; }
100% { visibility: hidden; opacity: 0; }
}
@keyframes fade3 {
0% { visibility: hidden; opacity: 0; }
27% { visibility: hidden; opacity: 0; }
33% { visibility: hidden; opacity: 0; }
60% { visibility: hidden; opacity: 0; }
66% { visibility: visible; opacity: 1; }
93% { visibility: visible; opacity: 1; }
100% { visibility: hidden; opacity: 0; }
}
.linecoverage {
animation-duration: 15s;
animation-name: fade1;
animation-iteration-count: infinite;
}
.branchcoverage {
animation-duration: 15s;
animation-name: fade2;
animation-iteration-count: infinite;
}
.methodcoverage {
animation-duration: 15s;
animation-name: fade3;
animation-iteration-count: infinite;
}
]]>
</style>
<title>Code coverage</title>
<defs>
<linearGradient id="gradient" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<linearGradient id="c">
<stop offset="0" stop-color="#d40000"/>
<stop offset="1" stop-color="#ff2a2a"/>
</linearGradient>
<linearGradient id="a">
<stop offset="0" stop-color="#e0e0de"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
<linearGradient id="b">
<stop offset="0" stop-color="#37c837"/>
<stop offset="1" stop-color="#217821"/>
</linearGradient>
<linearGradient xlink:href="#a" id="e" x1="106.44" x2="69.96" y1="-11.96" y2="-46.84" gradientTransform="matrix(-.8426 -.00045 -.00045 -.8426 -94.27 -75.82)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#b" id="f" x1="56.19" x2="77.97" y1="-23.45" y2="10.62" gradientTransform="matrix(.8426 .00045 .00045 .8426 94.27 75.82)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#c" id="g" x1="79.98" x2="132.9" y1="10.79" y2="10.79" gradientTransform="matrix(.8426 .00045 .00045 .8426 94.27 75.82)" gradientUnits="userSpaceOnUse"/>
<mask id="mask">
<rect width="155" height="20" rx="3" fill="#fff"/>
</mask>
<g id="icon" transform="matrix(.04486 0 0 .04481 -.48 -.63)">
<rect width="52.92" height="52.92" x="-109.72" y="-27.13" fill="url(#e)" transform="rotate(-135)"/>
<rect width="52.92" height="52.92" x="70.19" y="-39.18" fill="url(#f)" transform="rotate(45)"/>
<rect width="52.92" height="52.92" x="80.05" y="-15.74" fill="url(#g)" transform="rotate(45)"/>
</g>
</defs>
<g mask="url(#mask)">
<rect x="0" y="0" width="90" height="20" fill="#444"/>
<rect x="90" y="0" width="20" height="20" fill="#c00"/>
<rect x="110" y="0" width="45" height="20" fill="#00B600"/>
<rect x="0" y="0" width="155" height="20" fill="url(#gradient)"/>
</g>
<g>
<path class="" stroke="#fff" d="M94 6.5 h12 M94 10.5 h12 M94 14.5 h12"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="Verdana,Arial,Geneva,sans-serif" font-size="11">
<a xlink:href="https://github.com/danielpalme/ReportGenerator" target="_top">
<title>Generated by: ReportGenerator 5.1.26.0</title>
<use xlink:href="#icon" transform="translate(3,1) scale(3.5)"/>
</a>
<text x="53" y="15" fill="#010101" fill-opacity=".3">Coverage</text>
<text x="53" y="14" fill="#fff">Coverage</text>
<text class="" x="132.5" y="15" fill="#010101" fill-opacity=".3">100%</text><text class="" x="132.5" y="14">100%</text>
</g>
<g>
<rect class="" x="90" y="0" width="65" height="20" fill-opacity="0"><title>Line coverage</title></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,82 @@
# To collect code coverage, you will need the following environment setup:
#
# - A "GODOT" environment variable pointing to the Godot executable
# - ReportGenerator installed
#
# dotnet tool install -g dotnet-reportgenerator-globaltool
#
# - A version of coverlet > 3.2.0.
#
# As of Jan 2023, this is not yet released.
#
# The included `nuget.config` file will allow you to install a nightly
# version of coverlet from the coverlet nightly nuget feed.
#
# dotnet tool install --global coverlet.console --prerelease.
#
# You can build coverlet yourself, but you will need to edit the path to
# coverlet below to point to your local build of the coverlet dll.
#
# If you need help with coverage, feel free to join the Chickensoft Discord.
# https://chickensoft.games
dotnet build --no-restore
coverlet `
"./.godot/mono/temp/bin/Debug" --verbosity detailed `
--target $env:GODOT `
--targetargs "--run-tests --coverage --quit-on-finish" `
--format "opencover" `
--output "./coverage/coverage.xml" `
--exclude-by-file "**/test/**/*.cs" `
--exclude-by-file "**/*Microsoft.NET.Test.Sdk.Program.cs" `
--exclude-by-file "**/Godot.SourceGenerators/**/*.cs" `
--exclude-assemblies-without-sources "missingall"
# Projects included via <ProjectReference> will be collected in code coverage.
# If you want to exclude them, replace the string below with the names of
# the assemblies to ignore. e.g.,
# $ASSEMBLIES_TO_REMOVE="-AssemblyToRemove1;-AssemblyToRemove2"
$ASSEMBLIES_TO_REMOVE = "-GodotHelper.Tests"
reportgenerator `
-reports:"./coverage/coverage.xml" `
-targetdir:"./coverage/report" `
"-assemblyfilters:$ASSEMBLIES_TO_REMOVE" `
"-classfilters:-GodotPlugins.Game.Main" `
-reporttypes:"Html;Badges"
# Copy badges into their own folder. The badges folder should be included in
# source control so that the README.md in the root can reference the badges.
$badgesPath = "./badges"
if (-not (Test-Path $badgesPath))
{
mkdir $badgesPath
}
mv -Force "./coverage/report/badge_branchcoverage.svg" "$badgesPath/branch_coverage.svg"
mv -Force "./coverage/report/badge_linecoverage.svg" "$badgesPath/line_coverage.svg"
# Determine OS, open coverage accordingly.
$os = (Get-CimInstance -ClassName Win32_OperatingSystem).Caption
if ($os -match "Windows")
{
Write-Output 'MS Windows'
Start-Process "coverage/report/index.htm"
}
elseif ($os -match "Linux")
{
Write-Output 'Linux'
xdg-open "coverage/report/index.htm"
}
elseif ($os -match "Mac OS X")
{
Write-Output 'Mac OS X'
open "coverage/report/index.htm"
}
else
{
Write-Output 'Other OS'
}

View File

@@ -0,0 +1,80 @@
#!/bin/bash
# To collect code coverage, you will need the following environment setup:
#
# - A "GODOT" environment variable pointing to the Godot executable
# - ReportGenerator installed
#
# dotnet tool install -g dotnet-reportgenerator-globaltool
#
# - A version of coverlet > 3.2.0.
#
# As of Jan 2023, this is not yet released.
#
# The included `nuget.config` file will allow you to install a nightly
# version of coverlet from the coverlet nightly nuget feed.
#
# dotnet tool install --global coverlet.console --prerelease.
#
# You can build coverlet yourself, but you will need to edit the path to
# coverlet below to point to your local build of the coverlet dll.
#
# If you need help with coverage, feel free to join the Chickensoft Discord.
# https://chickensoft.games
dotnet build --no-restore
coverlet \
"./.godot/mono/temp/bin/Debug" --verbosity detailed \
--target "$GODOT" \
--targetargs "--run-tests --coverage --quit-on-finish" \
--format "opencover" \
--output "./coverage/coverage.xml" \
--exclude-by-file "**/test/**/*.cs" \
--exclude-by-file "**/*Microsoft.NET.Test.Sdk.Program.cs" \
--exclude-by-file "**/Godot.SourceGenerators/**/*.cs" \
--exclude-assemblies-without-sources "missingall"
# Projects included via <ProjectReference> will be collected in code coverage.
# If you want to exclude them, replace the string below with the names of
# the assemblies to ignore. e.g.,
# ASSEMBLIES_TO_REMOVE="-AssemblyToRemove1;-AssemblyToRemove2"
ASSEMBLIES_TO_REMOVE="-GodotHelper.Tests"
reportgenerator \
-reports:"./coverage/coverage.xml" \
-targetdir:"./coverage/report" \
"-assemblyfilters:$ASSEMBLIES_TO_REMOVE" \
"-classfilters:-GodotPlugins.Game.Main" \
-reporttypes:"Html;Badges"
# Copy badges into their own folder. The badges folder should be included in
# source control so that the README.md in the root can reference the badges.
mkdir -p ./badges
mv ./coverage/report/badge_branchcoverage.svg ./badges/branch_coverage.svg
mv ./coverage/report/badge_linecoverage.svg ./badges/line_coverage.svg
# Determine OS, open coverage accordingly.
case "$(uname -s)" in
Darwin)
echo 'Mac OS X'
open coverage/report/index.htm
;;
Linux)
echo 'Linux'
open coverage/report/index.htm
;;
CYGWIN*|MINGW32*|MSYS*|MINGW*)
echo 'MS Windows'
start coverage/report/index.htm
;;
*)
echo 'Other OS'
;;
esac

View File

View File

@@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><g transform="translate(32 32)"><path d="m-16-32c-8.86 0-16 7.13-16 15.99v95.98c0 8.86 7.13 15.99 16 15.99h96c8.86 0 16-7.13 16-15.99v-95.98c0-8.85-7.14-15.99-16-15.99z" fill="#363d52"/><path d="m-16-32c-8.86 0-16 7.13-16 15.99v95.98c0 8.86 7.13 15.99 16 15.99h96c8.86 0 16-7.13 16-15.99v-95.98c0-8.85-7.14-15.99-16-15.99zm0 4h96c6.64 0 12 5.35 12 11.99v95.98c0 6.64-5.35 11.99-12 11.99h-96c-6.64 0-12-5.35-12-11.99v-95.98c0-6.64 5.36-11.99 12-11.99z" fill-opacity=".4"/></g><g stroke-width="9.92746" transform="matrix(.10073078 0 0 .10073078 12.425923 2.256365)"><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 919.24059 771.67186)"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164715 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426579-6.973692 9.2079702-13.9828876 13.621-19.449z" fill="#478cbf" transform="matrix(4.162611 0 0 -4.162611 104.69892 525.90697)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.162611 0 0 -4.162611 784.07144 817.24284)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 389.21484 625.67104)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.162611 0 0 -4.162611 367.36686 631.05679)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 511.99336 724.73954)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 634.78706 625.67104)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.162611 0 0 -4.162611 656.64056 631.05679)"/></g></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://da2tcc2mhkfgi"
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

View File

@@ -0,0 +1,24 @@
; 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
[application]
config/name="GodotHelper.Tests"
run/main_scene="res://test/Tests.tscn"
config/features=PackedStringArray("4.2", "C#", "Mobile")
config/icon="res://icon.svg"
[dotnet]
project/assembly_name="GodotHelper.Tests"
[rendering]
renderer/rendering_method="mobile"

View File

@@ -0,0 +1,13 @@
namespace GodotHelper.Tests;
using System.Reflection;
using Chickensoft.GoDotTest;
using Godot;
public partial class Tests : Node2D
{
public override void _Ready() => CallDeferred(MethodName.RunTests);
public void RunTests() =>
GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
}

View File

@@ -0,0 +1 @@
uid://d1ejsfsekh8yr

View File

@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://bv5dxd8hrc5g4"]
[ext_resource type="Script" path="res://test/Tests.cs" id="1_310o6"]
[node name="Node2D" type="Node2D"]
script = ExtResource("1_310o6")

View File

@@ -0,0 +1,24 @@
namespace GodotHelper.Tests;
using Chickensoft.GoDotTest;
using Godot;
using Shouldly;
public class PackageTest : TestClass
{
public PackageTest(Node testScene) : base(testScene) { }
[Test]
public void Initializes()
{
var package = new Package();
package.ShouldBeAssignableTo<Package>();
}
[Test]
public void MethodReturnsString()
{
var package = new Package();
package.Method().ShouldBe("Hello, world!");
}
}

View File

@@ -0,0 +1 @@
uid://c5puoyi2jgtlm

28
GodotHelper.sln Normal file
View File

@@ -0,0 +1,28 @@
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}") = "GodotHelper", "GodotHelper\GodotHelper.csproj", "{60A9D927-4B12-4E5F-B026-F0E8B0A9AD8F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotHelper.Tests", "GodotHelper.Tests\GodotHelper.Tests.csproj", "{8C8F7DDB-82ED-49FB-8C73-1F27182B62F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{60A9D927-4B12-4E5F-B026-F0E8B0A9AD8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60A9D927-4B12-4E5F-B026-F0E8B0A9AD8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60A9D927-4B12-4E5F-B026-F0E8B0A9AD8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60A9D927-4B12-4E5F-B026-F0E8B0A9AD8F}.Release|Any CPU.Build.0 = Release|Any CPU
{8C8F7DDB-82ED-49FB-8C73-1F27182B62F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C8F7DDB-82ED-49FB-8C73-1F27182B62F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C8F7DDB-82ED-49FB-8C73-1F27182B62F5}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{8C8F7DDB-82ED-49FB-8C73-1F27182B62F5}.Release|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<LangVersion>preview</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Nullable>enable</Nullable>
<CopyAllFiles>true</CopyAllFiles>
<RootNamespace>GodotHelper</RootNamespace>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<OutputPath>./nupkg</OutputPath>
<DebugType>portable</DebugType>
<Title>GodotHelper</Title>
<Version>0.0.0-devbuild</Version>
<Description>GodotHelper description.</Description>
<Copyright>© 2024 Ronnie Kisner</Copyright>
<Authors>Ronnie Kisner</Authors>
<Company>Ronnie Kisner</Company>
<PackageId>GodotHelper</PackageId>
<PackageReleaseNotes>GodotHelper release.</PackageReleaseNotes>
<PackageIcon>icon.png</PackageIcon>
<PackageTags />
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageProjectUrl></PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl></RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="\" />
<None Include="../LICENSE" Pack="true" PackagePath="\" />
<None Include="./icon.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<!-- Dependencies go here. -->
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SauceControl.InheritDoc" Version="2.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="GodotSharp" Version="4.6.2" />
</ItemGroup>
</Project>

BIN
GodotHelper/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@@ -0,0 +1,12 @@
namespace GodotHelper;
/// <summary>
/// Package class.
/// </summary>
public class Package
{
/// <summary>
/// Method.
/// </summary>
public string Method() => "Hello, world!";
}

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
# MIT License
Copyright (c) 2023 Ronnie Kisner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

162
README.md Normal file
View File

@@ -0,0 +1,162 @@
# GodotHelper
[![Chickensoft Badge][chickensoft-badge]][chickensoft-website] [![Discord][discord-badge]][discord] [![Read the docs][read-the-docs-badge]][docs] ![line coverage][line-coverage] ![branch coverage][branch-coverage]
A .NET template for quickly creating a C# nuget package for use with Godot 4.
---
<p align="center">
<img alt="GodotHelper" src="GodotHelper/icon.png" width="200">
</p>
## 🥚 Getting Started
This template allows you to easily create a nuget package for use in Godot 4 C# projects. Microsoft's `dotnet` tool allows you to easily create, install, and use templates.
```sh
# Install this template
dotnet new --install GodotHelper
# Generate a new project based on this template
dotnet new chickenpackage --name "MyPackageName" --param:author "My Name"
# Use Godot to generate files needed to compile the package's test project.
cd MyPackageName/MyPackageName.Tests/
$GODOT --headless --build-solutions --quit
dotnet build
```
## 💁 Getting Help
*Is this template broken? Encountering obscure C# build problems?* We'll be happy to help you in the [Chickensoft Discord server][discord].
## 🏝 Environment Setup
For the provided debug configurations and test coverage to work correctly, you must setup your development environment correctly. The [Chickensoft Setup Docs][setup-docs] describe how to setup your Godot and C# development environment, following Chickensoft's best practices.
### VSCode Settings
This template includes some Visual Studio Code settings in `.vscode/settings.json`. The settings facilitate terminal environments on Windows (Git Bash, PowerShell, Command Prompt) and macOS (zsh), as well as fixing some syntax colorization issues that Omnisharp suffers from. You'll also find settings that enable editor config support in Omnisharp and the .NET Roslyn analyzers for a more enjoyable coding experience.
> Please double-check that the provided VSCode settings don't conflict with your existing settings.
## .NET Versioning
The included [`global.json`](./global.json) specifies the version of the .NET SDK that the included projects should use. It also specifies the `Godot.NET.Sdk` version that the included test project should use (since tests run inside an actual Godot game so you can use the full Godot API to verify your package is working as intended).
## 🐞 Debugging
You can debug the included test project for your package in `GodotHelper.Tests/` by opening the root of this repository in VSCode and selecting one of the launch configurations: `Debug Tests` or `Debug Current Test`.
> For the launch profile `Debug Current Test` to work, your test file must share the same name as the test class inside of it. For example, a test class named `PackageTest` must reside in a test file named `PackageTest.cs`.
The launch profiles will trigger a build (without restoring packages) and then instruct .NET to run Godot 4 (while communicating with VSCode for interactive debugging).
> **Important:** You must setup a `GODOT` environment variable for the launch configurations above. If you're using [GodotEnv] to install and manage Godot versions, you're already setup! For more info, see the [Chickensoft Setup Docs][setup-docs].
## 👷 Testing
By default, a test project in `GodotHelper.Tests/` is created for you to write tests for your package. [GoDotTest] is already included and setup, allowing you to focus on development and testing.
[GoDotTest] is an easy-to-use testing framework for Godot and C# that allows you to run tests from the command line, collect code coverage, and debug tests in VSCode.
The project is configured to allow tests to be easily run and debugged from VSCode or executed via CI/CD workflows, without having to include the test files or test dependencies in the final release build.
The `Main.tscn` and `Main.cs` scene and script file are the entry point of your game. In general, you probably won't need to modify these unless you're doing something highly custom. If the game isn't running in test mode (or it's a release build), it will just immediately change the scene to `game/Game.tscn`. In general, prefer editing `game/Game.tscn` over `Main.tscn`.
If you run Godot with the `--run-tests` command line argument, the game will run the tests instead of switching to the game scene located at `game/Game.tscn`. The provided debug configurations in `.vscode/launch.json` allow you to easily debug tests (or just the currently open test, provided its filename matches its class name).
Please see `test/ExampleTest.cs` and the [GoDotTest] readme for more examples.
## 🚦 Test Coverage
Code coverage requires a few `dotnet` global tools to be installed first. You should install these tools from the root of the project directory.
```sh
dotnet tool install --global coverlet.console
dotnet tool update --global coverlet.console
dotnet tool install --global dotnet-reportgenerator-globaltool
dotnet tool update --global dotnet-reportgenerator-globaltool
```
> Running `dotnet tool update` for the global tool is often necessary on Apple Silicon computers to ensure the tools are installed correctly.
You can collect code coverage and generate coverage badges by running the bash script in `test/coverage.sh` (on Windows, you can use the Git Bash shell that comes with git).
```sh
# Must give coverage script permission to run the first time it is used.
chmod +x test/.coverage.sh
# Run code coverage:
cd GodotHelper.Tests
./coverage.sh
```
You can also run test coverage through VSCode by opening the command palette and selecting `Tasks: Run Task` and then choosing `coverage`.
## 🏭 CI/CD
This package includes various GitHub Actions workflows to make developing and deploying your package easier.
### 🚥 Tests
Tests run on every push or pull request to the repository. You can configure which platforms you want to run tests on in [`.github/workflows/tests.yaml`](.github/workflows/tests.yaml).
By default, tests run each platform (macOS, Windows, and Linux) using the latest beta version of Godot 4.
Tests are executed by running the Godot test project in `GodotHelper.Tests` from the command line and passing in the relevant arguments to Godot so that [GoDotTest] can discover and run tests.
### 🧑‍🏫 Spellcheck
A spell check runs on every push or pull request to the repository. Spellcheck settings can be configured in [`.github/workflows/spellcheck.yaml`](.github/workflows/spellcheck.yaml)
The [Code Spell Checker][cspell] plugin for VSCode is recommended to help you catch typos before you commit them. If you need add a word to the dictionary, you can add it to the `cspell.json` file.
You can also words to the local `cspell.json` file from VSCode by hovering over a misspelled word and selecting `Quick Fix...` and then `Add "{word}" to config: GodotPackage/cspell.json`.
![Fix Spelling](docs/spelling_fix.png)
### 📦 Release
The included workflow in [`.github/workflows/release.yaml`](.github/workflows/publish.yaml) can be manually dispatched when you're ready to make a new release. Once you specify `major`, `minor`, or `patch` for the version bump strategy, the workflow will build your package with the updated version and release it on both GitHub and nuget.
The accompanying [`.github/workflows/auto_release.yaml`](.github/workflows/auto_release.yaml) will trigger the publish workflow if it detects a new commit in main that is a routine dependency update from renovatebot. Since Renovatebot is configured to auto-merge dependency updates, your package will automatically be published to Nuget when a new version of Godot.NET.Sdk is released or other packages you depend on are updated. If this behavior is undesired, remove the `"automerge": true` property from [`renovate.json`](./renovate.json).
> To publish to nuget, you need to configure a repository or organization secret within GitHub named `NUGET_API_KEY` that contains your Nuget API key. Make sure you setup `NUGET_API_KEY` as a **secret** (rather than an environment variable) to keep it safe!
### 🏚 Renovatebot
This repository includes a [`renovate.json`](./renovate.json) configuration for use with [Renovatebot]. Renovatebot can automatically open and merge pull requests to help you keep your dependencies up to date when it detects new dependency versions have been released.
![Renovatebot Pull Request](docs/renovatebot_pr.png)
> Unlike Dependabot, Renovatebot is able to combine all dependency updates into a single pull request — a must-have for Godot C# repositories where each sub-project needs the same Godot.NET.Sdk versions. If dependency version bumps were split across multiple repositories, the builds would fail in CI.
The easiest way to add Renovatebot to your repository is to [install it from the GitHub Marketplace][get-renovatebot]. Note that you have to grant it access to each organization and repository you want it to monitor.
The included `renovate.json` includes a few configuration options to limit how often Renovatebot can open pull requests as well as regex's to filter out some poorly versioned dependencies to prevent invalid dependency version updates.
If your project is setup to require approvals before pull requests can be merged *and* you wish to take advantage of Renovatebot's auto-merge feature, you can install the [Renovate Approve][renovate-approve] bot to automatically approve the Renovate dependency PR's. If you need two approvals, you can install the identical [Renovate Approve 2][renovate-approve-2] bot. See [this][about-renovate-approvals] for more information.
---
🐣 Package generated from a 🐤 Chickensoft Template — <https://chickensoft.games>
[chickensoft-badge]: https://chickensoft.games/img/badges/chickensoft_badge.svg
[chickensoft-website]: https://chickensoft.games
[discord-badge]: https://chickensoft.games/img/badges/discord_badge.svg
[discord]: https://discord.gg/gSjaPgMmYW
[read-the-docs-badge]: https://chickensoft.games/img/badges/read_the_docs_badge.svg
[docs]: https://chickensoft.games/docs
[line-coverage]: GodotHelper.Tests/badges/line_coverage.svg
[branch-coverage]: GodotHelper.Tests/badges/branch_coverage.svg
[GoDotTest]: https://github.com/chickensoft-games/go_dot_test
[setup-docs]: https://chickensoft.games/docs/setup
[cspell]: https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker
[Renovatebot]: https://www.mend.io/free-developer-tools/renovate/
[get-renovatebot]: https://github.com/apps/renovate
[renovate-approve]: https://github.com/apps/renovate-approve
[renovate-approve-2]: https://github.com/apps/renovate-approve-2
[about-renovate-approvals]: https://stackoverflow.com/a/66575885
[GodotEnv]: https://github.com/chickensoft-games/GodotEnv

70
cspell.json Normal file
View File

@@ -0,0 +1,70 @@
{
"files": [
"**/*.*"
],
"ignorePaths": [
"**/*.tscn",
"**/*.import",
"**/badges/**/*.*",
"**/coverage/**/*.*",
"**/.godot/**/*.*",
"**/obj/**/*.*",
"**/bin/**/*.*",
"**/nupkg/**/*.*"
],
"words": [
"assemblyfilters",
"automerge",
"branchcoverage",
"brandedoutcast",
"buildtransitive",
"camelcase",
"chickenpackage",
"Chickensoft",
"classfilters",
"contentfiles",
"CYGWIN",
"devbuild",
"endregion",
"Finalizer",
"Finalizers",
"globaltool",
"godotengine",
"godotpackage",
"issuecomment",
"justalemon",
"lcov",
"lihop",
"linecoverage",
"methodcoverage",
"missingall",
"msbuild",
"MSYS",
"nameof",
"Nerdbank",
"netstandard",
"NOLOGO",
"nupkg",
"Omnisharp",
"opencover",
"OPTOUT",
"paramref",
"pascalcase",
"Postinitialize",
"Predelete",
"renovatebot",
"reportgenerator",
"reporttypes",
"Shouldly",
"subfolders",
"targetargs",
"targetdir",
"tscn",
"typeof",
"typeparam",
"typeparamref",
"ulong",
"Unparented",
"Xunit"
]
}

BIN
docs/renovatebot_pr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
docs/spelling_fix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

9
global.json Normal file
View File

@@ -0,0 +1,9 @@
{
"sdk": {
"version": "8.0.125",
"rollForward": "latestMinor"
},
"msbuild-sdks": {
"Godot.NET.Sdk": "4.6.2"
}
}

4
renovate.json Normal file
View File

@@ -0,0 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>chickensoft-games/renovate:godot"]
}