Add steamshim integration
This commit is contained in:
		
							parent
							
								
									213ee81f1c
								
							
						
					
					
						commit
						4382bc57e7
					
				
					 4 changed files with 529 additions and 0 deletions
				
			
		
							
								
								
									
										444
									
								
								steamshim/steamshim_child.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								steamshim/steamshim_child.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,444 @@
 | 
			
		|||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN 1
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
typedef HANDLE PipeType;
 | 
			
		||||
#define NULLPIPE NULL
 | 
			
		||||
typedef unsigned __int8 uint8;
 | 
			
		||||
typedef __int32 int32;
 | 
			
		||||
typedef unsigned __int64 uint64;
 | 
			
		||||
#else
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
typedef uint8_t uint8;
 | 
			
		||||
typedef int32_t int32;
 | 
			
		||||
typedef uint64_t uint64;
 | 
			
		||||
typedef int PipeType;
 | 
			
		||||
#define NULLPIPE -1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "steamshim_child.h"
 | 
			
		||||
 | 
			
		||||
#define DEBUGPIPE 1
 | 
			
		||||
#if DEBUGPIPE
 | 
			
		||||
#define dbgpipe printf
 | 
			
		||||
#else
 | 
			
		||||
static inline void dbgpipe(const char *fmt, ...) {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int writePipe(PipeType fd, const void *buf, const unsigned int _len);
 | 
			
		||||
static int readPipe(PipeType fd, void *buf, const unsigned int _len);
 | 
			
		||||
static void closePipe(PipeType fd);
 | 
			
		||||
static char *getEnvVar(const char *key, char *buf, const size_t buflen);
 | 
			
		||||
static int pipeReady(PipeType fd);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
static int pipeReady(PipeType fd)
 | 
			
		||||
{
 | 
			
		||||
    DWORD avail = 0;
 | 
			
		||||
    return (PeekNamedPipe(fd, NULL, 0, NULL, &avail, NULL) && (avail > 0));
 | 
			
		||||
} /* pipeReady */
 | 
			
		||||
 | 
			
		||||
static int writePipe(PipeType fd, const void *buf, const unsigned int _len)
 | 
			
		||||
{
 | 
			
		||||
    const DWORD len = (DWORD) _len;
 | 
			
		||||
    DWORD bw = 0;
 | 
			
		||||
    return ((WriteFile(fd, buf, len, &bw, NULL) != 0) && (bw == len));
 | 
			
		||||
} /* writePipe */
 | 
			
		||||
 | 
			
		||||
static int readPipe(PipeType fd, void *buf, const unsigned int _len)
 | 
			
		||||
{
 | 
			
		||||
    const DWORD len = (DWORD) _len;
 | 
			
		||||
    DWORD br = 0;
 | 
			
		||||
    return ReadFile(fd, buf, len, &br, NULL) ? (int) br : -1;
 | 
			
		||||
} /* readPipe */
 | 
			
		||||
 | 
			
		||||
static void closePipe(PipeType fd)
 | 
			
		||||
{
 | 
			
		||||
    CloseHandle(fd);
 | 
			
		||||
} /* closePipe */
 | 
			
		||||
 | 
			
		||||
static char *getEnvVar(const char *key, char *buf, const size_t _buflen)
 | 
			
		||||
{
 | 
			
		||||
    const DWORD buflen = (DWORD) _buflen;
 | 
			
		||||
    const DWORD rc = GetEnvironmentVariableA(key, val, buflen);
 | 
			
		||||
    /* rc doesn't count null char, hence "<". */
 | 
			
		||||
    return ((rc > 0) && (rc < buflen)) ? NULL : buf;
 | 
			
		||||
} /* getEnvVar */
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static int pipeReady(PipeType fd)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
    struct pollfd pfd = { fd, POLLIN | POLLERR | POLLHUP, 0 };
 | 
			
		||||
    while (((rc = poll(&pfd, 1, 0)) == -1) && (errno == EINTR)) { /*spin*/ }
 | 
			
		||||
    return (rc == 1);
 | 
			
		||||
} /* pipeReady */
 | 
			
		||||
 | 
			
		||||
static int writePipe(PipeType fd, const void *buf, const unsigned int _len)
 | 
			
		||||
{
 | 
			
		||||
    const ssize_t len = (ssize_t) _len;
 | 
			
		||||
    ssize_t bw;
 | 
			
		||||
    while (((bw = write(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ }
 | 
			
		||||
    return (bw == len);
 | 
			
		||||
} /* writePipe */
 | 
			
		||||
 | 
			
		||||
static int readPipe(PipeType fd, void *buf, const unsigned int _len)
 | 
			
		||||
{
 | 
			
		||||
    const ssize_t len = (ssize_t) _len;
 | 
			
		||||
    ssize_t br;
 | 
			
		||||
    while (((br = read(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ }
 | 
			
		||||
    return (int) br;
 | 
			
		||||
} /* readPipe */
 | 
			
		||||
 | 
			
		||||
static void closePipe(PipeType fd)
 | 
			
		||||
{
 | 
			
		||||
    close(fd);
 | 
			
		||||
} /* closePipe */
 | 
			
		||||
 | 
			
		||||
static char *getEnvVar(const char *key, char *buf, const size_t buflen)
 | 
			
		||||
{
 | 
			
		||||
    const char *envr = getenv(key);
 | 
			
		||||
    if (!envr || (strlen(envr) >= buflen))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    strcpy(buf, envr);
 | 
			
		||||
    return buf;
 | 
			
		||||
} /* getEnvVar */
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static PipeType GPipeRead = NULLPIPE;
 | 
			
		||||
static PipeType GPipeWrite = NULLPIPE;
 | 
			
		||||
 | 
			
		||||
typedef enum ShimCmd
 | 
			
		||||
{
 | 
			
		||||
    SHIMCMD_BYE,
 | 
			
		||||
    SHIMCMD_PUMP,
 | 
			
		||||
    SHIMCMD_REQUESTSTATS,
 | 
			
		||||
    SHIMCMD_STORESTATS,
 | 
			
		||||
    SHIMCMD_SETACHIEVEMENT,
 | 
			
		||||
    SHIMCMD_GETACHIEVEMENT,
 | 
			
		||||
    SHIMCMD_RESETSTATS,
 | 
			
		||||
    SHIMCMD_SETSTATI,
 | 
			
		||||
    SHIMCMD_GETSTATI,
 | 
			
		||||
    SHIMCMD_SETSTATF,
 | 
			
		||||
    SHIMCMD_GETSTATF,
 | 
			
		||||
} ShimCmd;
 | 
			
		||||
 | 
			
		||||
static int write1ByteCmd(const uint8 b1)
 | 
			
		||||
{
 | 
			
		||||
    const uint8 buf[] = { 1, b1 };
 | 
			
		||||
    return writePipe(GPipeWrite, buf, sizeof (buf));
 | 
			
		||||
} /* write1ByteCmd */
 | 
			
		||||
 | 
			
		||||
static int write2ByteCmd(const uint8 b1, const uint8 b2)
 | 
			
		||||
{
 | 
			
		||||
    const uint8 buf[] = { 2, b1, b2 };
 | 
			
		||||
    return writePipe(GPipeWrite, buf, sizeof (buf));
 | 
			
		||||
} /* write2ByteCmd */
 | 
			
		||||
 | 
			
		||||
static inline int writeBye(void)
 | 
			
		||||
{
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_BYE().\n");
 | 
			
		||||
    return write1ByteCmd(SHIMCMD_BYE);
 | 
			
		||||
} // writeBye
 | 
			
		||||
 | 
			
		||||
static int initPipes(void)
 | 
			
		||||
{
 | 
			
		||||
    char buf[64];
 | 
			
		||||
    unsigned long long val;
 | 
			
		||||
 | 
			
		||||
    if (!getEnvVar("STEAMSHIM_READHANDLE", buf, sizeof (buf)))
 | 
			
		||||
        return 0;
 | 
			
		||||
    else if (sscanf(buf, "%llu", &val) != 1)
 | 
			
		||||
        return 0;
 | 
			
		||||
    else
 | 
			
		||||
        GPipeRead = (PipeType) val;
 | 
			
		||||
 | 
			
		||||
    if (!getEnvVar("STEAMSHIM_WRITEHANDLE", buf, sizeof (buf)))
 | 
			
		||||
        return 0;
 | 
			
		||||
    else if (sscanf(buf, "%llu", &val) != 1)
 | 
			
		||||
        return 0;
 | 
			
		||||
    else
 | 
			
		||||
        GPipeWrite = (PipeType) val;
 | 
			
		||||
    
 | 
			
		||||
    return ((GPipeRead != NULLPIPE) && (GPipeWrite != NULLPIPE));
 | 
			
		||||
} /* initPipes */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int STEAMSHIM_init(void)
 | 
			
		||||
{
 | 
			
		||||
    dbgpipe("Child init start.\n");
 | 
			
		||||
    if (!initPipes())
 | 
			
		||||
    {
 | 
			
		||||
        dbgpipe("Child init failed.\n");
 | 
			
		||||
        return 0;
 | 
			
		||||
    } /* if */
 | 
			
		||||
 | 
			
		||||
    signal(SIGPIPE, SIG_IGN);
 | 
			
		||||
 | 
			
		||||
    dbgpipe("Child init success!\n");
 | 
			
		||||
    return 1;
 | 
			
		||||
} /* STEAMSHIM_init */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_deinit(void)
 | 
			
		||||
{
 | 
			
		||||
    dbgpipe("Child deinit.\n");
 | 
			
		||||
    if (GPipeWrite != NULLPIPE)
 | 
			
		||||
    {
 | 
			
		||||
        writeBye();
 | 
			
		||||
        closePipe(GPipeWrite);
 | 
			
		||||
    } /* if */
 | 
			
		||||
 | 
			
		||||
    if (GPipeRead != NULLPIPE)
 | 
			
		||||
        closePipe(GPipeRead);
 | 
			
		||||
 | 
			
		||||
    GPipeRead = GPipeWrite = NULLPIPE;
 | 
			
		||||
 | 
			
		||||
    signal(SIGPIPE, SIG_DFL);
 | 
			
		||||
} /* STEAMSHIM_deinit */
 | 
			
		||||
 | 
			
		||||
static inline int isAlive(void)
 | 
			
		||||
{
 | 
			
		||||
    return ((GPipeRead != NULLPIPE) && (GPipeWrite != NULLPIPE));
 | 
			
		||||
} /* isAlive */
 | 
			
		||||
 | 
			
		||||
static inline int isDead(void)
 | 
			
		||||
{
 | 
			
		||||
    return !isAlive();
 | 
			
		||||
} /* isDead */
 | 
			
		||||
 | 
			
		||||
int STEAMSHIM_alive(void)
 | 
			
		||||
{
 | 
			
		||||
    return isAlive();
 | 
			
		||||
} /* STEAMSHIM_alive */
 | 
			
		||||
 | 
			
		||||
static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen)
 | 
			
		||||
{
 | 
			
		||||
    static STEAMSHIM_Event event;
 | 
			
		||||
    const STEAMSHIM_EventType type = (STEAMSHIM_EventType) *(buf++);
 | 
			
		||||
    buflen--;
 | 
			
		||||
 | 
			
		||||
    memset(&event, '\0', sizeof (event));
 | 
			
		||||
    event.type = type;
 | 
			
		||||
    event.okay = 1;
 | 
			
		||||
 | 
			
		||||
    #if DEBUGPIPE
 | 
			
		||||
    if (0) {}
 | 
			
		||||
    #define PRINTGOTEVENT(x) else if (type == x) printf("Child got " #x ".\n")
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_BYE);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_STATSRECEIVED);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_STATSSTORED);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_SETACHIEVEMENT);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_GETACHIEVEMENT);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_RESETSTATS);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_SETSTATI);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_GETSTATI);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_SETSTATF);
 | 
			
		||||
    PRINTGOTEVENT(SHIMEVENT_GETSTATF);
 | 
			
		||||
    #undef PRINTGOTEVENT
 | 
			
		||||
    else printf("Child got unknown shimevent %d.\n", (int) type);
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    switch (type)
 | 
			
		||||
    {
 | 
			
		||||
        case SHIMEVENT_BYE:
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case SHIMEVENT_STATSRECEIVED:
 | 
			
		||||
        case SHIMEVENT_STATSSTORED:
 | 
			
		||||
            if (!buflen) return NULL;
 | 
			
		||||
            event.okay = *(buf++) ? 1 : 0;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case SHIMEVENT_SETACHIEVEMENT:
 | 
			
		||||
            if (buflen < 3) return NULL;
 | 
			
		||||
            event.ivalue = *(buf++) ? 1 : 0;
 | 
			
		||||
            event.okay = *(buf++) ? 1 : 0;
 | 
			
		||||
            strcpy(event.name, (const char *) buf);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case SHIMEVENT_GETACHIEVEMENT:
 | 
			
		||||
            if (buflen < 10) return NULL;
 | 
			
		||||
            event.ivalue = (int) *(buf++);
 | 
			
		||||
            if (event.ivalue == 2)
 | 
			
		||||
                event.ivalue = event.okay = 0;
 | 
			
		||||
            event.epochsecs = (long long unsigned) *((uint64 *) buf);
 | 
			
		||||
            buf += sizeof (uint64);
 | 
			
		||||
            strcpy(event.name, (const char *) buf);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case SHIMEVENT_RESETSTATS:
 | 
			
		||||
            if (buflen != 2) return NULL;
 | 
			
		||||
            event.ivalue = *(buf++) ? 1 : 0;
 | 
			
		||||
            event.okay = *(buf++) ? 1 : 0;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case SHIMEVENT_SETSTATI:
 | 
			
		||||
        case SHIMEVENT_GETSTATI:
 | 
			
		||||
            event.okay = *(buf++) ? 1 : 0;
 | 
			
		||||
            event.ivalue = (int) *((int32 *) buf);
 | 
			
		||||
            buf += sizeof (int32);
 | 
			
		||||
            strcpy(event.name, (const char *) buf);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case SHIMEVENT_SETSTATF:
 | 
			
		||||
        case SHIMEVENT_GETSTATF:
 | 
			
		||||
            event.okay = *(buf++) ? 1 : 0;
 | 
			
		||||
            event.fvalue = (int) *((float *) buf);
 | 
			
		||||
            buf += sizeof (float);
 | 
			
		||||
            strcpy(event.name, (const char *) buf);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:  /* uh oh */
 | 
			
		||||
            return NULL;
 | 
			
		||||
    } /* switch */
 | 
			
		||||
 | 
			
		||||
    return &event;
 | 
			
		||||
} /* processEvent */
 | 
			
		||||
 | 
			
		||||
const STEAMSHIM_Event *STEAMSHIM_pump(void)
 | 
			
		||||
{
 | 
			
		||||
    static uint8 buf[256];
 | 
			
		||||
    static int br = 0;
 | 
			
		||||
    int evlen = (br > 0) ? ((int) buf[0]) : 0;
 | 
			
		||||
 | 
			
		||||
    if (isDead())
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    if (br <= evlen)  /* we have an incomplete commmand. Try to read more. */
 | 
			
		||||
    {
 | 
			
		||||
        if (pipeReady(GPipeRead))
 | 
			
		||||
        {
 | 
			
		||||
            const int morebr = readPipe(GPipeRead, buf + br, sizeof (buf) - br);
 | 
			
		||||
            if (morebr > 0)
 | 
			
		||||
                br += morebr;
 | 
			
		||||
            else  /* uh oh */
 | 
			
		||||
            {
 | 
			
		||||
                dbgpipe("Child readPipe failed! Shutting down.\n");
 | 
			
		||||
                STEAMSHIM_deinit();   /* kill it all. */
 | 
			
		||||
            } /* else */
 | 
			
		||||
        } /* if */
 | 
			
		||||
    } /* if */
 | 
			
		||||
 | 
			
		||||
    if (evlen && (br > evlen))
 | 
			
		||||
    {
 | 
			
		||||
        const STEAMSHIM_Event *retval = processEvent(buf+1, evlen);
 | 
			
		||||
        br -= evlen + 1;
 | 
			
		||||
        if (br > 0)
 | 
			
		||||
            memmove(buf, buf+evlen+1, br);
 | 
			
		||||
        return retval;
 | 
			
		||||
    } /* if */
 | 
			
		||||
 | 
			
		||||
    /* Run Steam event loop. */
 | 
			
		||||
    if (br == 0)
 | 
			
		||||
    {
 | 
			
		||||
        dbgpipe("Child sending SHIMCMD_PUMP().\n");
 | 
			
		||||
        write1ByteCmd(SHIMCMD_PUMP);
 | 
			
		||||
    } /* if */
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
} /* STEAMSHIM_pump */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_requestStats(void)
 | 
			
		||||
{
 | 
			
		||||
    if (isDead()) return;
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_REQUESTSTATS().\n");
 | 
			
		||||
    write1ByteCmd(SHIMCMD_REQUESTSTATS);
 | 
			
		||||
} /* STEAMSHIM_requestStats */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_storeStats(void)
 | 
			
		||||
{
 | 
			
		||||
    if (isDead()) return;
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_STORESTATS().\n");
 | 
			
		||||
    write1ByteCmd(SHIMCMD_STORESTATS);
 | 
			
		||||
} /* STEAMSHIM_storeStats */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_setAchievement(const char *name, const int enable)
 | 
			
		||||
{
 | 
			
		||||
    uint8 buf[256];
 | 
			
		||||
    uint8 *ptr = buf+1;
 | 
			
		||||
    if (isDead()) return;
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_SETACHIEVEMENT('%s', %senable).\n", name, enable ? "" : "!");
 | 
			
		||||
    *(ptr++) = (uint8) SHIMCMD_SETACHIEVEMENT;
 | 
			
		||||
    *(ptr++) = enable ? 1 : 0;
 | 
			
		||||
    strcpy((char *) ptr, name);
 | 
			
		||||
    ptr += strlen(name) + 1;
 | 
			
		||||
    buf[0] = (uint8) ((ptr-1) - buf);
 | 
			
		||||
    writePipe(GPipeWrite, buf, buf[0] + 1);
 | 
			
		||||
} /* STEAMSHIM_setAchievement */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_getAchievement(const char *name)
 | 
			
		||||
{
 | 
			
		||||
    uint8 buf[256];
 | 
			
		||||
    uint8 *ptr = buf+1;
 | 
			
		||||
    if (isDead()) return;
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_GETACHIEVEMENT('%s').\n", name);
 | 
			
		||||
    *(ptr++) = (uint8) SHIMCMD_GETACHIEVEMENT;
 | 
			
		||||
    strcpy((char *) ptr, name);
 | 
			
		||||
    ptr += strlen(name) + 1;
 | 
			
		||||
    buf[0] = (uint8) ((ptr-1) - buf);
 | 
			
		||||
    writePipe(GPipeWrite, buf, buf[0] + 1);
 | 
			
		||||
} /* STEAMSHIM_getAchievement */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_resetStats(const int bAlsoAchievements)
 | 
			
		||||
{
 | 
			
		||||
    if (isDead()) return;
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_RESETSTATS(%salsoAchievements).\n", bAlsoAchievements ? "" : "!");
 | 
			
		||||
    write2ByteCmd(SHIMCMD_RESETSTATS, bAlsoAchievements ? 1 : 0);
 | 
			
		||||
} /* STEAMSHIM_resetStats */
 | 
			
		||||
 | 
			
		||||
static void writeStatThing(const ShimCmd cmd, const char *name, const void *val, const size_t vallen)
 | 
			
		||||
{
 | 
			
		||||
    uint8 buf[256];
 | 
			
		||||
    uint8 *ptr = buf+1;
 | 
			
		||||
    if (isDead()) return;
 | 
			
		||||
    *(ptr++) = (uint8) cmd;
 | 
			
		||||
    if (vallen)
 | 
			
		||||
    {
 | 
			
		||||
        memcpy(ptr, val, vallen);
 | 
			
		||||
        ptr += vallen;
 | 
			
		||||
    } /* if */
 | 
			
		||||
    strcpy((char *) ptr, name);
 | 
			
		||||
    ptr += strlen(name) + 1;
 | 
			
		||||
    buf[0] = (uint8) ((ptr-1) - buf);
 | 
			
		||||
    writePipe(GPipeWrite, buf, buf[0] + 1);
 | 
			
		||||
} /* writeStatThing */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_setStatI(const char *name, const int _val)
 | 
			
		||||
{
 | 
			
		||||
    const int32 val = (int32) _val;
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_SETSTATI('%s', val %d).\n", name, val);
 | 
			
		||||
    writeStatThing(SHIMCMD_SETSTATI, name, &val, sizeof (val));
 | 
			
		||||
} /* STEAMSHIM_setStatI */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_getStatI(const char *name)
 | 
			
		||||
{
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_GETSTATI('%s').\n", name);
 | 
			
		||||
    writeStatThing(SHIMCMD_GETSTATI, name, NULL, 0);
 | 
			
		||||
} /* STEAMSHIM_getStatI */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_setStatF(const char *name, const float val)
 | 
			
		||||
{
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_SETSTATF('%s', val %f).\n", name, val);
 | 
			
		||||
    writeStatThing(SHIMCMD_SETSTATF, name, &val, sizeof (val));
 | 
			
		||||
} /* STEAMSHIM_setStatF */
 | 
			
		||||
 | 
			
		||||
void STEAMSHIM_getStatF(const char *name)
 | 
			
		||||
{
 | 
			
		||||
    dbgpipe("Child sending SHIMCMD_GETSTATF('%s').\n", name);
 | 
			
		||||
    writeStatThing(SHIMCMD_GETSTATF, name, NULL, 0);
 | 
			
		||||
} /* STEAMSHIM_getStatF */
 | 
			
		||||
 | 
			
		||||
/* end of steamshim_child.c ... */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										54
									
								
								steamshim/steamshim_child.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								steamshim/steamshim_child.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
#ifndef _INCL_STEAMSHIM_CHILD_H_
 | 
			
		||||
#define _INCL_STEAMSHIM_CHILD_H_
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef enum STEAMSHIM_EventType
 | 
			
		||||
{
 | 
			
		||||
    SHIMEVENT_BYE,
 | 
			
		||||
    SHIMEVENT_STATSRECEIVED,
 | 
			
		||||
    SHIMEVENT_STATSSTORED,
 | 
			
		||||
    SHIMEVENT_SETACHIEVEMENT,
 | 
			
		||||
    SHIMEVENT_GETACHIEVEMENT,
 | 
			
		||||
    SHIMEVENT_RESETSTATS,
 | 
			
		||||
    SHIMEVENT_SETSTATI,
 | 
			
		||||
    SHIMEVENT_GETSTATI,
 | 
			
		||||
    SHIMEVENT_SETSTATF,
 | 
			
		||||
    SHIMEVENT_GETSTATF,
 | 
			
		||||
} STEAMSHIM_EventType;
 | 
			
		||||
 | 
			
		||||
/* not all of these fields make sense in a given event. */
 | 
			
		||||
typedef struct STEAMSHIM_Event
 | 
			
		||||
{
 | 
			
		||||
    STEAMSHIM_EventType type;
 | 
			
		||||
    int okay;
 | 
			
		||||
    int ivalue;
 | 
			
		||||
    float fvalue;
 | 
			
		||||
    unsigned long long epochsecs;
 | 
			
		||||
    char name[256];
 | 
			
		||||
} STEAMSHIM_Event;
 | 
			
		||||
 | 
			
		||||
int STEAMSHIM_init(void);  /* non-zero on success, zero on failure. */
 | 
			
		||||
void STEAMSHIM_deinit(void);
 | 
			
		||||
int STEAMSHIM_alive(void);
 | 
			
		||||
const STEAMSHIM_Event *STEAMSHIM_pump(void);
 | 
			
		||||
void STEAMSHIM_requestStats(void);
 | 
			
		||||
void STEAMSHIM_storeStats(void);
 | 
			
		||||
void STEAMSHIM_setAchievement(const char *name, const int enable);
 | 
			
		||||
void STEAMSHIM_getAchievement(const char *name);
 | 
			
		||||
void STEAMSHIM_resetStats(const int bAlsoAchievements);
 | 
			
		||||
void STEAMSHIM_setStatI(const char *name, const int _val);
 | 
			
		||||
void STEAMSHIM_getStatI(const char *name);
 | 
			
		||||
void STEAMSHIM_setStatF(const char *name, const float val);
 | 
			
		||||
void STEAMSHIM_getStatF(const char *name);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif  /* include-once blocker */
 | 
			
		||||
 | 
			
		||||
/* end of steamshim_child.h ... */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue