network: start network before starting game to configure eeprom/flash
do second net sync when comm board is reset close menu/cancel loading when pressing menu button
This commit is contained in:
parent
65f156817c
commit
bec7a9f452
|
@ -22,6 +22,7 @@
|
|||
#include "naomi_regs.h"
|
||||
#include "hw/holly/sb.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include <chrono>
|
||||
|
||||
static inline u16 swap16(u16 w)
|
||||
|
@ -32,7 +33,7 @@ static inline u16 swap16(u16 w)
|
|||
void NaomiM3Comm::closeNetwork()
|
||||
{
|
||||
network_stopping = true;
|
||||
network.shutdown();
|
||||
naomiNetwork.shutdown();
|
||||
if (thread && thread->joinable())
|
||||
thread->join();
|
||||
}
|
||||
|
@ -40,17 +41,17 @@ void NaomiM3Comm::closeNetwork()
|
|||
void NaomiM3Comm::connectNetwork()
|
||||
{
|
||||
packet_number = 0;
|
||||
if (network.startNetwork())
|
||||
if (naomiNetwork.syncNetwork())
|
||||
{
|
||||
slot_count = network.slotCount();
|
||||
slot_id = network.slotId();
|
||||
slot_count = naomiNetwork.slotCount();
|
||||
slot_id = naomiNetwork.slotId();
|
||||
connectedState(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectedState(false);
|
||||
network_stopping = true;
|
||||
network.shutdown();
|
||||
naomiNetwork.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,7 @@ void NaomiM3Comm::receiveNetwork()
|
|||
|
||||
std::unique_ptr<u8[]> buf(new u8[packet_size]);
|
||||
|
||||
if (network.receive(buf.get(), packet_size))
|
||||
if (naomiNetwork.receive(buf.get(), packet_size))
|
||||
{
|
||||
packet_number += slot_count - 1;
|
||||
*(u16*)&comm_ram[6] = swap16(packet_number);
|
||||
|
@ -72,11 +73,11 @@ void NaomiM3Comm::receiveNetwork()
|
|||
|
||||
void NaomiM3Comm::sendNetwork()
|
||||
{
|
||||
if (network.hasToken())
|
||||
if (naomiNetwork.hasToken())
|
||||
{
|
||||
const u32 packet_size = swap16(*(u16*)&m68k_ram[0x204]) * slot_count;
|
||||
std::unique_lock<std::mutex> lock(mem_mutex);
|
||||
network.send(&comm_ram[0x100], packet_size);
|
||||
naomiNetwork.send(&comm_ram[0x100], packet_size);
|
||||
packet_number++;
|
||||
*(u16*)&comm_ram[6] = swap16(packet_number);
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ void NaomiM3Comm::sendNetwork()
|
|||
NaomiM3Comm::~NaomiM3Comm()
|
||||
{
|
||||
closeNetwork();
|
||||
network.terminate();
|
||||
naomiNetwork.terminate();
|
||||
}
|
||||
|
||||
u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
|
||||
|
@ -194,11 +195,11 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
|
|||
if (data & (1 << 5))
|
||||
{
|
||||
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL m68k reset");
|
||||
closeNetwork();
|
||||
memset(&comm_ram[0], 0, 32);
|
||||
comm_status0 = 0; // varies...
|
||||
comm_status1 = 0;
|
||||
startThread();
|
||||
if (!thread || !thread->joinable())
|
||||
startThread();
|
||||
}
|
||||
comm_ctrl = (u16)(data & ~(1 << 5));
|
||||
//DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL set to %x", comm_ctrl);
|
||||
|
@ -280,10 +281,10 @@ void NaomiM3Comm::startThread()
|
|||
|
||||
while (!network_stopping)
|
||||
{
|
||||
network.pipeSlaves();
|
||||
naomiNetwork.pipeSlaves();
|
||||
receiveNetwork();
|
||||
|
||||
if (slot_id == 0 && network.hasToken())
|
||||
if (slot_id == 0 && naomiNetwork.hasToken())
|
||||
{
|
||||
const auto target_duration = std::chrono::milliseconds(10);
|
||||
auto duration = the_clock::now() - token_time;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "network/naomi_network.h"
|
||||
|
||||
class NaomiM3Comm
|
||||
{
|
||||
|
@ -57,5 +56,4 @@ private:
|
|||
std::atomic<bool> network_stopping{ false };
|
||||
std::unique_ptr<std::thread> thread;
|
||||
std::mutex mem_mutex;
|
||||
NaomiNetwork network;
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "naomi_network.h"
|
||||
|
||||
#include "types.h"
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "rend/gui.h"
|
||||
|
@ -31,13 +32,15 @@
|
|||
typedef int ssize_t;
|
||||
#endif
|
||||
|
||||
NaomiNetwork naomiNetwork;
|
||||
|
||||
sock_t NaomiNetwork::createAndBind(int protocol)
|
||||
{
|
||||
sock_t sock = socket(AF_INET, protocol == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM, protocol);
|
||||
if (sock == INVALID_SOCKET)
|
||||
if (!VALID(sock))
|
||||
{
|
||||
ERROR_LOG(NETWORK, "Cannot create server socket");
|
||||
return INVALID_SOCKET;
|
||||
return sock;
|
||||
}
|
||||
int option = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&option, sizeof(option));
|
||||
|
@ -50,8 +53,7 @@ sock_t NaomiNetwork::createAndBind(int protocol)
|
|||
if (::bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
|
||||
{
|
||||
ERROR_LOG(NETWORK, "NaomiServer: bind() failed. errno=%d", get_last_error());
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
closeSocket(sock);
|
||||
}
|
||||
else
|
||||
set_non_blocking(sock);
|
||||
|
@ -79,18 +81,17 @@ bool NaomiNetwork::init()
|
|||
|
||||
bool NaomiNetwork::createServerSocket()
|
||||
{
|
||||
if (server_sock != INVALID_SOCKET)
|
||||
if (VALID(server_sock))
|
||||
return true;
|
||||
|
||||
server_sock = createAndBind(IPPROTO_TCP);
|
||||
if (server_sock == INVALID_SOCKET)
|
||||
if (!VALID(server_sock))
|
||||
return false;
|
||||
|
||||
if (listen(server_sock, 5) < 0)
|
||||
{
|
||||
ERROR_LOG(NETWORK, "NaomiServer: listen() failed. errno=%d", get_last_error());
|
||||
closesocket(server_sock);
|
||||
server_sock = INVALID_SOCKET;
|
||||
closeSocket(server_sock);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -98,10 +99,10 @@ bool NaomiNetwork::createServerSocket()
|
|||
|
||||
bool NaomiNetwork::createBeaconSocket()
|
||||
{
|
||||
if (beacon_sock == INVALID_SOCKET)
|
||||
if (!VALID(beacon_sock))
|
||||
beacon_sock = createAndBind(IPPROTO_UDP);
|
||||
|
||||
return beacon_sock != INVALID_SOCKET;
|
||||
return VALID(beacon_sock);
|
||||
}
|
||||
|
||||
void NaomiNetwork::processBeacon()
|
||||
|
@ -132,7 +133,7 @@ bool NaomiNetwork::findServer()
|
|||
{
|
||||
// Automatically find the adhoc server on the local network using broadcast
|
||||
sock_t sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd == INVALID_SOCKET)
|
||||
if (!VALID(sockfd))
|
||||
{
|
||||
ERROR_LOG(NETWORK, "Datagram socket creation error. errno=%d", get_last_error());
|
||||
return false;
|
||||
|
@ -147,8 +148,8 @@ bool NaomiNetwork::findServer()
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set a 1 sec timeout on recv call
|
||||
if (!set_recv_timeout(sockfd, 1000))
|
||||
// Set a 500ms timeout on recv call
|
||||
if (!set_recv_timeout(sockfd, 500))
|
||||
{
|
||||
ERROR_LOG(NETWORK, "setsockopt(SO_RCVTIMEO) failed. errno=%d", get_last_error());
|
||||
closesocket(sockfd);
|
||||
|
@ -203,7 +204,6 @@ bool NaomiNetwork::findServer()
|
|||
|
||||
bool NaomiNetwork::startNetwork()
|
||||
{
|
||||
network_stopping = false;
|
||||
if (!init())
|
||||
return false;
|
||||
|
||||
|
@ -213,7 +213,7 @@ bool NaomiNetwork::startNetwork()
|
|||
got_token = false;
|
||||
|
||||
using namespace std::chrono;
|
||||
const auto timeout = seconds(10);
|
||||
const auto timeout = seconds(20);
|
||||
|
||||
if (settings.network.ActAsServer)
|
||||
{
|
||||
|
@ -224,9 +224,9 @@ bool NaomiNetwork::startNetwork()
|
|||
{
|
||||
if (network_stopping)
|
||||
{
|
||||
for (auto clientSock : slaves)
|
||||
if (clientSock != INVALID_SOCKET)
|
||||
closesocket(clientSock);
|
||||
for (auto& slave : slaves)
|
||||
if (VALID(slave.socket))
|
||||
closeSocket(slave.socket);
|
||||
return false;
|
||||
}
|
||||
std::string notif = slaves.empty() ? "Waiting for players..."
|
||||
|
@ -239,7 +239,7 @@ bool NaomiNetwork::startNetwork()
|
|||
socklen_t addr_len = sizeof(src_addr);
|
||||
memset(&src_addr, 0, addr_len);
|
||||
sock_t clientSock = accept(server_sock, (struct sockaddr *)&src_addr, &addr_len);
|
||||
if (clientSock == INVALID_SOCKET)
|
||||
if (!VALID(clientSock))
|
||||
{
|
||||
if (get_last_error() != L_EAGAIN && get_last_error() != L_EWOULDBLOCK)
|
||||
perror("accept");
|
||||
|
@ -247,11 +247,58 @@ bool NaomiNetwork::startNetwork()
|
|||
else
|
||||
{
|
||||
NOTICE_LOG(NETWORK, "Slave connection accepted");
|
||||
set_non_blocking(clientSock);
|
||||
set_tcp_nodelay(clientSock);
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
slaves.push_back(clientSock);
|
||||
if (slaves.size() == 3)
|
||||
break;
|
||||
slaves.emplace_back(clientSock);
|
||||
}
|
||||
const auto now = steady_clock::now();
|
||||
u32 waiting_slaves = 0;
|
||||
for (auto& slave : slaves)
|
||||
{
|
||||
if (slave.state == ClientState::Waiting)
|
||||
waiting_slaves++;
|
||||
else if (slave.state == ClientState::Connected)
|
||||
{
|
||||
u8 buffer[8];
|
||||
ssize_t l = ::recv(slave.socket, buffer, sizeof(buffer), 0);
|
||||
if (l < (int)sizeof(buffer) && get_last_error() != EAGAIN && get_last_error() != EWOULDBLOCK)
|
||||
{
|
||||
// error
|
||||
INFO_LOG(NETWORK, "Slave socket recv error. errno=%d", get_last_error());
|
||||
closeSocket(slave.socket);
|
||||
}
|
||||
else if (l == -1 && now - slave.state_time > milliseconds(100))
|
||||
{
|
||||
// timeout
|
||||
INFO_LOG(NETWORK, "Slave socket Connected timeout");
|
||||
closeSocket(slave.socket);
|
||||
}
|
||||
else if (l == (int)sizeof(buffer))
|
||||
{
|
||||
if (memcmp(buffer, naomi_game_id, sizeof(buffer)))
|
||||
{
|
||||
// wrong game
|
||||
WARN_LOG(NETWORK, "Wrong game id received: %.8s", buffer);
|
||||
closeSocket(slave.socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
slave.set_state(ClientState::Waiting);
|
||||
waiting_slaves++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
slaves.erase(std::remove_if(slaves.begin(),
|
||||
slaves.end(),
|
||||
[](const Slave& slave){ return !VALID(slave.socket); }),
|
||||
slaves.end());
|
||||
}
|
||||
if (waiting_slaves == 3 || (start_now && !slaves.empty() && waiting_slaves == slaves.size()))
|
||||
break;
|
||||
std::this_thread::sleep_for(milliseconds(100));
|
||||
}
|
||||
slot_id = 0;
|
||||
|
@ -259,22 +306,27 @@ bool NaomiNetwork::startNetwork()
|
|||
u8 buf[2] = { (u8)slot_count, 0 };
|
||||
int slot_num = 1;
|
||||
{
|
||||
for (int socket : slaves)
|
||||
for (auto& slave : slaves)
|
||||
{
|
||||
buf[1] = { (u8)slot_num };
|
||||
slot_num++;
|
||||
::send(socket, (const char *)buf, 2, 0);
|
||||
set_non_blocking(socket);
|
||||
set_tcp_nodelay(socket);
|
||||
::send(slave.socket, (const char *)buf, 2, 0);
|
||||
slave.set_state(ClientState::Starting);
|
||||
}
|
||||
}
|
||||
NOTICE_LOG(NETWORK, "Master starting: %zd slaves", slaves.size());
|
||||
if (slot_count > 1)
|
||||
if (!slaves.empty())
|
||||
{
|
||||
gui_display_notification("Starting game", 2000);
|
||||
else
|
||||
gui_display_notification("No player connected", 8000);
|
||||
SetNaomiNetworkConfig(0);
|
||||
|
||||
return !slaves.empty();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
gui_display_notification("No player connected", 8000);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -296,8 +348,7 @@ bool NaomiNetwork::startNetwork()
|
|||
gui_display_notification("Connecting to server", 10000);
|
||||
steady_clock::time_point start_time = steady_clock::now();
|
||||
|
||||
while (client_sock == INVALID_SOCKET && !network_stopping
|
||||
&& steady_clock::now() - start_time < timeout)
|
||||
while (!network_stopping && steady_clock::now() - start_time < timeout)
|
||||
{
|
||||
if (server_ip.s_addr == INADDR_NONE && !findServer())
|
||||
continue;
|
||||
|
@ -310,20 +361,20 @@ bool NaomiNetwork::startNetwork()
|
|||
if (::connect(client_sock, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0)
|
||||
{
|
||||
ERROR_LOG(NETWORK, "Socket connect failed");
|
||||
closesocket(client_sock);
|
||||
client_sock = INVALID_SOCKET;
|
||||
closeSocket(client_sock);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
else
|
||||
{
|
||||
gui_display_notification("Waiting for server to start", 10000);
|
||||
set_tcp_nodelay(client_sock);
|
||||
::send(client_sock, naomi_game_id, 8, 0);
|
||||
set_recv_timeout(client_sock, (int)std::chrono::milliseconds(timeout * 2).count());
|
||||
u8 buf[2];
|
||||
if (::recv(client_sock, (char *)buf, 2, 0) < 2)
|
||||
{
|
||||
ERROR_LOG(NETWORK, "recv failed: errno=%d", get_last_error());
|
||||
closesocket(client_sock);
|
||||
client_sock = INVALID_SOCKET;
|
||||
closeSocket(client_sock);
|
||||
gui_display_notification("Server failed to start", 10000);
|
||||
|
||||
return false;
|
||||
|
@ -331,10 +382,11 @@ bool NaomiNetwork::startNetwork()
|
|||
slot_count = buf[0];
|
||||
slot_id = buf[1];
|
||||
got_token = slot_id == 1;
|
||||
set_tcp_nodelay(client_sock);
|
||||
set_non_blocking(client_sock);
|
||||
std::string notif = "Connected as slot " + std::to_string(slot_id);
|
||||
gui_display_notification(notif.c_str(), 2000);
|
||||
SetNaomiNetworkConfig(slot_id);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -343,6 +395,109 @@ bool NaomiNetwork::startNetwork()
|
|||
}
|
||||
}
|
||||
|
||||
bool NaomiNetwork::syncNetwork()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
const auto timeout = seconds(10);
|
||||
|
||||
if (settings.network.ActAsServer)
|
||||
{
|
||||
steady_clock::time_point start_time = steady_clock::now();
|
||||
|
||||
bool all_slaves_ready = false;
|
||||
while (steady_clock::now() - start_time < timeout && !all_slaves_ready)
|
||||
{
|
||||
all_slaves_ready = true;
|
||||
for (auto& slave : slaves)
|
||||
if (slave.state != ClientState::Ready)
|
||||
{
|
||||
u8 buf[4];
|
||||
ssize_t l = ::recv(slave.socket, buf, sizeof(buf), 0);
|
||||
if (l < 4 && get_last_error() != EAGAIN && get_last_error() != EWOULDBLOCK)
|
||||
{
|
||||
INFO_LOG(NETWORK, "Socket recv failed. errno=%d", get_last_error());
|
||||
closeSocket(slave.socket);
|
||||
return false;
|
||||
}
|
||||
if (l == 4)
|
||||
{
|
||||
if (memcmp(buf, "REDY", 4))
|
||||
{
|
||||
INFO_LOG(NETWORK, "Synchronization failed");
|
||||
closeSocket(slave.socket);
|
||||
return false;
|
||||
}
|
||||
slave.set_state(ClientState::Ready);
|
||||
}
|
||||
else
|
||||
all_slaves_ready = false;
|
||||
}
|
||||
if (network_stopping)
|
||||
return false;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
for (auto& slave : slaves)
|
||||
{
|
||||
ssize_t l = ::send(slave.socket, "GO!!", 4, 0);
|
||||
if (l < 4)
|
||||
{
|
||||
INFO_LOG(NETWORK, "Socket send failed. errno=%d", get_last_error());
|
||||
closeSocket(slave.socket);
|
||||
return false;
|
||||
}
|
||||
slave.set_state(ClientState::Online);
|
||||
}
|
||||
gui_display_notification("Network started", 5000);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Tell master we're ready
|
||||
ssize_t l = ::send(client_sock, "REDY", 4 ,0);
|
||||
if (l < 4)
|
||||
{
|
||||
WARN_LOG(NETWORK, "Socket send failed. errno=%d", get_last_error());
|
||||
closeSocket(client_sock);
|
||||
return false;
|
||||
}
|
||||
steady_clock::time_point start_time = steady_clock::now();
|
||||
|
||||
while (steady_clock::now() - start_time < timeout)
|
||||
{
|
||||
// Wait for the go
|
||||
u8 buf[4];
|
||||
l = ::recv(client_sock, buf, sizeof(buf), 0);
|
||||
if (l < 4 && get_last_error() != EAGAIN && get_last_error() != EWOULDBLOCK)
|
||||
{
|
||||
INFO_LOG(NETWORK, "Socket recv failed. errno=%d", get_last_error());
|
||||
closeSocket(client_sock);
|
||||
return false;
|
||||
}
|
||||
else if (l == 4)
|
||||
{
|
||||
if (memcmp(buf, "GO!!", 4))
|
||||
{
|
||||
INFO_LOG(NETWORK, "Synchronization failed");
|
||||
closeSocket(client_sock);
|
||||
return false;
|
||||
}
|
||||
gui_display_notification("Network started", 5000);
|
||||
return true;
|
||||
}
|
||||
if (network_stopping)
|
||||
{
|
||||
closeSocket(client_sock);
|
||||
return false;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
INFO_LOG(NETWORK, "Socket recv timeout");
|
||||
closeSocket(client_sock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NaomiNetwork::pipeSlaves()
|
||||
{
|
||||
if (!isMaster() || slot_count < 3)
|
||||
|
@ -350,25 +505,23 @@ void NaomiNetwork::pipeSlaves()
|
|||
char buf[16384];
|
||||
for (auto it = slaves.begin(); it != slaves.end() - 1; it++)
|
||||
{
|
||||
if (*it == INVALID_SOCKET || *(it + 1) == INVALID_SOCKET)
|
||||
if (!VALID(it->socket) || !VALID((it + 1)->socket))
|
||||
// TODO keep link on
|
||||
continue;
|
||||
ssize_t l = ::recv(*it, buf, sizeof(buf), 0);
|
||||
ssize_t l = ::recv(it->socket, buf, sizeof(buf), 0);
|
||||
if (l <= 0)
|
||||
{
|
||||
if (get_last_error() == L_EAGAIN || get_last_error() == L_EWOULDBLOCK)
|
||||
continue;
|
||||
WARN_LOG(NETWORK, "pipeSlaves: receive failed. errno=%d", get_last_error());
|
||||
closesocket(*it);
|
||||
*it = INVALID_SOCKET;
|
||||
closeSocket(it->socket);
|
||||
continue;
|
||||
}
|
||||
ssize_t l2 = ::send(*(it + 1), buf, l, 0);
|
||||
ssize_t l2 = ::send((it + 1)->socket, buf, l, 0);
|
||||
if (l2 != l)
|
||||
{
|
||||
WARN_LOG(NETWORK, "pipeSlaves: send failed. errno=%d", get_last_error());
|
||||
closesocket(*(it + 1));
|
||||
*(it + 1) = INVALID_SOCKET;
|
||||
closeSocket((it + 1)->socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -377,10 +530,10 @@ bool NaomiNetwork::receive(u8 *data, u32 size)
|
|||
{
|
||||
sock_t sockfd = INVALID_SOCKET;
|
||||
if (isMaster())
|
||||
sockfd = slaves.empty() ? INVALID_SOCKET : slaves.back();
|
||||
sockfd = slaves.empty() ? INVALID_SOCKET : slaves.back().socket;
|
||||
else
|
||||
sockfd = client_sock;
|
||||
if (sockfd == INVALID_SOCKET)
|
||||
if (!VALID(sockfd))
|
||||
return false;
|
||||
|
||||
ssize_t received = 0;
|
||||
|
@ -394,8 +547,7 @@ bool NaomiNetwork::receive(u8 *data, u32 size)
|
|||
WARN_LOG(NETWORK, "receiveNetwork: read failed. errno=%d", get_last_error());
|
||||
if (isMaster())
|
||||
{
|
||||
slaves.back() = INVALID_SOCKET;
|
||||
closesocket(sockfd);
|
||||
closeSocket(slaves.back().socket);
|
||||
got_token = false;
|
||||
}
|
||||
else
|
||||
|
@ -422,10 +574,10 @@ void NaomiNetwork::send(u8 *data, u32 size)
|
|||
|
||||
sock_t sockfd;
|
||||
if (isMaster())
|
||||
sockfd = slaves.empty() ? INVALID_SOCKET : slaves.front();
|
||||
sockfd = slaves.empty() ? INVALID_SOCKET : slaves.front().socket;
|
||||
else
|
||||
sockfd = client_sock;
|
||||
if (sockfd == INVALID_SOCKET)
|
||||
if (!VALID(sockfd))
|
||||
return;
|
||||
|
||||
if (::send(sockfd, (const char *)data, size, 0) < size)
|
||||
|
@ -434,10 +586,7 @@ void NaomiNetwork::send(u8 *data, u32 size)
|
|||
{
|
||||
WARN_LOG(NETWORK, "send failed. errno=%d", get_last_error());
|
||||
if (isMaster())
|
||||
{
|
||||
slaves.front() = INVALID_SOCKET;
|
||||
closesocket(sockfd);
|
||||
}
|
||||
closeSocket(slaves.front().socket);
|
||||
else
|
||||
shutdown();
|
||||
}
|
||||
|
@ -455,32 +604,29 @@ void NaomiNetwork::shutdown()
|
|||
network_stopping = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (auto& sock : slaves)
|
||||
{
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
if (client_sock != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(client_sock);
|
||||
client_sock = INVALID_SOCKET;
|
||||
for (auto& slave : slaves)
|
||||
closeSocket(slave.socket);
|
||||
}
|
||||
if (VALID(client_sock))
|
||||
closeSocket(client_sock);
|
||||
}
|
||||
|
||||
void NaomiNetwork::terminate()
|
||||
{
|
||||
shutdown();
|
||||
if (beacon_sock != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(beacon_sock);
|
||||
beacon_sock = INVALID_SOCKET;
|
||||
}
|
||||
if (server_sock != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(server_sock);
|
||||
server_sock = INVALID_SOCKET;
|
||||
}
|
||||
if (VALID(beacon_sock))
|
||||
closeSocket(beacon_sock);
|
||||
if (VALID(server_sock))
|
||||
closeSocket(server_sock);
|
||||
}
|
||||
|
||||
std::future<bool> NaomiNetwork::startNetworkAsync()
|
||||
{
|
||||
network_stopping = false;
|
||||
start_now = false;
|
||||
return std::async(std::launch::async, [this] {
|
||||
return startNetwork();
|
||||
});
|
||||
}
|
||||
|
||||
// Sets the game network config using MIE eeprom or bbsram:
|
||||
|
@ -549,3 +695,19 @@ void SetNaomiNetworkConfig(int node)
|
|||
write_naomi_flash(0x220, node == 0 ? 0 : 1); // node id
|
||||
}
|
||||
}
|
||||
|
||||
bool NaomiNetworkSupported()
|
||||
{
|
||||
static const std::array<const char *, 12> games = {
|
||||
"ALIEN FRONT", "MOBILE SUIT GUNDAM JAPAN", "MOBILE SUIT GUNDAM DELUXE JAPAN", " BIOHAZARD GUN SURVIVOR2",
|
||||
"HEAVY METAL JAPAN", "OUTTRIGGER JAPAN", "SLASHOUT JAPAN VERSION", "SPAWN JAPAN",
|
||||
"SPIKERS BATTLE JAPAN VERSION", "VIRTUAL-ON ORATORIO TANGRAM", "WAVE RUNNER GP", "WORLD KICKS"
|
||||
};
|
||||
if (!settings.network.Enable)
|
||||
return false;
|
||||
for (auto game : games)
|
||||
if (!strcmp(game, naomi_game_id))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "types.h"
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "net_platform.h"
|
||||
|
@ -37,8 +38,9 @@ public:
|
|||
#endif
|
||||
}
|
||||
~NaomiNetwork() { terminate(); }
|
||||
bool init();
|
||||
bool startNetwork();
|
||||
std::future<bool> startNetworkAsync();
|
||||
void startNow() { start_now = true; }
|
||||
bool syncNetwork();
|
||||
void pipeSlaves();
|
||||
bool receive(u8 *data, u32 size);
|
||||
void send(u8 *data, u32 size);
|
||||
|
@ -49,19 +51,32 @@ public:
|
|||
bool hasToken() const { return got_token; }
|
||||
|
||||
private:
|
||||
bool init();
|
||||
bool createServerSocket();
|
||||
bool createBeaconSocket();
|
||||
bool startNetwork();
|
||||
void processBeacon();
|
||||
bool findServer();
|
||||
sock_t createAndBind(int protocol);
|
||||
bool isMaster() const { return slot_id == 0; }
|
||||
void closeSocket(sock_t& socket) const { closesocket(socket); socket = INVALID_SOCKET; }
|
||||
|
||||
struct in_addr server_ip;
|
||||
std::string server_name;
|
||||
// server stuff
|
||||
sock_t server_sock = INVALID_SOCKET;
|
||||
sock_t beacon_sock = INVALID_SOCKET;
|
||||
std::vector<sock_t> slaves;
|
||||
enum class ClientState { Connected, Waiting, Starting, Ready, Online };
|
||||
struct Slave {
|
||||
Slave(sock_t socket)
|
||||
: state(ClientState::Connected), state_time(std::chrono::steady_clock::now()), socket(socket) {}
|
||||
void set_state(ClientState state) { this->state = state; this->state_time = std::chrono::steady_clock::now(); }
|
||||
ClientState state;
|
||||
std::chrono::steady_clock::time_point state_time;
|
||||
sock_t socket;
|
||||
};
|
||||
std::vector<Slave> slaves;
|
||||
bool start_now = false;
|
||||
// client stuff
|
||||
sock_t client_sock = INVALID_SOCKET;
|
||||
// common stuff
|
||||
|
@ -73,5 +88,7 @@ private:
|
|||
|
||||
static const uint16_t SERVER_PORT = 37391;
|
||||
};
|
||||
extern NaomiNetwork naomiNetwork;
|
||||
|
||||
void SetNaomiNetworkConfig(int node);
|
||||
bool NaomiNetworkSupported();
|
||||
|
|
|
@ -638,8 +638,7 @@ static void dc_start_game(const char *path)
|
|||
if (settings.platform.system == DC_PLATFORM_NAOMI)
|
||||
{
|
||||
mcfg_CreateNAOMIJamma();
|
||||
SetNaomiNetworkConfig(settings.network.Enable ? settings.network.ActAsServer ? 0 : 1 // FIXME more than 2 nodes
|
||||
: -1);
|
||||
SetNaomiNetworkConfig(-1);
|
||||
}
|
||||
else if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
mcfg_CreateAtomisWaveControllers();
|
||||
|
@ -1096,8 +1095,6 @@ static void cleanup_serialize(void *data)
|
|||
{
|
||||
if ( data != NULL )
|
||||
free(data) ;
|
||||
|
||||
dc_resume();
|
||||
}
|
||||
|
||||
static std::string get_savestate_file_path()
|
||||
|
@ -1275,6 +1272,7 @@ void dc_cancel_load()
|
|||
loading_canceled = true;
|
||||
loading_done.get();
|
||||
}
|
||||
settings.imgread.ImagePath[0] = '\0';
|
||||
}
|
||||
|
||||
void dc_get_load_status()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mutex>
|
||||
#include "gui.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "hw/maple/maple_if.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include "imgread/common.h"
|
||||
#include "log/LogManager.h"
|
||||
#include "emulator.h"
|
||||
#include "network/naomi_network.h"
|
||||
|
||||
extern void UpdateInputState(u32 port);
|
||||
extern bool game_started;
|
||||
|
@ -56,6 +58,7 @@ static bool touch_up;
|
|||
static std::string error_msg;
|
||||
static std::string osd_message;
|
||||
static double osd_message_end;
|
||||
static std::mutex osd_message_mutex;
|
||||
|
||||
static void display_vmus();
|
||||
static void reset_vmus();
|
||||
|
@ -207,7 +210,6 @@ void ImGui_Impl_NewFrame()
|
|||
io.NavInputs[ImGuiNavInput_Activate] = (kcode[0] & DC_BTN_A) == 0;
|
||||
io.NavInputs[ImGuiNavInput_Cancel] = (kcode[0] & DC_BTN_B) == 0;
|
||||
io.NavInputs[ImGuiNavInput_Input] = (kcode[0] & DC_BTN_X) == 0;
|
||||
//io.NavInputs[ImGuiNavInput_Menu] = (kcode[0] & DC_BTN_Y) == 0;
|
||||
io.NavInputs[ImGuiNavInput_DpadLeft] = (kcode[0] & DC_DPAD_LEFT) == 0;
|
||||
io.NavInputs[ImGuiNavInput_DpadRight] = (kcode[0] & DC_DPAD_RIGHT) == 0;
|
||||
io.NavInputs[ImGuiNavInput_DpadUp] = (kcode[0] & DC_DPAD_UP) == 0;
|
||||
|
@ -282,6 +284,16 @@ void gui_open_settings()
|
|||
{
|
||||
gui_state = VJoyEditCommands;
|
||||
}
|
||||
else if (gui_state == Loading)
|
||||
{
|
||||
dc_cancel_load();
|
||||
gui_state = Main;
|
||||
}
|
||||
else if (gui_state == Commands)
|
||||
{
|
||||
gui_state = Closed;
|
||||
dc_resume();
|
||||
}
|
||||
}
|
||||
|
||||
static void gui_start_game(const std::string& path)
|
||||
|
@ -1447,6 +1459,20 @@ static void gui_display_settings()
|
|||
settings.dynarec.Enable = (bool)dynarec_enabled;
|
||||
}
|
||||
|
||||
void gui_display_notification(const char *msg, int duration)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(osd_message_mutex);
|
||||
osd_message = msg;
|
||||
osd_message_end = os_GetSeconds() + (double)duration / 1000.0;
|
||||
}
|
||||
|
||||
static std::string get_notification()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(osd_message_mutex);
|
||||
if (!osd_message.empty() && os_GetSeconds() >= osd_message_end)
|
||||
osd_message.clear();
|
||||
return osd_message;
|
||||
}
|
||||
|
||||
static void gui_display_demo()
|
||||
{
|
||||
|
@ -1498,7 +1524,6 @@ static void gui_display_content()
|
|||
if (ImGui::Selectable("Dreamcast BIOS"))
|
||||
{
|
||||
gui_state = Closed;
|
||||
settings.imgread.ImagePath[0] = '\0';
|
||||
gui_start_game("");
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
@ -1551,7 +1576,7 @@ static void gui_display_content()
|
|||
ImGui_impl_RenderDrawData(ImGui::GetDrawData(), false);
|
||||
}
|
||||
|
||||
void systemdir_selected_callback(bool cancelled, std::string selection)
|
||||
static void systemdir_selected_callback(bool cancelled, std::string selection)
|
||||
{
|
||||
if (!cancelled)
|
||||
{
|
||||
|
@ -1570,7 +1595,7 @@ void systemdir_selected_callback(bool cancelled, std::string selection)
|
|||
}
|
||||
}
|
||||
|
||||
void gui_display_onboarding()
|
||||
static void gui_display_onboarding()
|
||||
{
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
@ -1582,7 +1607,71 @@ void gui_display_onboarding()
|
|||
ImGui_impl_RenderDrawData(ImGui::GetDrawData(), false);
|
||||
}
|
||||
|
||||
void gui_display_loadscreen()
|
||||
static std::future<bool> networkStatus;
|
||||
|
||||
static void start_network()
|
||||
{
|
||||
networkStatus = naomiNetwork.startNetworkAsync();
|
||||
gui_state = NetworkStart;
|
||||
}
|
||||
|
||||
static void gui_network_start()
|
||||
{
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(screen_width / 2, screen_height / 2), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(330 * scaling, 180 * scaling));
|
||||
|
||||
ImGui::Begin("##network", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20 * scaling, 10 * scaling));
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::SetCursorPosX(20.f * scaling);
|
||||
|
||||
if (networkStatus.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready)
|
||||
{
|
||||
if (networkStatus.get())
|
||||
{
|
||||
gui_state = Closed;
|
||||
ImGui::Text("STARTING...");
|
||||
}
|
||||
else
|
||||
{
|
||||
gui_state = Main;
|
||||
settings.imgread.ImagePath[0] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("STARTING NETWORK...");
|
||||
if (settings.network.ActAsServer)
|
||||
ImGui::Text("Press Start to start the game now.");
|
||||
}
|
||||
ImGui::Text("%s", get_notification().c_str());
|
||||
|
||||
float currentwidth = ImGui::GetContentRegionAvailWidth();
|
||||
ImGui::SetCursorPosX((currentwidth - 100.f * scaling) / 2.f + ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::SetCursorPosY(126.f * scaling);
|
||||
if (ImGui::Button("Cancel", ImVec2(100.f * scaling, 0.f)))
|
||||
{
|
||||
naomiNetwork.terminate();
|
||||
networkStatus.get();
|
||||
gui_state = Main;
|
||||
settings.imgread.ImagePath[0] = '\0';
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_impl_RenderDrawData(ImGui::GetDrawData(), false);
|
||||
|
||||
if ((kcode[0] & DC_BTN_START) == 0)
|
||||
naomiNetwork.startNow();
|
||||
}
|
||||
|
||||
static void gui_display_loadscreen()
|
||||
{
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
@ -1599,9 +1688,16 @@ void gui_display_loadscreen()
|
|||
{
|
||||
try {
|
||||
dc_get_load_status();
|
||||
gui_state = Closed;
|
||||
ImGui::Text("STARTING...");
|
||||
} catch (ReicastException& ex) {
|
||||
if (NaomiNetworkSupported())
|
||||
{
|
||||
start_network();
|
||||
}
|
||||
else
|
||||
{
|
||||
gui_state = Closed;
|
||||
ImGui::Text("STARTING...");
|
||||
}
|
||||
} catch (const ReicastException& ex) {
|
||||
ERROR_LOG(BOOT, "%s", ex.reason.c_str());
|
||||
error_msg = ex.reason;
|
||||
#ifdef TEST_AUTOMATION
|
||||
|
@ -1614,17 +1710,9 @@ void gui_display_loadscreen()
|
|||
else
|
||||
{
|
||||
ImGui::Text("LOADING... ");
|
||||
double now = os_GetSeconds();
|
||||
if (!osd_message.empty())
|
||||
{
|
||||
if (now >= osd_message_end)
|
||||
osd_message.clear();
|
||||
else
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", osd_message.c_str());
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", get_notification().c_str());
|
||||
|
||||
float currentwidth = ImGui::GetContentRegionAvailWidth();
|
||||
ImGui::SetCursorPosX((currentwidth - 100.f * scaling) / 2.f + ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::SetCursorPosY(126.f * scaling);
|
||||
|
@ -1632,7 +1720,6 @@ void gui_display_loadscreen()
|
|||
{
|
||||
dc_cancel_load();
|
||||
gui_state = Main;
|
||||
settings.imgread.ImagePath[0] = '\0';
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
@ -1681,6 +1768,12 @@ void gui_display_ui()
|
|||
case Loading:
|
||||
gui_display_loadscreen();
|
||||
break;
|
||||
case NetworkStart:
|
||||
gui_network_start();
|
||||
break;
|
||||
default:
|
||||
die("Unknown UI state");
|
||||
break;
|
||||
}
|
||||
|
||||
if (gui_state == Closed)
|
||||
|
@ -1693,12 +1786,6 @@ static float fps = -1;
|
|||
|
||||
extern bool fast_forward_mode;
|
||||
|
||||
void gui_display_notification(const char *msg, int duration)
|
||||
{
|
||||
osd_message = msg;
|
||||
osd_message_end = os_GetSeconds() + (double)duration / 1000.0;
|
||||
}
|
||||
|
||||
static std::string getFPSNotification()
|
||||
{
|
||||
if (settings.rend.ShowFPS)
|
||||
|
@ -1723,19 +1810,9 @@ void gui_display_osd()
|
|||
{
|
||||
if (gui_state == VJoyEdit)
|
||||
return;
|
||||
double now = os_GetSeconds();
|
||||
if (!osd_message.empty())
|
||||
{
|
||||
if (now >= osd_message_end)
|
||||
osd_message.clear();
|
||||
}
|
||||
std::string message;
|
||||
if (osd_message.empty())
|
||||
{
|
||||
std::string message = get_notification();
|
||||
if (message.empty())
|
||||
message = getFPSNotification();
|
||||
}
|
||||
else
|
||||
message = osd_message;
|
||||
|
||||
if (!message.empty() || settings.rend.FloatVMUs)
|
||||
{
|
||||
|
|
|
@ -33,7 +33,18 @@ extern u32 vmu_lcd_data[8][48 * 32];
|
|||
extern bool vmu_lcd_status[8];
|
||||
extern bool vmu_lcd_changed[8];
|
||||
|
||||
typedef enum { Closed, Commands, Settings, Main, Onboarding, VJoyEdit, VJoyEditCommands, SelectDisk, Loading } GuiState;
|
||||
typedef enum {
|
||||
Closed,
|
||||
Commands,
|
||||
Settings,
|
||||
Main,
|
||||
Onboarding,
|
||||
VJoyEdit,
|
||||
VJoyEditCommands,
|
||||
SelectDisk,
|
||||
Loading,
|
||||
NetworkStart
|
||||
} GuiState;
|
||||
extern GuiState gui_state;
|
||||
void ImGui_Impl_NewFrame();
|
||||
|
||||
|
|
|
@ -24,11 +24,8 @@
|
|||
#include "types.h"
|
||||
#include "stdclass.h"
|
||||
#include "imgui/imgui.h"
|
||||
//#include "gles/imgui_impl_opengl3.h"
|
||||
#include "gui_util.h"
|
||||
|
||||
extern bool settings_opening;
|
||||
|
||||
void vjoy_reset_editing();
|
||||
void vjoy_stop_editing(bool canceled);
|
||||
|
||||
|
|
Loading…
Reference in New Issue