mirror of
https://github.com/libretro/RetroArch.git
synced 2025-02-21 10:11:18 +00:00
Add preliminary network command interface.
This commit is contained in:
parent
e1a3bf48fd
commit
0375de48a2
2
Makefile
2
Makefile
@ -46,7 +46,7 @@ ifeq ($(HAVE_BSV_MOVIE), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_NETPLAY), 1)
|
||||
OBJ += netplay.o
|
||||
OBJ += netplay.o network_cmd.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RSOUND), 1)
|
||||
|
@ -95,7 +95,7 @@ endif
|
||||
|
||||
ifeq ($(HAVE_NETPLAY), 1)
|
||||
DEFINES += -DHAVE_NETPLAY
|
||||
OBJ += netplay.o
|
||||
OBJ += netplay.o network_cmd.o
|
||||
LIBS += -lws2_32
|
||||
endif
|
||||
|
||||
|
@ -280,6 +280,10 @@ static const bool savestate_auto_index = false;
|
||||
// Slowmotion ratio.
|
||||
static const float slowmotion_ratio = 3.0;
|
||||
|
||||
// Enable network command interface
|
||||
static const bool network_cmd_enable = false;
|
||||
static const uint16_t network_cmd_port = 55355;
|
||||
|
||||
|
||||
////////////////////
|
||||
// Keybinds, Joypad
|
||||
|
23
driver.h
23
driver.h
@ -24,6 +24,14 @@
|
||||
#include "msvc/msvc_compat.h"
|
||||
#include "input/keysym.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
#include "network_cmd.h"
|
||||
#endif
|
||||
|
||||
#define AUDIO_CHUNK_SIZE_BLOCKING 64
|
||||
#define AUDIO_CHUNK_SIZE_NONBLOCKING 2048 // So we don't get complete line-noise when fast-forwarding audio.
|
||||
#define AUDIO_MAX_RATIO 16
|
||||
@ -167,6 +175,10 @@ typedef struct driver
|
||||
void *audio_data;
|
||||
void *video_data;
|
||||
void *input_data;
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
network_cmd_t *network_cmd;
|
||||
#endif
|
||||
} driver_t;
|
||||
|
||||
void init_drivers(void);
|
||||
@ -243,8 +255,17 @@ extern const input_driver_t input_xdk360;
|
||||
#define input_poll_func() driver.input->poll(driver.input_data)
|
||||
#define input_input_state_func(snes_keybinds, port, device, index, id) \
|
||||
driver.input->input_state(driver.input_data, snes_keybinds, port, device, index, id)
|
||||
#define input_key_pressed_func(key) driver.input->key_pressed(driver.input_data, key)
|
||||
#define input_free_func() driver.input->free(driver.input_data)
|
||||
|
||||
static inline bool input_key_pressed_func(int key)
|
||||
{
|
||||
bool ret = driver.input->key_pressed(driver.input_data, key);
|
||||
#ifdef HAVE_NETPLAY
|
||||
if (!ret && driver.network_cmd)
|
||||
ret = network_cmd_get(driver.network_cmd, key);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -53,6 +53,7 @@
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
#include "netplay.h"
|
||||
#include "network_cmd.h"
|
||||
#endif
|
||||
|
||||
#include "audio/resampler.h"
|
||||
@ -177,6 +178,9 @@ struct settings
|
||||
|
||||
bool block_sram_overwrite;
|
||||
bool savestate_auto_index;
|
||||
|
||||
bool network_cmd_enable;
|
||||
uint16_t network_cmd_port;
|
||||
};
|
||||
|
||||
// Settings and/or global state that is specific to a console-style implementation.
|
||||
|
32
netplay.c
32
netplay.c
@ -13,35 +13,7 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(_XBOX)
|
||||
#define NOD3D
|
||||
#include <xtl.h>
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/sysmodule.h>
|
||||
#include <netex/net.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "netplay_compat.h"
|
||||
#include "netplay.h"
|
||||
#include "general.h"
|
||||
#include "autosave.h"
|
||||
@ -50,8 +22,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "netplay_compat.h"
|
||||
|
||||
// Checks if input port/index is controlled by netplay or not.
|
||||
static bool netplay_is_alive(netplay_t *handle);
|
||||
|
||||
|
@ -57,3 +57,4 @@ void netplay_pre_frame(netplay_t *handle);
|
||||
void netplay_post_frame(netplay_t *handle);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -20,6 +20,34 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(_XBOX)
|
||||
#define NOD3D
|
||||
#include <xtl.h>
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/sysmodule.h>
|
||||
#include <netex/net.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _XBOX
|
||||
#define socklen_t int
|
||||
#endif
|
||||
@ -29,9 +57,7 @@
|
||||
#define close(x) closesocket(x)
|
||||
#define CONST_CAST (const char*)
|
||||
#define NONCONST_CAST (char*)
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CAST
|
||||
#define NONCONST_CAST
|
||||
#include <sys/time.h>
|
||||
@ -41,7 +67,6 @@
|
||||
#define close(x) socketclose(x)
|
||||
#define select(nfds, readfds, writefds, errorfds, timeout) socketselect(nfds, readfds, writefds, errorfds, timeout)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Compatibility layer for legacy or incomplete BSD socket implementations.
|
||||
@ -80,6 +105,5 @@ void freeaddrinfo(struct addrinfo *res);
|
||||
// gai_strerror() not used, so we skip that.
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
179
network_cmd.c
Normal file
179
network_cmd.c
Normal file
@ -0,0 +1,179 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "netplay_compat.h"
|
||||
#include "network_cmd.h"
|
||||
#include "driver.h"
|
||||
#include "general.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
struct network_cmd
|
||||
{
|
||||
int fd;
|
||||
bool state[RARCH_BIND_LIST_END];
|
||||
};
|
||||
|
||||
network_cmd_t *network_cmd_new(uint16_t port)
|
||||
{
|
||||
network_cmd_t *handle = (network_cmd_t*)calloc(1, sizeof(*handle));
|
||||
if (!handle)
|
||||
return NULL;
|
||||
|
||||
handle->fd = -1;
|
||||
|
||||
struct addrinfo hints, *res = NULL;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
#if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY)
|
||||
hints.ai_family = AF_INET;
|
||||
#else
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
#endif
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
char port_buf[16];
|
||||
int yes = 1;
|
||||
|
||||
snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
|
||||
if (getaddrinfo(NULL, port_buf, &hints, &res) < 0)
|
||||
goto error;
|
||||
|
||||
handle->fd = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, res->ai_protocol);
|
||||
if (handle->fd < 0)
|
||||
goto error;
|
||||
|
||||
setsockopt(handle->fd, SOL_SOCKET, SO_REUSEADDR, CONST_CAST &yes, sizeof(int));
|
||||
if (bind(handle->fd, res->ai_addr, res->ai_addrlen) < 0)
|
||||
{
|
||||
RARCH_ERR("Failed to bind socket.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
return handle;
|
||||
|
||||
error:
|
||||
if (res)
|
||||
freeaddrinfo(res);
|
||||
network_cmd_free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void network_cmd_free(network_cmd_t *handle)
|
||||
{
|
||||
if (handle->fd >= 0)
|
||||
close(handle->fd);
|
||||
|
||||
free(handle);
|
||||
}
|
||||
|
||||
struct cmd_map
|
||||
{
|
||||
const char *str;
|
||||
unsigned id;
|
||||
};
|
||||
|
||||
static const struct cmd_map map[] = {
|
||||
{ "FAST_FORWARD", RARCH_FAST_FORWARD_KEY },
|
||||
{ "FAST_FORWARD_HOLD", RARCH_FAST_FORWARD_HOLD_KEY },
|
||||
{ "LOAD_STATE", RARCH_LOAD_STATE_KEY },
|
||||
{ "SAVE_STATE", RARCH_SAVE_STATE_KEY },
|
||||
{ "FULLSCREEN_TOGGLE", RARCH_FULLSCREEN_TOGGLE_KEY },
|
||||
{ "QUIT", RARCH_QUIT_KEY },
|
||||
{ "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS },
|
||||
{ "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS },
|
||||
{ "AUDIO_INPUT_RATE_PLUS", RARCH_AUDIO_INPUT_RATE_PLUS },
|
||||
{ "AUDIO_INPUT_RATE_MINUS", RARCH_AUDIO_INPUT_RATE_MINUS },
|
||||
{ "REWIND", RARCH_REWIND },
|
||||
{ "MOVIE_RECORD_TOGGLE", RARCH_MOVIE_RECORD_TOGGLE },
|
||||
{ "PAUSE_TOGGLE", RARCH_PAUSE_TOGGLE },
|
||||
{ "FRAMEADVANCE", RARCH_FRAMEADVANCE },
|
||||
{ "RESET", RARCH_RESET },
|
||||
{ "SHADER_NEXT", RARCH_SHADER_NEXT },
|
||||
{ "SHADER_PREV", RARCH_SHADER_PREV },
|
||||
{ "CHEAT_INDEX_PLUS", RARCH_CHEAT_INDEX_PLUS },
|
||||
{ "CHEAT_INDEX_MINUS", RARCH_CHEAT_INDEX_MINUS },
|
||||
{ "CHEAT_TOGGLE", RARCH_CHEAT_TOGGLE },
|
||||
{ "SCREENSHOT", RARCH_SCREENSHOT },
|
||||
{ "DSP_CONFIG", RARCH_DSP_CONFIG },
|
||||
{ "MUTE", RARCH_MUTE },
|
||||
{ "NETPLAY_FLIP", RARCH_NETPLAY_FLIP },
|
||||
{ "SLOWMOTION", RARCH_SLOWMOTION },
|
||||
};
|
||||
|
||||
static void parse_sub_msg(network_cmd_t *handle, const char *tok)
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(map) / sizeof(map[0]); i++)
|
||||
{
|
||||
if (strcmp(tok, map[i].str) == 0)
|
||||
{
|
||||
handle->state[map[i].id] = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RARCH_WARN("Unrecognized command \"%s\" received.\n", tok);
|
||||
}
|
||||
|
||||
static void parse_msg(network_cmd_t *handle, char *buf)
|
||||
{
|
||||
const char *tok = strtok(buf, "\n");
|
||||
while (tok)
|
||||
{
|
||||
parse_sub_msg(handle, tok);
|
||||
tok = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void network_cmd_set(network_cmd_t *handle, unsigned id)
|
||||
{
|
||||
if (id < RARCH_BIND_LIST_END)
|
||||
handle->state[id] = true;
|
||||
}
|
||||
|
||||
bool network_cmd_get(network_cmd_t *handle, unsigned id)
|
||||
{
|
||||
return id < RARCH_BIND_LIST_END && handle->state[id];
|
||||
}
|
||||
|
||||
void network_cmd_pre_frame(network_cmd_t *handle)
|
||||
{
|
||||
memset(handle->state, 0, sizeof(handle->state));
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(handle->fd, &fds);
|
||||
|
||||
struct timeval tmp_tv = {0};
|
||||
if (select(handle->fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
||||
return;
|
||||
|
||||
if (!FD_ISSET(handle->fd, &fds))
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buf[1024];
|
||||
ssize_t ret = recvfrom(handle->fd, buf, sizeof(buf) - 1, 0, NULL, NULL);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
buf[ret] = '\0';
|
||||
parse_msg(handle, buf);
|
||||
}
|
||||
}
|
||||
|
32
network_cmd.h
Normal file
32
network_cmd.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_CMD_H__
|
||||
#define NETWORK_CMD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct network_cmd network_cmd_t;
|
||||
|
||||
network_cmd_t *network_cmd_new(uint16_t port);
|
||||
void network_cmd_free(network_cmd_t *handle);
|
||||
|
||||
void network_cmd_pre_frame(network_cmd_t *handle);
|
||||
void network_cmd_set(network_cmd_t *handle, unsigned id);
|
||||
bool network_cmd_get(network_cmd_t *handle, unsigned id);
|
||||
|
||||
#endif
|
||||
|
26
retroarch.c
26
retroarch.c
@ -1337,6 +1337,25 @@ static void deinit_netplay(void)
|
||||
if (g_extern.netplay)
|
||||
netplay_free(g_extern.netplay);
|
||||
}
|
||||
|
||||
static void init_network_cmd(void)
|
||||
{
|
||||
if (!g_settings.network_cmd_enable)
|
||||
return;
|
||||
|
||||
driver.network_cmd = network_cmd_new(g_settings.network_cmd_port);
|
||||
if (!driver.network_cmd)
|
||||
RARCH_ERR("Failed to initialize network command interface.\n");
|
||||
}
|
||||
|
||||
static void deinit_network_cmd(void)
|
||||
{
|
||||
if (driver.network_cmd)
|
||||
{
|
||||
network_cmd_free(driver.network_cmd);
|
||||
driver.network_cmd = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void init_libretro_cbs_plain(void)
|
||||
@ -2353,6 +2372,7 @@ int rarch_main_init(int argc, char *argv[])
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
init_netplay();
|
||||
init_network_cmd();
|
||||
#endif
|
||||
init_drivers();
|
||||
|
||||
@ -2427,6 +2447,11 @@ bool rarch_main_iterate(void)
|
||||
!video_alive_func())
|
||||
return false;
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
if (driver.network_cmd)
|
||||
network_cmd_pre_frame(driver.network_cmd);
|
||||
#endif
|
||||
|
||||
// Checks for stuff like fullscreen, save states, etc.
|
||||
do_state_checks();
|
||||
|
||||
@ -2480,6 +2505,7 @@ void rarch_main_deinit(void)
|
||||
{
|
||||
#ifdef HAVE_NETPLAY
|
||||
deinit_netplay();
|
||||
deinit_network_cmd();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
|
@ -358,3 +358,7 @@
|
||||
# Slowmotion ratio. When slowmotion, game will slow down by factor.
|
||||
# slowmotion_ratio = 3.0
|
||||
|
||||
# Enable network command interface.
|
||||
# network_cmd_enable = false
|
||||
# network_cmd_port = 55355
|
||||
|
||||
|
@ -189,6 +189,8 @@ void config_set_defaults(void)
|
||||
|
||||
g_settings.block_sram_overwrite = block_sram_overwrite;
|
||||
g_settings.savestate_auto_index = savestate_auto_index;
|
||||
g_settings.network_cmd_enable = network_cmd_enable;
|
||||
g_settings.network_cmd_port = network_cmd_port;
|
||||
|
||||
rarch_assert(sizeof(g_settings.input.binds[0]) >= sizeof(snes_keybinds_1));
|
||||
rarch_assert(sizeof(g_settings.input.binds[1]) >= sizeof(snes_keybinds_rest));
|
||||
@ -455,6 +457,9 @@ bool config_load_file(const char *path)
|
||||
CONFIG_GET_BOOL(block_sram_overwrite, "block_sram_overwrite");
|
||||
CONFIG_GET_BOOL(savestate_auto_index, "savestate_auto_index");
|
||||
|
||||
CONFIG_GET_BOOL(network_cmd_enable, "network_cmd_enable");
|
||||
CONFIG_GET_INT(network_cmd_port, "network_cmd_port");
|
||||
|
||||
if (config_get_string(conf, "environment_variables",
|
||||
&g_extern.system.environment))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user