diff --git a/Source/UnrealLibretro/Private/ulnet.h b/Source/UnrealLibretro/Private/ulnet.h index a186731..4f4902f 100644 --- a/Source/UnrealLibretro/Private/ulnet.h +++ b/Source/UnrealLibretro/Private/ulnet.h @@ -31,7 +31,7 @@ #define ULNET_CHANNEL_EXTRA 0x00 #define ULNET_CHANNEL_INPUT 0x10 -#define ULNET_CHANNEL_INPUT_AUDIT_CONSISTENCY 0x20 +#define ULNET_CHANNEL_SPECTATOR_INPUT 0x20 #define ULNET_CHANNEL_SAVESTATE_TRANSFER 0x30 #define ULNET_CHANNEL_DESYNC_DEBUG 0xF0 @@ -184,6 +184,7 @@ typedef struct ulnet_session { juice_agent_t *agent [SAM2_PORT_MAX + 1 /* Plus Authority */ + ULNET_SPECTATOR_MAX]; int64_t peer_desynced_frame [SAM2_PORT_MAX + 1 /* Plus Authority */ + ULNET_SPECTATOR_MAX]; ulnet_state_t state [SAM2_PORT_MAX + 1 /* Plus Authority */]; + ulnet_input_state_t spectator_suggested_input_state[SAM2_PORT_MAX + 1 /* Plus Authority */ + ULNET_SPECTATOR_MAX][ULNET_PORT_COUNT]; unsigned char state_packet_history[SAM2_PORT_MAX + 1 /* Plus Authority */][ULNET_STATE_PACKET_HISTORY_SIZE][ULNET_PACKET_SIZE_BYTES_MAX]; uint64_t peer_needs_sync_bitfield; @@ -323,6 +324,8 @@ ULNET_LINKAGE ulnet_input_state_t (*ulnet_query_generate_next_input(ulnet_sessio //} return &session->state[ulnet_our_port(session)].input_state[next_buffer_index]; + } else if (ulnet_is_spectator(session, session->our_peer_id)) { + return &session->spectator_suggested_input_state[ulnet_our_port(session)]; } return NULL; @@ -386,19 +389,24 @@ ULNET_LINKAGE int ulnet_poll_session(ulnet_session_t *session, bool force_save_s uint8_t _[RLE8_ENCODE_UPPER_BOUND(ULNET_PACKET_SIZE_BYTES_MAX)]; ulnet_state_packet_t *input_packet = (ulnet_state_packet_t *) _; input_packet->channel_and_port = ULNET_CHANNEL_INPUT | ulnet_our_port(session); - int64_t actual_payload_size = rle8_encode( - (uint8_t *)&session->state[ulnet_our_port(session)], - sizeof(session->state[0]), - input_packet->coded_state - ); - void *next_history_packet = &session->state_packet_history[ulnet_our_port(session)][session->state[ulnet_our_port(session)].frame % ULNET_STATE_PACKET_HISTORY_SIZE]; - memset(next_history_packet, 0, sizeof(session->state_packet_history[0][0])); - memcpy( - next_history_packet, - input_packet, - actual_payload_size - ); + if (ulnet_is_spectator(session, session->our_peer_id)) { + ; + } else { + int64_t actual_payload_size = rle8_encode( + (uint8_t *)&session->state[ulnet_our_port(session)], + sizeof(session->state[0]), + input_packet->coded_state + ); + + void *next_history_packet = &session->state_packet_history[ulnet_our_port(session)][session->state[ulnet_our_port(session)].frame % ULNET_STATE_PACKET_HISTORY_SIZE]; + memset(next_history_packet, 0, sizeof(session->state_packet_history[0][0])); + memcpy( + next_history_packet, + input_packet, + actual_payload_size + ); + } if (sizeof(ulnet_state_packet_t) + actual_payload_size > ULNET_PACKET_SIZE_BYTES_MAX) { SAM2_LOG_FATAL("Input packet too large to send"); @@ -409,8 +417,7 @@ ULNET_LINKAGE int ulnet_poll_session(ulnet_session_t *session, bool force_save_s juice_state_t state = juice_get_state(session->agent[p]); // Wait until we can send netplay messages to everyone without fail - if ( state == JUICE_STATE_CONNECTED || state == JUICE_STATE_COMPLETED - && !ulnet_is_spectator(session, session->our_peer_id)) { + if (state == JUICE_STATE_CONNECTED || state == JUICE_STATE_COMPLETED) { juice_send(session->agent[p], (const char *) input_packet, sizeof(ulnet_state_packet_t) + actual_payload_size); SAM2_LOG_DEBUG("Sent input packet for frame %" PRId64 " dest peer_ids[%d]=%" PRIx64, session->state[SAM2_AUTHORITY_INDEX].frame, p, session->room_we_are_in.peer_ids[p]); @@ -852,7 +859,8 @@ static void ulnet_receive_packet_callback(juice_agent_t *agent, const char *data return; } - if (p >= SAM2_PORT_MAX+1) { + if (p >= SAM2_PORT_MAX+1 + && (data[0] & ULNET_CHANNEL_MASK) == ULNET_CHANNEL_SPECTATOR_INPUT) { SAM2_LOG_WARN("A spectator sent us a UDP packet for unsupported channel %" PRIx8 " for some reason", data[0] & ULNET_CHANNEL_MASK); return; } @@ -927,6 +935,14 @@ static void ulnet_receive_packet_callback(juice_agent_t *agent, const char *data break; } + case ULNET_CHANNEL_SPECTATOR_INPUT: { + rle8_decode( + (const uint8_t *) &data[1], size - 1, + (uint8_t *) &session->state[p], sizeof(session->state[p]) + ); + + break; + } case ULNET_CHANNEL_DESYNC_DEBUG: { // @todo This channel doesn't receive messages reliably, but I think it should be changed to in the same manner as the input channel assert(size == sizeof(desync_debug_packet_t));