Browse Source

Added discord RPC

tags/8.1
Madiwka3 3 years ago
parent
commit
59a496a4ee
11 changed files with 305 additions and 6 deletions
  1. +1
    -0
      debuggame.sh
  2. +1
    -0
      levels/levelgeneral.lua
  3. +1
    -1
      levels/menu.lua
  4. +1
    -0
      levels/practice.lua
  5. +1
    -0
      levels/selectlv.lua
  6. BIN
      libdiscord-rpc.so
  7. +18
    -5
      main.lua
  8. +1
    -0
      src/dependencies.lua
  9. +252
    -0
      src/discordRPC.lua
  10. +28
    -0
      src/rpcManager.lua
  11. +1
    -0
      src/stateMachine.lua

+ 1
- 0
debuggame.sh View File

@@ -1,4 +1,5 @@
rm game.love rm game.love
cp libdiscord-rpc.so /usr/lib32/
rm game.zip rm game.zip
zip -r game * zip -r game *
mv game.zip game.love mv game.zip game.love


+ 1
- 0
levels/levelgeneral.lua View File

@@ -10,6 +10,7 @@ function levelgeneral.update(dt)
if not pauseStatus then if not pauseStatus then
if not levelLoaded then if not levelLoaded then
level = require("levels/level" .. currentLevel) level = require("levels/level" .. currentLevel)
startTime = os.time(os.date("*t"))
level.load() level.load()
frame = 0 frame = 0
animationComplete = false animationComplete = false


+ 1
- 1
levels/menu.lua View File

@@ -4,7 +4,7 @@ local M = {}
menuLoaded = false menuLoaded = false
function menu.update(dt) function menu.update(dt)
if not menuLoaded then if not menuLoaded then
startTime = os.time(os.date("*t"))
firstShip.x = -100 firstShip.x = -100
menuLoaded = true menuLoaded = true
planets = {} planets = {}


+ 1
- 0
levels/practice.lua View File

@@ -6,6 +6,7 @@ local currenctScore = 0
function practice.update(dt) function practice.update(dt)
if not pauseStatus then if not pauseStatus then
if not levelLoaded then if not levelLoaded then
startTime = os.time(os.date("*t"))
shipsleft = 1 shipsleft = 1
planetsleft = 10 planetsleft = 10
cannonsleft = 10 cannonsleft = 10


+ 1
- 0
levels/selectlv.lua View File

@@ -70,6 +70,7 @@ table.insert(levels, menu:addButton("Go Back", function ()
local M = {} local M = {}
function selectlv.update(dt) function selectlv.update(dt)
if not menuLoaded then if not menuLoaded then
startTime = os.time(os.date("*t"))
firstShip.x = -100 firstShip.x = -100
menuLoaded = true menuLoaded = true
table.insert(planets, planet(love.math.random(100, WINDOW_WIDTH-100), love.math.random(100, WINDOW_HEIGHT-100), 90000000, 0.3, love.graphics.newImage("entities/planet/planet.png"))) table.insert(planets, planet(love.math.random(100, WINDOW_WIDTH-100), love.math.random(100, WINDOW_HEIGHT-100), 90000000, 0.3, love.graphics.newImage("entities/planet/planet.png")))


BIN
libdiscord-rpc.so View File


+ 18
- 5
main.lua View File

@@ -2,6 +2,8 @@ gameState = "menu"
animationSecsLeft = 3 animationSecsLeft = 3
require 'src/dependencies' require 'src/dependencies'
math.randomseed(os.time()) math.randomseed(os.time())
local discordRPC = require("src/discordRPC")
local appId = "889428447972175933"
--VARIABLES --VARIABLES
RESOLUTION_SET = 0 RESOLUTION_SET = 0
isFullscreen = 0 isFullscreen = 0
@@ -44,11 +46,6 @@ function love.keyreleased(key)
end end
function love.load() function love.load()
love.graphics.setLineWidth(4) love.graphics.setLineWidth(4)
print(love.filesystem.getAppdataDirectory())
print(love.filesystem.getSaveDirectory())
print(love.filesystem.areSymlinksEnabled())
print(love.filesystem.createDirectory('.'))
love.filesystem.newFile("File")
pauseMake() pauseMake()
testwalls = love.filesystem.load("save") testwalls = love.filesystem.load("save")
if testwalls ~= nil then if testwalls ~= nil then
@@ -60,6 +57,16 @@ function love.load()
if saveData.score == nil then if saveData.score == nil then
saveData.score = 0 saveData.score = 0
end end
discordRPC.initialize(appId, true)
local now = os.time(os.date("*t"))
presence = {
state = "Having a good time",
details = "Main Menu",
largeImageKey = "gravitynew",
largeImageText = "Gravity",
}

nextPresenceUpdate = 0
tick.framerate = 60 tick.framerate = 60
camera = Camera() camera = Camera()
BG = love.graphics.newImage("entities/background.jpg") BG = love.graphics.newImage("entities/background.jpg")
@@ -78,6 +85,12 @@ end


function love.update(dt) function love.update(dt)
stateUpdate(dt) stateUpdate(dt)
if nextPresenceUpdate < love.timer.getTime() then
discordRPC.updatePresence(presence)
nextPresenceUpdate = love.timer.getTime() + 2.0
end
discordRPC.runCallbacks()
love.window.setTitle("Nuclear Gravity") love.window.setTitle("Nuclear Gravity")
end end




+ 1
- 0
src/dependencies.lua View File

@@ -16,6 +16,7 @@ require 'entities/camera/VCAM'
require 'src/musicController' require 'src/musicController'
require 'entities/enemy/enemy' require 'entities/enemy/enemy'
require 'entities/enemy/projectile' require 'entities/enemy/projectile'
require 'src/rpcManager'
tick = require 'src/tick' tick = require 'src/tick'
utf8 = require("utf8") utf8 = require("utf8")
serialize = require 'src/ser' serialize = require 'src/ser'

+ 252
- 0
src/discordRPC.lua View File

@@ -0,0 +1,252 @@
local ffi = require "ffi"
local discordRPClib = ffi.load("discord-rpc")

ffi.cdef[[
typedef struct DiscordRichPresence {
const char* state; /* max 128 bytes */
const char* details; /* max 128 bytes */
int64_t startTimestamp;
int64_t endTimestamp;
const char* largeImageKey; /* max 32 bytes */
const char* largeImageText; /* max 128 bytes */
const char* smallImageKey; /* max 32 bytes */
const char* smallImageText; /* max 128 bytes */
const char* partyId; /* max 128 bytes */
int partySize;
int partyMax;
const char* matchSecret; /* max 128 bytes */
const char* joinSecret; /* max 128 bytes */
const char* spectateSecret; /* max 128 bytes */
int8_t instance;
} DiscordRichPresence;

typedef struct DiscordUser {
const char* userId;
const char* username;
const char* discriminator;
const char* avatar;
} DiscordUser;

typedef void (*readyPtr)(const DiscordUser* request);
typedef void (*disconnectedPtr)(int errorCode, const char* message);
typedef void (*erroredPtr)(int errorCode, const char* message);
typedef void (*joinGamePtr)(const char* joinSecret);
typedef void (*spectateGamePtr)(const char* spectateSecret);
typedef void (*joinRequestPtr)(const DiscordUser* request);

typedef struct DiscordEventHandlers {
readyPtr ready;
disconnectedPtr disconnected;
erroredPtr errored;
joinGamePtr joinGame;
spectateGamePtr spectateGame;
joinRequestPtr joinRequest;
} DiscordEventHandlers;

void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers,
int autoRegister,
const char* optionalSteamId);

void Discord_Shutdown(void);

void Discord_RunCallbacks(void);

void Discord_UpdatePresence(const DiscordRichPresence* presence);

void Discord_ClearPresence(void);

void Discord_Respond(const char* userid, int reply);

void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
]]

local discordRPC = {} -- module table

-- proxy to detect garbage collection of the module
discordRPC.gcDummy = newproxy(true)

local function unpackDiscordUser(request)
return ffi.string(request.userId), ffi.string(request.username),
ffi.string(request.discriminator), ffi.string(request.avatar)
end

-- callback proxies
-- note: callbacks are not JIT compiled (= SLOW), try to avoid doing performance critical tasks in them
-- luajit.org/ext_ffi_semantics.html
local ready_proxy = ffi.cast("readyPtr", function(request)
if discordRPC.ready then
discordRPC.ready(unpackDiscordUser(request))
end
end)

local disconnected_proxy = ffi.cast("disconnectedPtr", function(errorCode, message)
if discordRPC.disconnected then
discordRPC.disconnected(errorCode, ffi.string(message))
end
end)

local errored_proxy = ffi.cast("erroredPtr", function(errorCode, message)
if discordRPC.errored then
discordRPC.errored(errorCode, ffi.string(message))
end
end)

local joinGame_proxy = ffi.cast("joinGamePtr", function(joinSecret)
if discordRPC.joinGame then
discordRPC.joinGame(ffi.string(joinSecret))
end
end)

local spectateGame_proxy = ffi.cast("spectateGamePtr", function(spectateSecret)
if discordRPC.spectateGame then
discordRPC.spectateGame(ffi.string(spectateSecret))
end
end)

local joinRequest_proxy = ffi.cast("joinRequestPtr", function(request)
if discordRPC.joinRequest then
discordRPC.joinRequest(unpackDiscordUser(request))
end
end)

-- helpers
local function checkArg(arg, argType, argName, func, maybeNil)
assert(type(arg) == argType or (maybeNil and arg == nil),
string.format("Argument \"%s\" to function \"%s\" has to be of type \"%s\"",
argName, func, argType))
end

local function checkStrArg(arg, maxLen, argName, func, maybeNil)
if maxLen then
assert(type(arg) == "string" and arg:len() <= maxLen or (maybeNil and arg == nil),
string.format("Argument \"%s\" of function \"%s\" has to be of type string with maximum length %d",
argName, func, maxLen))
else
checkArg(arg, "string", argName, func, true)
end
end

local function checkIntArg(arg, maxBits, argName, func, maybeNil)
maxBits = math.min(maxBits or 32, 52) -- lua number (double) can only store integers < 2^53
local maxVal = 2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
assert(type(arg) == "number" and math.floor(arg) == arg
and arg < maxVal and arg >= -maxVal
or (maybeNil and arg == nil),
string.format("Argument \"%s\" of function \"%s\" has to be a whole number <= %d",
argName, func, maxVal))
end

-- function wrappers
function discordRPC.initialize(applicationId, autoRegister, optionalSteamId)
local func = "discordRPC.Initialize"
checkStrArg(applicationId, nil, "applicationId", func)
checkArg(autoRegister, "boolean", "autoRegister", func)
if optionalSteamId ~= nil then
checkStrArg(optionalSteamId, nil, "optionalSteamId", func)
end

local eventHandlers = ffi.new("struct DiscordEventHandlers")
eventHandlers.ready = ready_proxy
eventHandlers.disconnected = disconnected_proxy
eventHandlers.errored = errored_proxy
eventHandlers.joinGame = joinGame_proxy
eventHandlers.spectateGame = spectateGame_proxy
eventHandlers.joinRequest = joinRequest_proxy

discordRPClib.Discord_Initialize(applicationId, eventHandlers,
autoRegister and 1 or 0, optionalSteamId)
end

function discordRPC.shutdown()
discordRPClib.Discord_Shutdown()
end

function discordRPC.runCallbacks()
discordRPClib.Discord_RunCallbacks()
end
-- http://luajit.org/ext_ffi_semantics.html#callback :
-- It is not allowed, to let an FFI call into a C function (runCallbacks)
-- get JIT-compiled, which in turn calls a callback, calling into Lua again (e.g. discordRPC.ready).
-- Usually this attempt is caught by the interpreter first and the C function
-- is blacklisted for compilation.
-- solution:
-- "Then you'll need to manually turn off JIT-compilation with jit.off() for
-- the surrounding Lua function that invokes such a message polling function."
jit.off(discordRPC.runCallbacks)

function discordRPC.updatePresence(presence)
local func = "discordRPC.updatePresence"
checkArg(presence, "table", "presence", func)

-- -1 for string length because of 0-termination
checkStrArg(presence.state, 127, "presence.state", func, true)
checkStrArg(presence.details, 127, "presence.details", func, true)

checkIntArg(presence.startTimestamp, 64, "presence.startTimestamp", func, true)
checkIntArg(presence.endTimestamp, 64, "presence.endTimestamp", func, true)

checkStrArg(presence.largeImageKey, 31, "presence.largeImageKey", func, true)
checkStrArg(presence.largeImageText, 127, "presence.largeImageText", func, true)
checkStrArg(presence.smallImageKey, 31, "presence.smallImageKey", func, true)
checkStrArg(presence.smallImageText, 127, "presence.smallImageText", func, true)
checkStrArg(presence.partyId, 127, "presence.partyId", func, true)

checkIntArg(presence.partySize, 32, "presence.partySize", func, true)
checkIntArg(presence.partyMax, 32, "presence.partyMax", func, true)

checkStrArg(presence.matchSecret, 127, "presence.matchSecret", func, true)
checkStrArg(presence.joinSecret, 127, "presence.joinSecret", func, true)
checkStrArg(presence.spectateSecret, 127, "presence.spectateSecret", func, true)

checkIntArg(presence.instance, 8, "presence.instance", func, true)

local cpresence = ffi.new("struct DiscordRichPresence")
cpresence.state = presence.state
cpresence.details = presence.details
cpresence.startTimestamp = presence.startTimestamp or 0
cpresence.endTimestamp = presence.endTimestamp or 0
cpresence.largeImageKey = presence.largeImageKey
cpresence.largeImageText = presence.largeImageText
cpresence.smallImageKey = presence.smallImageKey
cpresence.smallImageText = presence.smallImageText
cpresence.partyId = presence.partyId
cpresence.partySize = presence.partySize or 0
cpresence.partyMax = presence.partyMax or 0
cpresence.matchSecret = presence.matchSecret
cpresence.joinSecret = presence.joinSecret
cpresence.spectateSecret = presence.spectateSecret
cpresence.instance = presence.instance or 0

discordRPClib.Discord_UpdatePresence(cpresence)
end

function discordRPC.clearPresence()
discordRPClib.Discord_ClearPresence()
end

local replyMap = {
no = 0,
yes = 1,
ignore = 2
}

-- maybe let reply take ints too (0, 1, 2) and add constants to the module
function discordRPC.respond(userId, reply)
checkStrArg(userId, nil, "userId", "discordRPC.respond")
assert(replyMap[reply], "Argument 'reply' to discordRPC.respond has to be one of \"yes\", \"no\" or \"ignore\"")
discordRPClib.Discord_Respond(userId, replyMap[reply])
end

-- garbage collection callback
getmetatable(discordRPC.gcDummy).__gc = function()
discordRPC.shutdown()
ready_proxy:free()
disconnected_proxy:free()
errored_proxy:free()
joinGame_proxy:free()
spectateGame_proxy:free()
joinRequest_proxy:free()
end

return discordRPC

+ 28
- 0
src/rpcManager.lua View File

@@ -0,0 +1,28 @@
function rpcManager()
if gameState == "levelgeneral" then
presence = {
state = "Thinking...",
details = "Level: " .. currentLevel,
startTimestamp = startTime,
largeImageKey = "gravitynew",
largeImageText = "Gravity",
}
end
if gameState == "menu" or gameState == "selectlv" then
presence = {
state = "Choosing the best level",
startTimestamp = startTime,
largeImageKey = "gravitynew",
largeImageText = "Gravity",
}
end
if gameState == "practice" then
presence = {
state = "Practicing",
details = "Current best score: " .. math.floor(saveData.score/100),
startTimestamp = startTime,
largeImageKey = "gravitynew",
largeImageText = "Gravity",
}
end
end

+ 1
- 0
src/stateMachine.lua View File

@@ -4,6 +4,7 @@ function stateUpdate(dt)
state = require("levels/"..gameState) state = require("levels/"..gameState)
state.update(dt) state.update(dt)
musicController("norm") musicController("norm")
rpcManager()
end end


function goBack() function goBack()


Loading…
Cancel
Save