/* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2016 - Daniel De Matteis * * 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 . */ #ifndef __RARCH_NETPLAY_PRIVATE_H #define __RARCH_NETPLAY_PRIVATE_H #include "netplay.h" #include #include #include "../command.h" #include "../general.h" #include "../autosave.h" #include "../dynamic.h" #include "../movie.h" #include "../msg_hash.h" #include "../system.h" #include "../runloop.h" #include "../verbosity.h" #ifdef ANDROID #define HAVE_IPV6 #endif #define UDP_FRAME_PACKETS 16 #define UDP_WORDS_PER_FRAME 4 /* Allows us to send 128 bits worth of state per frame. */ #define MAX_SPECTATORS 16 #define RARCH_DEFAULT_PORT 55435 #define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1) #define NEXT_PTR(x) ((x + 1) % netplay->buffer_size) struct delta_frame { void *state; uint32_t real_input_state[UDP_WORDS_PER_FRAME - 1]; uint32_t simulated_input_state[UDP_WORDS_PER_FRAME - 1]; uint32_t self_state[UDP_WORDS_PER_FRAME - 1]; bool is_simulated; bool used_real; }; struct netplay_callbacks { void (*pre_frame) (netplay_t *netplay); void (*post_frame)(netplay_t *netplay); bool (*info_cb) (netplay_t *netplay, unsigned frames); }; struct netplay { char nick[32]; char other_nick[32]; struct sockaddr_storage other_addr; struct retro_callbacks cbs; /* TCP connection for state sending, etc. Also used for commands */ int fd; /* UDP connection for game state updates. */ int udp_fd; /* Which port is governed by netplay (other user)? */ unsigned port; bool has_connection; struct delta_frame *buffer; size_t buffer_size; /* Pointer where we are now. */ size_t self_ptr; /* Points to the last reliable state that self ever had. */ size_t other_ptr; /* Pointer to where we are reading. * Generally, other_ptr <= read_ptr <= self_ptr. */ size_t read_ptr; /* A temporary pointer used on replay. */ size_t tmp_ptr; size_t state_size; /* Are we replaying old frames? */ bool is_replay; /* We don't want to poll several times on a frame. */ bool can_poll; /* To compat UDP packet loss we also send * old data along with the packets. */ uint32_t packet_buffer[UDP_FRAME_PACKETS * UDP_WORDS_PER_FRAME]; uint32_t frame_count; uint32_t read_frame_count; uint32_t other_frame_count; uint32_t tmp_frame_count; struct addrinfo *addr; struct sockaddr_storage their_addr; bool has_client_addr; unsigned timeout_cnt; /* Spectating. */ struct { bool enabled; int fds[MAX_SPECTATORS]; uint16_t *input; size_t input_ptr; size_t input_sz; } spectate; bool is_server; /* User flipping * Flipping state. If ptr >= flip_frame, we apply the flip. * If not, we apply the opposite, effectively creating a trigger point. * To avoid collition we need to make sure our client/host is synced up * well after flip_frame before allowing another flip. */ bool flip; uint32_t flip_frame; /* Netplay pausing */ bool pause; uint32_t pause_frame; struct netplay_callbacks* net_cbs; }; extern void *netplay_data; struct netplay_callbacks* netplay_get_cbs_net(void); struct netplay_callbacks* netplay_get_cbs_spectate(void); void netplay_log_connection(const struct sockaddr_storage *their_addr, unsigned slot, const char *nick); bool netplay_get_nickname(netplay_t *netplay, int fd); bool netplay_send_nickname(netplay_t *netplay, int fd); bool netplay_send_info(netplay_t *netplay); uint32_t *netplay_bsv_header_generate(size_t *size, uint32_t magic); bool netplay_bsv_parse_header(const uint32_t *header, uint32_t magic); uint32_t netplay_impl_magic(void); bool netplay_send_info(netplay_t *netplay); bool netplay_get_info(netplay_t *netplay); bool netplay_is_server(netplay_t* netplay); bool netplay_is_spectate(netplay_t* netplay); #endif