From 4279f9c2cb2b489243ee26251fd21c19dd6f08a3 Mon Sep 17 00:00:00 2001 From: Dominic Bytes <305052051+dominicbytes@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:28:28 -0500 Subject: [PATCH] Add Redot 26.2 compatibility --- .github/workflows/redot-compatibility.yml | 52 +++++++++++++++++ README.md | 23 +++++++- .../editor/setup/page_game_authorization.gd | 2 +- .../setup/page_overlay_authorization.gd | 2 +- addons/twitcher/plugin.cfg | 4 +- project.godot | 4 +- tests/redot_compatibility.gd | 56 +++++++++++++++++++ tests/redot_compatibility.gd.uid | 1 + tests/sprite_frame_effect.tscn | 6 +- 9 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/redot-compatibility.yml create mode 100644 tests/redot_compatibility.gd create mode 100644 tests/redot_compatibility.gd.uid diff --git a/.github/workflows/redot-compatibility.yml b/.github/workflows/redot-compatibility.yml new file mode 100644 index 00000000..a2aa0fee --- /dev/null +++ b/.github/workflows/redot-compatibility.yml @@ -0,0 +1,52 @@ +name: Redot compatibility + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + redot-26-2: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Download Redot 26.2 + shell: bash + run: | + set -euo pipefail + mkdir -p "$RUNNER_TEMP/redot" + curl --fail --location --retry 3 \ + --output "$RUNNER_TEMP/redot/redot.zip" \ + https://github.com/Redot-Engine/redot-engine/releases/download/redot-26.2-stable/Redot_v26.2-stable_linux_x64.zip + echo "f474d890806c41af15513cf5a8600243e241882e11b68dbb95660e3465b5b1e4 $RUNNER_TEMP/redot/redot.zip" | sha256sum --check + unzip -q "$RUNNER_TEMP/redot/redot.zip" -d "$RUNNER_TEMP/redot/bin" + REDOT_BIN="$(find "$RUNNER_TEMP/redot/bin" -type f -iname 'redot*' | head -n 1)" + chmod +x "$REDOT_BIN" + echo "REDOT_BIN=$REDOT_BIN" >> "$GITHUB_ENV" + + - name: Verify engine version + run: '"$REDOT_BIN" --version' + + - name: Import project and compile addon + shell: bash + run: | + set -euo pipefail + "$REDOT_BIN" --headless --path . --import 2>&1 | tee "$RUNNER_TEMP/redot-import.log" + if grep -E 'SCRIPT ERROR|Parse Error|Failed to load script|Failed loading resource' "$RUNNER_TEMP/redot-import.log"; then + exit 1 + fi + + - name: Run compatibility probe + shell: bash + run: | + set -euo pipefail + "$REDOT_BIN" --headless --path . --script res://tests/redot_compatibility.gd 2>&1 | tee "$RUNNER_TEMP/redot-probe.log" + if grep -E 'SCRIPT ERROR|Parse Error|Failed to load script|Failed loading resource' "$RUNNER_TEMP/redot-probe.log"; then + exit 1 + fi + grep -F 'Twitcher Redot compatibility probe passed' "$RUNNER_TEMP/redot-probe.log" diff --git a/README.md b/README.md index 3809a08b..11808ba2 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Twitcher +> **Redot compatibility fork:** This branch preserves Twitcher's Godot support while targeting +> Redot LTS 26.2. The editor plugin, setup wizard, and runtime `TwitchService` are validated with +> Redot `26.2.stable.official.4f5b14aba`. + [![Godot Asset Library](https://img.shields.io/badge/Godot%20Asset%20Library-Twitcher-blue?style=flat-square)](https://godotengine.org/asset-library/asset/2629) [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/kanimaru/twitcher/blob/v2/LICENSE) [![Twitch](https://img.shields.io/badge/Support_on_Twitch-kani_dev-purple?style=flat-square&logo=twitch)](https://www.twitch.tv/kani_dev/) [![Documentation](https://img.shields.io/badge/Twitcher-Documentation-purple?style=flat-square&logo=readthedocs)](https://twitcher.kani.dev/) -**Seamless Twitch Integration for Godot 4.4+** +**Seamless Twitch Integration for Godot 4.4+ and Redot 26.2** Twitcher provides a comprehensive toolkit to effortlessly connect your Godot Engine games, overlays, or applications to the Twitch platform. Integrate real-time chat, respond to events like @@ -29,6 +33,23 @@ follows and subscriptions, manage rewards, handle chat commands, and utilize the * **Important:** The addon *must* reside in the exact path `res://addons/twitcher` for internal resources to load correctly. 2. **Enable Plugin:** Go to `Project -> Project Settings -> Plugins` and check the `Enable` box next to "Twitcher". +### Redot + +Copy `addons/twitcher` to the same path in your Redot project, then enable Twitcher under +`Project -> Project Settings -> Plugins`. This fork uses the same public API and scene paths as +upstream Twitcher. + +The development project can be checked with: + +```powershell +redot --headless --path . --import +redot --headless --path . --script res://tests/redot_compatibility.gd +``` + +The probe loads the editor plugin, both setup-wizard variants, and an instantiated runtime +`TwitchService`. Live Twitch authentication and EventSub delivery require Twitch credentials and +are intentionally separate integration tests. + ## Quick Start & Documentation 1. **Run Setup Wizard:** After enabling the plugin, the easiest way to configure authentication is via the Setup Wizard: diff --git a/addons/twitcher/editor/setup/page_game_authorization.gd b/addons/twitcher/editor/setup/page_game_authorization.gd index 0833faec..56632162 100644 --- a/addons/twitcher/editor/setup/page_game_authorization.gd +++ b/addons/twitcher/editor/setup/page_game_authorization.gd @@ -49,7 +49,7 @@ func bootstrap() -> void: var twitch_service: TwitchService = root_node.get_node(^"TwitchService") twitch_service.token = TwitchEditorSettings.game_oauth_token twitch_service.oauth_setting = TwitchEditorSettings.game_oauth_setting - EditorInterface.add_root_node(root_node) + get_tree().edited_scene_root = root_node func _on_to_documentation_pressed() -> void: diff --git a/addons/twitcher/editor/setup/page_overlay_authorization.gd b/addons/twitcher/editor/setup/page_overlay_authorization.gd index c60560a2..0f2f1267 100644 --- a/addons/twitcher/editor/setup/page_overlay_authorization.gd +++ b/addons/twitcher/editor/setup/page_overlay_authorization.gd @@ -66,7 +66,7 @@ func bootstrap() -> void: subscription.condition[key] = TwitchEditorSettings.default_user.id subscription.set_meta(key + "_user", TwitchEditorSettings.default_user) - EditorInterface.add_root_node(root_node) + get_tree().edited_scene_root = root_node func _set_authorized() -> void: diff --git a/addons/twitcher/plugin.cfg b/addons/twitcher/plugin.cfg index c0c1f1fa..99f473c2 100644 --- a/addons/twitcher/plugin.cfg +++ b/addons/twitcher/plugin.cfg @@ -1,7 +1,7 @@ [plugin] name="Twitcher" -description="A plugin to use Twitch API in Godot." +description="A plugin to use the Twitch API in Godot and Redot." author="kani_dev" -version="2.5.1" +version="2.5.1-redot.1" script="plugin.gd" diff --git a/project.godot b/project.godot index 8d155198..dd1a6bc4 100644 --- a/project.godot +++ b/project.godot @@ -12,8 +12,8 @@ config_version=5 config/name="Twitcher" run/main_scene="uid://5lyf04rwo1mf" -config/features=PackedStringArray("4.6", "Forward Plus") -config/icon="uid://pnr400301dhc" +config/features=PackedStringArray("26.2", "Redot") +config/icon="res://addons/twitcher/assets/twitcher-icon.svg" [debug] diff --git a/tests/redot_compatibility.gd b/tests/redot_compatibility.gd new file mode 100644 index 00000000..d7a6929b --- /dev/null +++ b/tests/redot_compatibility.gd @@ -0,0 +1,56 @@ +extends SceneTree + +const REQUIRED_SCRIPTS: PackedStringArray = [ + "res://addons/twitcher/plugin.gd", +] + +const REQUIRED_SCENES: PackedStringArray = [ + "res://addons/twitcher/editor/setup/page_game_authorization.tscn", + "res://addons/twitcher/editor/setup/page_overlay_authorization.tscn", + "res://addons/twitcher/twitch_service.tscn", +] + + +func _init() -> void: + call_deferred(&"_run_probe") + + +func _run_probe() -> void: + await process_frame + for path: String in REQUIRED_SCRIPTS: + if load(path) == null: + push_error("Failed to load required Twitcher script: %s" % path) + quit(1) + return + + for path: String in REQUIRED_SCENES: + var scene: PackedScene = load(path) + if scene == null: + push_error("Failed to load required Twitcher scene: %s" % path) + quit(1) + return + if path.ends_with("twitch_service.tscn"): + var instance: Node = scene.instantiate() + if instance.get_script() == null: + push_error("Twitcher runtime scene root has no script: %s" % path) + instance.free() + quit(1) + return + root.add_child(instance) + instance.queue_free() + await process_frame + else: + var state: SceneState = scene.get_state() + var root_script: Script = null + for property_index: int in state.get_node_property_count(0): + if state.get_node_property_name(0, property_index) == &"script": + root_script = state.get_node_property_value(0, property_index) + break + if root_script == null: + push_error("Twitcher editor scene root has no script: %s" % path) + quit(1) + return + + print("Twitcher Redot compatibility probe passed on Redot %s." % Engine.get_version_info().string) + await create_timer(3.0).timeout + quit() diff --git a/tests/redot_compatibility.gd.uid b/tests/redot_compatibility.gd.uid new file mode 100644 index 00000000..d682d20d --- /dev/null +++ b/tests/redot_compatibility.gd.uid @@ -0,0 +1 @@ +uid://fvbx576yivc2 diff --git a/tests/sprite_frame_effect.tscn b/tests/sprite_frame_effect.tscn index 8439aa8b..fc85fb1a 100644 --- a/tests/sprite_frame_effect.tscn +++ b/tests/sprite_frame_effect.tscn @@ -1,7 +1,7 @@ -[gd_scene load_steps=3 format=3 uid="uid://ucvrw0jylplf"] +[gd_scene load_steps=3 format=3 uid="uid://ucvrw0jylplf"] [ext_resource type="Script" uid="uid://dkppamu55n5j1" path="res://tests/sprite_frame_effect.gd" id="1_shaxi"] -[ext_resource type="SpriteFrames" uid="uid://da5n4t1o5ot67" path="res://documentation/create-credentials.gif" id="2_hw5pt"] +[ext_resource type="SpriteFrames" path="res://documentation/create-credentials.gif" id="2_hw5pt"] [node name="SpriteFrameEffect" type="Control"] layout_mode = 3 @@ -21,4 +21,4 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -bbcode_enabled = true \ No newline at end of file +bbcode_enabled = true