Note: I'm from Brazil and I'm looking for job, feel free to contact me 🤣
Discord Social SDK
Wrapper around Discord Social SDK.
[!IMPORTANT]
Support for:
- Linux (x86_64)
- Windows
If you want to request support for other build, make an issue.
If you already knows how to make other build, feel free to make a pull request.
Usage
Is suppose to be a close one-to-one with the C++ SDK, so looking at the C++ Getting Started is recommended to understand how the SDK works.
Here is the final code from Getting Started but using this extension:
extends Node
# Replace with your Discord Application ID
const APPLICATION_ID = 1349146942634065960
var client := DiscordppClient.new()
func _ready() -> void:
print("🚀 Initializing Discord SDK...")
client.AddLogCallback(
func(message: String, severity: DiscordppLoggingSeverity.Enum):
print("[%s] %s" % [severity, message]),
DiscordppLoggingSeverity.Info
)
client.SetStatusChangedCallback(
func(status: DiscordppClientStatus.Enum, error: DiscordppClientError.Enum, errorDetail: int):
print("🔄 Status changed: %s" % status)
if status == DiscordppClientStatus.Ready:
print("✅ Client is ready! You can now call SDK functions.")
print("👥 Friends Count: %s" % client.GetRelationships().size())
var activity := DiscordppActivity.new()
activity.SetType(DiscordppActivityTypes.Playing)
activity.SetState("In Competitive Match")
activity.SetDetails("Rank: Diamond II")
client.UpdateRichPresence(activity,
func(result: DiscordppClientResult):
if result.Successful():
print("🎮 Rich Presence updated successfully!")
else:
print("❌ Rich Presence update failed")
)
elif error != DiscordppClientError.None:
print("❌ Connection Error: %s - Details: %s" % [error, errorDetail])
)
var code_verifier = client.CreateAuthorizationCodeVerifier()
var args := DiscordppAuthorizationArgs.new()
args.SetClientId(APPLICATION_ID)
args.SetScopes(DiscordppClient.GetDefaultPresenceScopes())
args.SetCodeChallenge(code_verifier.Challenge())
client.Authorize(args,
func(result: DiscordppClientResult, code: String, redirectUri: String):
if not result.Successful():
print("❌ Authentication Error: %s" % result.Error())
else:
print("✅ Authorization successful! Getting access token...")
client.GetToken(APPLICATION_ID, code, code_verifier.Verifier(), redirectUri,
func(
result: DiscordppClientResult,
accessToken: String,
refreshToken: String,
tokenType: DiscordppAuthorizationTokenType.Enum,
expiresIn: int,
scopes: String
):
print("🔓 Access token received! Establishing connection...")
client.UpdateToken(
DiscordppAuthorizationTokenType.Bearer,
accessToken,
func(result: DiscordppClientResult):
if result.Successful():
print("🔑 Token updated, connecting to Discord...")
client.Connect()
)
)
)
func _process(_delta: float) -> void:
Discordpp.RunCallbacks()
Installation
It's available in Godot Asset Library, so you can search and install through Godot.
Alternative:
- Go to releases from Github
- Download latest release ZIP
- Extract
addons
directory from ZIP- It will be inside a
demo
directory
- It will be inside a
- Move
addons
directory to your project directory- If your project already have an
addons
directory, copyaddons/discord_social_sdk
to your projectaddons
- If your project already have an
Examples
Directory discord-social-sdk/demo/examples contains many examples.
Examples in this repository will be mostly convertions from the official C++ documentation, so I do recommend you to adapt to your like. For example, we don't need to use lambda functions everywhere:
func _ready() -> void:
# ...
client.Authorize(args, _on_authorization_result.bind(code_verifier))
func _on_authorization_result(
result: DiscordppClientResult,
code: String,
redirectUri: String,
code_verifier: DiscordppAuthorizationCodeVerifier
):
if not result.Successful():
print("❌ Authentication Error: %s" % result.Error())
else:
print("✅ Authorization successful! Getting access token...")
client.GetToken(APPLICATION_ID, code, code_verifier.Verifier(), redirectUri, _on_token_result)
func _on_token_result(
result: DiscordppClientResult,
accessToken: String,
refreshToken: String,
tokenType: DiscordppAuthorizationTokenType.Enum,
expiresIn: int,
scopes: String
):
print("🔓 Access token received! Establishing connection...")
client.UpdateToken(DiscordppAuthorizationTokenType.Bearer, accessToken, _on_token_update)
func _on_token_update(result: DiscordppClientResult):
if result.Successful():
print("🔑 Token updated, connecting to Discord...")
client.Connect()
Instead of running Discordpp.RunCallbacks()
every frame, you could use a timer which would reduce the frequence which your code stop to run callbacks.
var timer = Timer.new()
timer.wait_time = 1
timer.autostart = true
timer.timeout.connect(func(): Discordpp.RunCallbacks())
get_tree().root.add_child.call_deferred(timer)
Questions
Why some functions return
Variant
?
GDScript doesn't has an alternative to std::optional<T>
, so we just return a Variant which can hold a null
or an actual value.
Why exists many functions like
Discordpp.EnumToString0()
,Discordpp.EnumToString1()
,Discordpp.EnumToString2()
, ...?
GDScript doesn't support function overloading, so I just made one function for each option.
Why doesn't follow GDScript style guide?
I made this decision to avoid solving conflict between methods names because, as mentioned above, GDScript doesn't support function overloading.
Example: discordpp:Client
has Connect()
and Object
has connect()
.
If I were to snake_case the discordpp:Client
method, I would need to find another name for it.
Development
This GDExtension is all built using Python and nothing should be add manually at src
. If this is weird for you, listen to me...
All that I want is to use the SDK from GDScript, without assuming any setup from the user, which means that I can guess all the logic behind the methods wrappers:
flowchart TD
gd_to_c[gdscript types to c types]
return_void{return void?}
call_method1["<pre>method(args)</pre>"]
call_method2["<pre>auto r = method(args)</pre>"]
c_to_gd[c type to gdscript type]
gd_to_c-->return_void
return_void--"yes"-->call_method1
return_void--"no"-->call_method2
call_method2-->c_to_gd
Knowing this I automated generating all the GDExtension source code through Python code, which is a language that I prefer to user when I don't have to care about low level/security/speed/anything.
Now that you understand why everything is done through Python, let me explain what is done through Python:
- Clean headers
- Parse headers
- Build source code
- Document details
flowchart LR
Clean --> Parse
Parse --> Build
Build --> Document
Clean: Remove unnecessary informations from headers. We are not a C/C++ compiler, so we don't need many lines from the headers and this makes our parser job easier.
Parse: Scan headers to collect useful informations for us. This is closer to be a tokenizer + parser but built together because this is much easier than a scanning a complete programming language.
Build: Build our GDExtension source code (writing .cpp
and .h
files in src/
).
Document: Update the generated XML documentation from Godot (files in doc_classes/
) with some details to help.
Prerequisites
I'm using Ubuntu, please adapt this list to your operating system.
- Godot
- SCons
sudo apt install scons
- Mingw-w64
sudo apt install mingw-w64
- Python >=3.12
- Included by default
- Clang format
sudo apt install clang-format
- VSCode
- Discord SDK for C++
Tree
.
├── demo/
│ └── Godot project containing the addon, examples and tests
├── doc_classes/
│ └── Project classes documentation
├── godot-cpp/
│ └── C++ bindings for GDExtension API
├── include/
│ └── Discord headers
├── lib/
│ └── Discord libs
├── scripts/
│ └── Python scripts
└── src/
└── GDExtension source codes and headers
Step by step
# Unzip libraries and headers to correct directories.
# Assuming that repository "discord-social-sdk" and "DiscordSocialSdk*.zip" are in the same directory.
unzip DiscordSocialSdk*.zip -d /tmp/
cp -r /tmp/discord_social_sdk/lib/release/* discord-social-sdk/lib/
cp -r /tmp/discord_social_sdk/bin/release/* discord-social-sdk/lib/
cp -r /tmp/discord_social_sdk/include/* discord-social-sdk/include/
rm -rf /tmp/discord_social_sdk
# Making sure that headers are formatted.
clang-format -i --style=file:.clang-format include/cdiscord.h
clang-format -i --style=file:.clang-format include/discordpp.h
# Clear files generated during previous execution.
rm -rf doc_classes
rm -rf src
# Generate GDExtension API files.
cd godot-cpp
godot --dump-extension-api
scons platform=linux custom_api_file=extension_api.json
cd ..
# Generate GDExtension source code.
python3 scripts/main.py
# Generate GDExtension library.
scons platform=linux # Debug
scons platform=linux target=template_release # Release
scons platform=windows # Debug
scons platform=windows target=template_release # Release
# Open project, at least once, to be able to generate GDExtension documentation.
godot ./demo/project.godot
# Generate GDExtension documentation.
cd demo
godot --doctool ../ --gdextension-docs
cd ..
# Rerun to update GDExtension documentation.
python3 scripts/main.py
# Generate ZIP file for the Asset Library.
zip -r discord_social_sdk.zip demo/addons/discord_social_sdk/**
[!WARNING] Make sure that Godot version match with
godot-cpp
repository.