Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discord integration #363

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ debian/jellyfin-media-player.substvars
dist.zip
obj-x86_64-linux-gnu/
deployment/dist
.vscode/
25 changes: 0 additions & 25 deletions .vscode/settings.json

This file was deleted.

4 changes: 2 additions & 2 deletions bundle/win/Bundle.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@
<MsiProperty Name="ADDDESKTOPSHORTCUT" Value="[AddDesktopShortcut]" />
</MsiPackage>
<ExePackage Id="vcredist_repair"
SourceFile="C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Redist\MSVC\v142\vcredist_x64.exe"
SourceFile="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Redist\MSVC\v142\vcredist_x64.exe"
Name="vcredist_x64.exe"
InstallCommand="/repair /quiet /norestart"
InstallCondition="Bad_VCRedist"
Expand All @@ -256,7 +256,7 @@
<ExitCode Value="1638" Behavior="success"/>
</ExePackage>
<ExePackage Id="vcredist"
SourceFile="C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Redist\MSVC\v142\vcredist_x64.exe"
SourceFile="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Redist\MSVC\v142\vcredist_x64.exe"
Name="vcredist_x64.exe"
InstallCommand="/install /quiet /norestart"
InstallCondition="NOT Bad_VCRedist"
Expand Down
1 change: 1 addition & 0 deletions external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILER_FLAGS_THIRD_PARTY}")

add_subdirectory(qslog)
add_subdirectory(qhttp)
add_subdirectory(discord)

if(APPLE)
add_subdirectory(plistparser)
Expand Down
13 changes: 13 additions & 0 deletions external/discord/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
include_directories(.)

file(GLOB DISCORD_SRC
"*.h"
"*.cpp"
)

add_library(discord STATIC
${DISCORD_SRC}
)
# add_library(discord discord_game_sdk.dll.lib)
target_link_libraries(discord D:/Projects/jellyfin-media-player/external/discord/discord_game_sdk.dll.lib)
set_target_properties(discord PROPERTIES LINKER_LANGUAGE C)
99 changes: 99 additions & 0 deletions external/discord/achievement_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "achievement_manager.h"

#include "core.h"

#include <cstring>
#include <memory>

namespace discord {

class AchievementEvents final {
public:
static void DISCORD_CALLBACK OnUserAchievementUpdate(void* callbackData,
DiscordUserAchievement* userAchievement)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}

auto& module = core->AchievementManager();
module.OnUserAchievementUpdate(*reinterpret_cast<UserAchievement const*>(userAchievement));
}
};

IDiscordAchievementEvents AchievementManager::events_{
&AchievementEvents::OnUserAchievementUpdate,
};

void AchievementManager::SetUserAchievement(Snowflake achievementId,
std::uint8_t percentComplete,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->set_user_achievement(
internal_, achievementId, percentComplete, cb.release(), wrapper);
}

void AchievementManager::FetchUserAchievements(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->fetch_user_achievements(internal_, cb.release(), wrapper);
}

void AchievementManager::CountUserAchievements(std::int32_t* count)
{
if (!count) {
return;
}

internal_->count_user_achievements(internal_, reinterpret_cast<int32_t*>(count));
}

Result AchievementManager::GetUserAchievement(Snowflake userAchievementId,
UserAchievement* userAchievement)
{
if (!userAchievement) {
return Result::InternalError;
}

auto result = internal_->get_user_achievement(
internal_, userAchievementId, reinterpret_cast<DiscordUserAchievement*>(userAchievement));
return static_cast<Result>(result);
}

Result AchievementManager::GetUserAchievementAt(std::int32_t index,
UserAchievement* userAchievement)
{
if (!userAchievement) {
return Result::InternalError;
}

auto result = internal_->get_user_achievement_at(
internal_, index, reinterpret_cast<DiscordUserAchievement*>(userAchievement));
return static_cast<Result>(result);
}

} // namespace discord
34 changes: 34 additions & 0 deletions external/discord/achievement_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "types.h"

namespace discord {

class AchievementManager final {
public:
~AchievementManager() = default;

void SetUserAchievement(Snowflake achievementId,
std::uint8_t percentComplete,
std::function<void(Result)> callback);
void FetchUserAchievements(std::function<void(Result)> callback);
void CountUserAchievements(std::int32_t* count);
Result GetUserAchievement(Snowflake userAchievementId, UserAchievement* userAchievement);
Result GetUserAchievementAt(std::int32_t index, UserAchievement* userAchievement);

Event<UserAchievement const&> OnUserAchievementUpdate;

private:
friend class Core;

AchievementManager() = default;
AchievementManager(AchievementManager const& rhs) = delete;
AchievementManager& operator=(AchievementManager const& rhs) = delete;
AchievementManager(AchievementManager&& rhs) = delete;
AchievementManager& operator=(AchievementManager&& rhs) = delete;

IDiscordAchievementManager* internal_;
static IDiscordAchievementEvents events_;
};

} // namespace discord
177 changes: 177 additions & 0 deletions external/discord/activity_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "activity_manager.h"

#include "core.h"

#include <cstring>
#include <memory>

namespace discord {

class ActivityEvents final {
public:
static void DISCORD_CALLBACK OnActivityJoin(void* callbackData, char const* secret)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}

auto& module = core->ActivityManager();
module.OnActivityJoin(static_cast<const char*>(secret));
}

static void DISCORD_CALLBACK OnActivitySpectate(void* callbackData, char const* secret)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}

auto& module = core->ActivityManager();
module.OnActivitySpectate(static_cast<const char*>(secret));
}

static void DISCORD_CALLBACK OnActivityJoinRequest(void* callbackData, DiscordUser* user)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}

auto& module = core->ActivityManager();
module.OnActivityJoinRequest(*reinterpret_cast<User const*>(user));
}

static void DISCORD_CALLBACK OnActivityInvite(void* callbackData,
EDiscordActivityActionType type,
DiscordUser* user,
DiscordActivity* activity)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}

auto& module = core->ActivityManager();
module.OnActivityInvite(static_cast<ActivityActionType>(type),
*reinterpret_cast<User const*>(user),
*reinterpret_cast<Activity const*>(activity));
}
};

IDiscordActivityEvents ActivityManager::events_{
&ActivityEvents::OnActivityJoin,
&ActivityEvents::OnActivitySpectate,
&ActivityEvents::OnActivityJoinRequest,
&ActivityEvents::OnActivityInvite,
};

Result ActivityManager::RegisterCommand(char const* command)
{
auto result = internal_->register_command(internal_, const_cast<char*>(command));
return static_cast<Result>(result);
}

Result ActivityManager::RegisterSteam(std::uint32_t steamId)
{
auto result = internal_->register_steam(internal_, steamId);
return static_cast<Result>(result);
}

void ActivityManager::UpdateActivity(Activity const& activity, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->update_activity(internal_,
reinterpret_cast<DiscordActivity*>(const_cast<Activity*>(&activity)),
cb.release(),
wrapper);
}

void ActivityManager::ClearActivity(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->clear_activity(internal_, cb.release(), wrapper);
}

void ActivityManager::SendRequestReply(UserId userId,
ActivityJoinRequestReply reply,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->send_request_reply(internal_,
userId,
static_cast<EDiscordActivityJoinRequestReply>(reply),
cb.release(),
wrapper);
}

void ActivityManager::SendInvite(UserId userId,
ActivityActionType type,
char const* content,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->send_invite(internal_,
userId,
static_cast<EDiscordActivityActionType>(type),
const_cast<char*>(content),
cb.release(),
wrapper);
}

void ActivityManager::AcceptInvite(UserId userId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->accept_invite(internal_, userId, cb.release(), wrapper);
}

} // namespace discord
Loading