Skip to content

Commit

Permalink
Using Discord Game SDK with a custom python wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
SayakMukhopadhyay committed Apr 25, 2021
1 parent d3891f0 commit 37c1ea8
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 169 deletions.
1 change: 1 addition & 0 deletions .idea/EDMC-Discord-Presence.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

250 changes: 83 additions & 167 deletions load.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,151 +14,48 @@
# limitations under the License.
#

import functools
import logging
import threading
import tkinter as tk
from os.path import dirname, join
from sys import platform

import semantic_version
import sys
import time
import ctypes

import l10n
import myNotebook as nb
from config import config, appname, appversion
import l10n
import functools
import tkinter as tk
import semantic_version
import logging
from py_discord_sdk import discordsdk as dsdk

plugin_name = "DiscordPresence"

logger = logging.getLogger(f'{appname}.{plugin_name}')

_ = functools.partial(l10n.Translations.translate, context=__file__)

CLIENT_ID = b'386149818227097610'
CLIENT_ID = 386149818227097610

VERSION = '3.0.0'

# Add global var for Planet name (landing + around)
planet = '<Hidden>'
landingPad = '2'
#
# From discrod-rpc.h
#
discord_rpc_lib = 'discord-rpc.dll'
if platform == 'darwin':
discord_rpc_lib = 'libdiscord-rpc.dylib'
elif platform == 'linux' or platform == 'linux2':
discord_rpc_lib = 'libdiscord-rpc.so'
discord_rpc = ctypes.cdll.LoadLibrary(join(dirname(__file__), discord_rpc_lib))


class DiscordRichPresence(ctypes.Structure):
_fields_ = [
('state', ctypes.c_char_p), # max 128 bytes
('details', ctypes.c_char_p), # max 128 bytes
('startTimestamp', ctypes.c_int64),
('endTimestamp', ctypes.c_int64),
('largeImageKey', ctypes.c_char_p), # max 32 bytes
('largeImageText', ctypes.c_char_p), # max 128 bytes
('smallImageKey', ctypes.c_char_p), # max 32 bytes
('smallImageText', ctypes.c_char_p), # max 128 bytes
('partyId', ctypes.c_char_p), # max 128 bytes
('partySize', ctypes.c_int),
('partyMax', ctypes.c_int),
('matchSecret', ctypes.c_char_p), # max 128 bytes
('joinSecret', ctypes.c_char_p), # max 128 bytes
('spectateSecret', ctypes.c_char_p), # max 128 bytes
('instance', ctypes.c_int8)
]


class DiscordJoinRequest(ctypes.Structure):
_fields_ = [
('userId', ctypes.c_char_p),
('username', ctypes.c_char_p),
('avatar', ctypes.c_char_p)
]


ReadyProc = ctypes.CFUNCTYPE(None)
DisconnectedProc = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) # errorCode, message
ErroredProc = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) # errorCode, message
JoinGameProc = ctypes.CFUNCTYPE(None, ctypes.c_char_p) # joinSecret
SpectateGameProc = ctypes.CFUNCTYPE(None, ctypes.c_char_p) # spectateSecret
JoinRequestProc = ctypes.CFUNCTYPE(None, ctypes.POINTER(DiscordJoinRequest))


class DiscordEventHandlers(ctypes.Structure):
_fields_ = [
('ready', ReadyProc),
('disconnected', DisconnectedProc),
('errored', ErroredProc),
('joinGame', JoinGameProc),
('spectateGame', SpectateGameProc),
('joinRequest', JoinRequestProc)
]


DISCORD_REPLY_NO, DISCORD_REPLY_YES, DISCORD_REPLY_IGNORE = list(range(3))

Discord_Initialize = discord_rpc.Discord_Initialize
Discord_Initialize.argtypes = [ctypes.c_char_p, ctypes.POINTER(DiscordEventHandlers), ctypes.c_int,
ctypes.c_char_p] # applicationId, handlers, autoRegister, optionalSteamId
Discord_Shutdown = discord_rpc.Discord_Shutdown
Discord_Shutdown.argtypes = None
Discord_UpdatePresence = discord_rpc.Discord_UpdatePresence
Discord_UpdatePresence.argtypes = [ctypes.POINTER(DiscordRichPresence)]
Discord_Respond = discord_rpc.Discord_Respond
Discord_Respond.argtypes = [ctypes.c_char_p, ctypes.c_int] # userid, reply


#
# Callback handlers
#


def ready():
print('ready')


def disconnected(errorCode, message):
print('disconnected', errorCode, message)


def errored(errorCode, message):
print('errored', errorCode, message)


def joinGame(joinSecret):
print('joinGame', joinSecret)


def spectateGame(spectateSecret):
print('spectateGame', spectateSecret)


def joinRequest(request):
print('joinRequest', request.userId, request.username, request.avatar)


event_handlers = DiscordEventHandlers(ReadyProc(ready),
DisconnectedProc(disconnected),
ErroredProc(errored),
JoinGameProc(joinGame),
SpectateGameProc(spectateGame),
JoinRequestProc(joinRequest))

Discord_Initialize(CLIENT_ID, event_handlers, True, None)

this = sys.modules[__name__] # For holding module globals

this.presence_state = _('Connecting CMDR Interface').encode('utf-8')
this.presence_details = b''
this.time_start = time.time()

def callback(result):
logger.info(f'Callback: {result}')
if result == dsdk.Result.ok:
logger.info("Successfully set the activity!")
else:
logger.error(f'Error in callback: {result}')
raise Exception(result)

def update_presence():
presence = DiscordRichPresence()

def update_presence():
if isinstance(appversion, str):
core_version = semantic_version.Version(appversion)

Expand All @@ -169,20 +66,16 @@ def update_presence():
if core_version < semantic_version.Version('5.0.0-beta1'):
logger.info('EDMC core version is before 5.0.0-beta1')
if config.getint("disable_presence") == 0:
presence.state = this.presence_state
presence.details = this.presence_details
this.activity.state = this.presence_state
this.activity.details = this.presence_details
else:
logger.info('EDMC core version is at least 5.0.0-beta1')
if config.get_int("disable_presence") == 0:
presence.state = this.presence_state
presence.details = this.presence_details
this.activity.state = this.presence_state
this.activity.details = this.presence_details


presence.startTimestamp = int(this.time_start)
Discord_UpdatePresence(presence)


this.disablePresence = None
this.activity.timestamps.start = int(this.time_start)
this.activity_manager.update_activity(this.activity, callback)


def plugin_prefs(parent, cmdr, is_beta):
Expand Down Expand Up @@ -219,84 +112,107 @@ def prefs_changed(cmdr, is_beta):


def plugin_start3(plugin_dir):
update_presence()
return 'DiscordPresence'
plugin_path = join(dirname(plugin_dir), plugin_name)
this.app = dsdk.Discord(CLIENT_ID, dsdk.CreateFlags.default, plugin_path)
this.activity_manager = this.app.get_activity_manager()
this.activity = dsdk.Activity()

this.call_back_thread = threading.Thread(target=run_callbacks)
this.call_back_thread.setDaemon(True)
this.call_back_thread.start()

this.presence_state = _('Connecting CMDR Interface')
this.presence_details = ''
this.time_start = time.time()

this.disablePresence = None

def plugin_start():
update_presence()
return 'DiscordPresence'


def plugin_stop():
Discord_Shutdown()
this.activity_manager.clear_activity(callback)
this.call_back_thread = None


def journal_entry(cmdr, is_beta, system, station, entry, state):
global planet
global landingPad
presence_state = this.presence_state
presence_details = this.presence_details
if entry['event'] == 'StartUp':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
presence_state = _('In system {system}').format(system=system)
if station is None:
this.presence_details = _('Flying in normal space').encode('utf-8')
presence_details = _('Flying in normal space')
else:
this.presence_details = _('Docked at {station}').format(station=station).encode('utf-8')
presence_details = _('Docked at {station}').format(station=station)
elif entry['event'] == 'Location':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
presence_state = _('In system {system}').format(system=system)
if station is None:
this.presence_details = _('Flying in normal space').encode('utf-8')
presence_details = _('Flying in normal space')
else:
this.presence_details = _('Docked at {station}').format(station=station).encode('utf-8')
presence_details = _('Docked at {station}').format(station=station)
elif entry['event'] == 'StartJump':
this.presence_state = _('Jumping').encode('utf-8')
presence_state = _('Jumping')
if entry['JumpType'] == 'Hyperspace':
this.presence_details = _('Jumping to system {system}').format(system=entry['StarSystem']).encode('utf-8')
presence_details = _('Jumping to system {system}').format(system=entry['StarSystem'])
elif entry['JumpType'] == 'Supercruise':
this.presence_details = _('Preparing for supercruise').encode('utf-8')
presence_details = _('Preparing for supercruise')
elif entry['event'] == 'SupercruiseEntry':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
this.presence_details = _('Supercruising').encode('utf-8')
presence_state = _('In system {system}').format(system=system)
presence_details = _('Supercruising')
elif entry['event'] == 'SupercruiseExit':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
this.presence_details = _('Flying in normal space').encode('utf-8')
presence_state = _('In system {system}').format(system=system)
presence_details = _('Flying in normal space')
elif entry['event'] == 'FSDJump':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
this.presence_details = _('Supercruising').encode('utf-8')
presence_state = _('In system {system}').format(system=system)
presence_details = _('Supercruising')
elif entry['event'] == 'Docked':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
this.presence_details = _('Docked at {station}').format(station=station).encode('utf-8')
presence_state = _('In system {system}').format(system=system)
presence_details = _('Docked at {station}').format(station=station)
elif entry['event'] == 'Undocked':
this.presence_state = _('In system {system}').format(system=system).encode('utf-8')
this.presence_details = _('Flying in normal space').encode('utf-8')
presence_state = _('In system {system}').format(system=system)
presence_details = _('Flying in normal space')
elif entry['event'] == 'ShutDown':
this.presence_state = _('Connecting CMDR Interface').encode('utf-8')
this.presence_details = b''
presence_state = _('Connecting CMDR Interface')
presence_details = ''
elif entry['event'] == 'DockingGranted':
landingPad = entry['LandingPad']
elif entry['event'] == 'Music':
if entry['MusicTrack'] == 'MainMenu':
this.presence_state = _('Connecting CMDR Interface').encode('utf-8')
this.presence_details = b''
presence_state = _('Connecting CMDR Interface')
presence_details = ''
# Todo: This elif might not be executed on undocked. Functionality can be improved
elif entry['event'] == 'Undocked' or entry['event'] == 'DockingCancelled' or entry['event'] == 'DockingTimeout':
this.presence_details = _('Flying near {station}').format(station=entry['StationName']).encode('utf-8')
presence_details = _('Flying near {station}').format(station=entry['StationName'])
# Planetary events
elif entry['event'] == 'ApproachBody':
this.presence_details = _('Approaching {body}').format(body=entry['Body']).encode('utf-8')
presence_details = _('Approaching {body}').format(body=entry['Body'])
planet = entry['Body']
elif entry['event'] == 'Touchdown' and entry['PlayerControlled']:
this.presence_details = _('Landed on {body}').format(body=planet).encode('utf-8')
presence_details = _('Landed on {body}').format(body=planet)
elif entry['event'] == 'Liftoff' and entry['PlayerControlled']:
if entry['PlayerControlled']:
this.presence_details = _('Flying around {body}').format(body=planet).encode('utf-8')
presence_details = _('Flying around {body}').format(body=planet)
else:
this.presence_details = _('In SRV on {body}, ship in orbit').format(body=planet).encode('utf-8')
presence_details = _('In SRV on {body}, ship in orbit').format(body=planet)
elif entry['event'] == 'LeaveBody':
this.presence_details = _('Supercruising').encode('utf-8')
presence_details = _('Supercruising')

# EXTERNAL VEHICLE EVENTS
elif entry['event'] == 'LaunchSRV':
this.presence_details = _('In SRV on {body}').format(body=planet).encode('utf-8')
presence_details = _('In SRV on {body}').format(body=planet)
elif entry['event'] == 'DockSRV':
this.presence_details = _('Landed on {body}').format(body=planet).encode('utf-8')
update_presence()
presence_details = _('Landed on {body}').format(body=planet)

if presence_state != this.presence_state or presence_details != this.presence_details:
this.presence_state = presence_state
this.presence_details = presence_details
update_presence()


def run_callbacks():
while True:
time.sleep(1 / 10)
this.app.run_callbacks()
2 changes: 1 addition & 1 deletion py_discord_sdk

0 comments on commit 37c1ea8

Please sign in to comment.