diff --git a/voxygen/src/discord.rs b/voxygen/src/discord.rs
new file mode 100644
index 0000000000..ca4ef32a51
--- /dev/null
+++ b/voxygen/src/discord.rs
@@ -0,0 +1,104 @@
+use discord_game_sdk::{Activity, Discord};
+use std::ffi::CString;
+use std::sync::mpsc::Sender;
+use std::sync::{mpsc, Mutex, MutexGuard};
+use std::thread;
+use std::thread::JoinHandle;
+
+use crate::DEFAULT_PUBLIC_SERVER;
+use chrono::Utc;
+
+const DISCORD_APPLICATION_ID: i64 = 583662036194689035;
+
+/// Represents an update of the game which should be reflected in Discord
+pub enum DiscordUpdate {
+    Details(String),
+    State(String),
+    SmallImg(String),
+    SmallImgDesc(String),
+    LargeImg(String),
+    LargeImgDesc(String),
+    Shutdown,
+}
+
+pub struct DiscordState {
+    pub tx: Sender<DiscordUpdate>,
+    pub thread: Option<JoinHandle<()>>,
+}
+
+pub fn run() -> Mutex<DiscordState> {
+    let (tx, rx) = mpsc::channel();
+
+    Mutex::new(DiscordState {
+        tx,
+        thread: Some(thread::spawn(move || {
+            let mut discord =
+                Discord::new(DISCORD_APPLICATION_ID).expect("failed to initiate discord_game_sdk");
+
+            //Set initial Status
+            let mut current_activity = Activity::empty();
+            current_activity.with_details(CString::new("Menu").expect("failed to create CString"));
+            current_activity.with_state(CString::new("Idling").expect("failed to create CString"));
+            current_activity.with_small_image_key(
+                CString::new("veloren_logo_squareicon_2000").expect("failed to create CString"),
+            );
+            current_activity.with_small_image_tooltip(
+                CString::new("Veloren").expect("failed to create CString"),
+            );
+            current_activity
+                .with_large_image_key(CString::new("bg_main").expect("failed to create CString"));
+            current_activity.with_large_image_tooltip(
+                CString::new("veloren.net").expect("failed to create CString"),
+            );
+
+            current_activity.with_start_time(Utc::now());
+
+            discord.update_activity(&current_activity, |_, _| {});
+
+            'outer: loop {
+                discord.empty_event_receivers();
+                discord.run_callbacks();
+
+                let msg = rx.try_recv();
+                match msg {
+                    Ok(update) => {
+                        match update {
+                            DiscordUpdate::Details(x) => current_activity
+                                .with_details(CString::new(x).expect("failed to create CString")),
+                            DiscordUpdate::State(x) => current_activity
+                                .with_state(CString::new(x).expect("failed to create CString")),
+                            DiscordUpdate::SmallImg(x) => current_activity.with_small_image_key(
+                                CString::new(x).expect("failed to create CString"),
+                            ),
+                            DiscordUpdate::SmallImgDesc(x) => current_activity
+                                .with_small_image_tooltip(
+                                    CString::new(x).expect("failed to create CString"),
+                                ),
+                            DiscordUpdate::LargeImg(x) => current_activity.with_large_image_key(
+                                CString::new(x).expect("failed to create CString"),
+                            ),
+                            DiscordUpdate::LargeImgDesc(x) => current_activity
+                                .with_large_image_tooltip(
+                                    CString::new(x).expect("failed to create CString"),
+                                ),
+                            DiscordUpdate::Shutdown => break 'outer,
+                        };
+                        discord.update_activity(&current_activity, |_, _| {});
+                    }
+                    Err(_) => {}
+                }
+            }
+        })),
+    })
+}
+
+/* Some helpers */
+pub fn send_menu(disc: &mut MutexGuard<DiscordState>) {
+    disc.tx.send(DiscordUpdate::Details("Menu".into()));
+    disc.tx.send(DiscordUpdate::State("Idling".into()));
+    disc.tx.send(DiscordUpdate::LargeImg("bg_main".into()));
+}
+pub fn send_singleplayer(disc: &mut MutexGuard<DiscordState>) {
+    disc.tx.send(DiscordUpdate::Details("Singleplayer".into()));
+    disc.tx.send(DiscordUpdate::State("Playing...".into()));
+}
\ No newline at end of file
diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs
index 185dc7d2cd..8bde637e8c 100644
--- a/voxygen/src/main.rs
+++ b/voxygen/src/main.rs
@@ -1,6 +1,10 @@
 #![feature(drain_filter)]
 #![recursion_limit = "2048"]
 
+#[cfg(feature = "discord")]
+#[macro_use]
+extern crate lazy_static;
+
 #[macro_use]
 pub mod ui;
 pub mod anim;
@@ -17,16 +21,21 @@ pub mod settings;
 pub mod singleplayer;
 pub mod window;
 
+#[cfg(feature = "discord")]
+pub mod discord;
+
 // Reexports
 pub use crate::error::Error;
 
-use crate::{
-    audio::{base::Genre, AudioFrontend},
-    menu::main::MainMenuState,
-    settings::Settings,
-    window::Window,
+use crate::{audio::AudioFrontend, menu::main::MainMenuState, settings::Settings, window::Window};
+use log::{self, debug, error, info, warn};
+
+#[cfg(feature = "discord")]
+use std::sync::{
+    mpsc::Sender,
+    Mutex,
 };
-use log::{debug, error, info, warn};
+
 use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
 use std::{fs::File, mem, panic, str::FromStr};
 
@@ -80,6 +89,14 @@ pub trait PlayState {
     fn name(&self) -> &'static str;
 }
 
+#[cfg(feature = "discord")]
+lazy_static! {
+    //Set up discord rich presence
+    static ref discord_instance: Mutex<discord::DiscordState> = {
+        discord::run()
+    };
+}
+
 fn main() {
     // Set up the global state.
     let settings = Settings::load();
@@ -109,6 +126,17 @@ fn main() {
         ),
     ])
     .unwrap();
+    
+    // Initialize discord. (lazy_static intialise lazily...)
+    #[cfg(feature = "discord")]
+    {
+        match discord_instance.lock() {
+            Ok(disc) => {
+                //great
+            }
+            Err(e) => {}
+        }
+    }
 
     // Set up panic handler to relay swish panic messages to the user
     let settings_clone = global_state.settings.clone();
@@ -238,6 +266,26 @@ fn main() {
             }
         }
     }
+    
+    //Properly shutdown discord thread
+    #[cfg(feature = "discord")]
+    {
+        match discord_instance.lock() {
+            Ok(mut disc) => {
+                disc.tx.send(discord::DiscordUpdate::Shutdown);
+                match disc.thread.take() {
+                    Some(th) => {
+                        th.join();
+                    }
+                    None => {
+                        error!("couldn't gracefully shutdown discord thread");
+                    }
+                }
+            }
+            Err(e) => error!("couldn't gracefully shutdown discord thread: {}", e),
+        }
+    }
+    
     // Save settings to add new fields or create the file if it is not already there
     if let Err(err) = global_state.settings.save_to_file() {
         warn!("Failed to save settings: {:?}", err);