basic disconnect recovery automatically

This commit is contained in:
Tenari
2026-03-23 07:50:41 -05:00
parent 9f8d83e1e2
commit f7403581ae
3 changed files with 75 additions and 34 deletions
+56 -32
View File
@@ -336,6 +336,7 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
case MessagePayoffResult: case MessagePayoffResult:
case MessageTurnTick: case MessageTurnTick:
case MessageNewAccountCreated: case MessageNewAccountCreated:
case MessageNotAlive:
case MessageBadPw: {/*nothing to parse but the type*/} break; case MessageBadPw: {/*nothing to parse but the type*/} break;
case MessageGameOver: { case MessageGameOver: {
parsed.byte = message[msg_pos++]; parsed.byte = message[msg_pos++];
@@ -502,6 +503,26 @@ fn Box defaultModal(TuiState* tui) {
return modal_outline; return modal_outline;
} }
fn void sendLoginCommand(SocketAddress addr, u16 client_port) {
u32 msg_idx = 0;
// drop the login message into the network_send_queue
UDPMessage msg = { .address = addr };
// 1. msg type/CommandType
msg.bytes[msg_idx++] = CommandLogin;
// 2. our LAN-IP to handle the case where we are on the same LAN as the guy we are trying to fight
// and our "listened" UDP port
msg_idx += writeU16ToBufferLE(msg.bytes + msg_idx, ~client_port);
msg_idx += writeI32ToBufferLE(msg.bytes + msg_idx, ~osLanIPAddress());
// 2. how long is the name
msg.bytes[msg_idx++] = state.login_state.name.length;
// 3. the name
memcpy(msg.bytes + msg_idx, state.login_state.name.bytes, state.login_state.name.length);
// 4. the password
memcpy(msg.bytes + msg_idx + state.login_state.name.length, state.login_state.password.bytes, state.login_state.password.length);
msg.bytes_len = msg_idx + state.login_state.name.length + state.login_state.password.length;
outgoingMessageQueuePush(network_send_queue, &msg);
}
fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count) { fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count) {
GameState* state = (GameState*) s; GameState* state = (GameState*) s;
state->loop_count = loop_count; state->loop_count = loop_count;
@@ -524,6 +545,15 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
while (next_net_msg != NULL) { while (next_net_msg != NULL) {
msg_iters += 0; msg_iters += 0;
switch (msg.type) { switch (msg.type) {
case MessageNotAlive: {
// auto-re-login
if (state->me.base_cost > 0) {
addSystemMessage((u8*)"auto re logging in due to MessageNotAlive");
sendLoginCommand(udp->server_address, udp->client_port);
state->screen = ScreenLogin;
state->login_state.state = LoginScreenStateLoading;
}
} break;
case MessageSystemPassengers: { case MessageSystemPassengers: {
// put the stuff from msg into the correct state.map[i] // put the stuff from msg into the correct state.map[i]
MemoryCopy(&state->map[msg.byte].offers, &msg.offers, sizeof(PassengerJobOffer) * MAX_PASSENGER_JOB_OFFERS); MemoryCopy(&state->map[msg.byte].offers, &msg.offers, sizeof(PassengerJobOffer) * MAX_PASSENGER_JOB_OFFERS);
@@ -846,17 +876,8 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
} }
Tab tab = state->menu.selected_index; Tab tab = state->menu.selected_index;
// per-tab simulation+rendering
u32 tabs_y = 1;
u32 tx = 2;
for (u32 i = 0; i < Tab_Count; i++) {
u32 tab_len = strlen(TAB_STRS[i]);
Box b = { .x = tx, .y = tabs_y, .width = tab_len+1, .height = 1 };
drawAnsiBox(tui->frame_buffer, b, screen_dimensions, state->menu.selected_index == i);
renderStrToBuffer(tui->frame_buffer, tx+1, tabs_y+ 1, TAB_STRS[i], screen_dimensions);
tx += (tab_len + 3);
}
// draw the tabs box // draw the tabs box
u32 tabs_y = 0;
u32 box_y = tabs_y + 3; u32 box_y = tabs_y + 3;
Box box = { Box box = {
.x = 1, .x = 1,
@@ -865,6 +886,15 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
.height = screen_dimensions.height - box_y - 2, .height = screen_dimensions.height - box_y - 2,
}; };
drawAnsiBox(tui->frame_buffer, box, screen_dimensions, true); drawAnsiBox(tui->frame_buffer, box, screen_dimensions, true);
u32 tx = 2;
// draw the actual tabs
for (u32 i = 0; i < Tab_Count; i++) {
u32 tab_len = strlen(TAB_STRS[i]);
Box b = { .x = tx, .y = tabs_y, .width = tab_len+1, .height = 1 };
drawAnsiBox(tui->frame_buffer, b, screen_dimensions, state->menu.selected_index == i);
renderStrToBuffer(tui->frame_buffer, tx+1, tabs_y+ 1, TAB_STRS[i], screen_dimensions);
tx += (tab_len + 3);
}
StarSystem curr = state->map[state->me.system_idx]; StarSystem curr = state->map[state->me.system_idx];
switch (tab) { switch (tab) {
case TabDebug: { case TabDebug: {
@@ -1137,9 +1167,20 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
} }
for (u32 i = 0; i < Commodity_Count; i++) { for (u32 i = 0; i < Commodity_Count; i++) {
if (i == CommodityOxygen || i == CommodityHydrogenFuel || state->me.commodities[i] > 0) { bool is_o2_or_fuel = i == CommodityOxygen || i == CommodityHydrogenFuel;
if (is_o2_or_fuel || state->me.commodities[i] > 0) {
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "%-18s %d", COMMODITIES[i].name, state->me.commodities[i]); if (is_o2_or_fuel) {
sprintf(
sbuf,
"%-18s %d / %dkg",
COMMODITIES[i].name,
state->me.commodities[i],
i == CommodityHydrogenFuel ? state->me.cu_m_fuel : state->me.cu_m_o2
);
} else {
sprintf(sbuf, "%-18s %d", COMMODITIES[i].name, state->me.commodities[i]);
}
renderStrToBuffer(tui->frame_buffer, box.x+4, (++yoff)+3, sbuf, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+4, (++yoff)+3, sbuf, screen_dimensions);
} }
} }
@@ -1602,28 +1643,11 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
state->login_state.selected_field = 1; state->login_state.selected_field = 1;
state->login_state.field_index = 0; state->login_state.field_index = 0;
} else { } else {
u32 msg_idx = 0; sendLoginCommand(udp->server_address, udp->client_port);
// drop the login message into the network_send_queue
UDPMessage msg = {0};
msg.address = udp->server_address;
// 1. msg type/CommandType
msg.bytes[msg_idx++] = CommandLogin;
// 2. our LAN-IP to handle the case where we are on the same LAN as the guy we are trying to fight
// and our "listened" UDP port
msg_idx += writeU16ToBufferLE(msg.bytes + msg_idx, ~(udp->client_port));
msg_idx += writeI32ToBufferLE(msg.bytes + msg_idx, ~osLanIPAddress());
// 2. how long is the name
msg.bytes[msg_idx++] = state->login_state.name.length;
// 3. the name
memcpy(msg.bytes + msg_idx, state->login_state.name.bytes, state->login_state.name.length);
// 4. the password
memcpy(msg.bytes + msg_idx + state->login_state.name.length, state->login_state.password.bytes, state->login_state.password.length);
msg.bytes_len = msg_idx + state->login_state.name.length + state->login_state.password.length;
addSystemMessage((u8*)state->login_state.name.bytes);
addSystemMessage((u8*)state->login_state.password.bytes);
outgoingMessageQueuePush(network_send_queue, &msg);
// show loading signal, stop accepting input // show loading signal, stop accepting input
state->login_state.state = LoginScreenStateLoading; state->login_state.state = LoginScreenStateLoading;
addSystemMessage((u8*)state->login_state.name.bytes);
addSystemMessage((u8*)state->login_state.password.bytes);
} }
} }
+17 -2
View File
@@ -670,6 +670,7 @@ fn void* gameLoop(void* params) {
Client* client = &state.clients.items[client_handle]; Client* client = &state.clients.items[client_handle];
switch (msg.type) { switch (msg.type) {
case CommandAcceptPassengerJob: { case CommandAcceptPassengerJob: {
if (client_handle == 0) break;
// move the offer out of the system and INTO the PlayerShip // move the offer out of the system and INTO the PlayerShip
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
StarSystem* player_sys = &state.map[account->ship.system_idx]; StarSystem* player_sys = &state.map[account->ship.system_idx];
@@ -710,6 +711,7 @@ fn void* gameLoop(void* params) {
} }
} break; } break;
case CommandPayMortgage: { case CommandPayMortgage: {
if (client_handle == 0) break;
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
u32 amount_to_pay = msg.id; u32 amount_to_pay = msg.id;
if (amount_to_pay > account->ship.credits) { if (amount_to_pay > account->ship.credits) {
@@ -724,10 +726,12 @@ fn void* gameLoop(void* params) {
sendMessagePayoffResult(sender); sendMessagePayoffResult(sender);
} break; } break;
case CommandSetDestination: { case CommandSetDestination: {
if (client_handle == 0) break;
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
account->destination_sys_idx = msg.byte; account->destination_sys_idx = msg.byte;
} break; } break;
case CommandReadyStatus: { case CommandReadyStatus: {
if (client_handle == 0) break;
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
account->ship.ready_to_depart = msg.byte; account->ship.ready_to_depart = msg.byte;
sendMessagePlayerDetails(account->ship, sender); sendMessagePlayerDetails(account->ship, sender);
@@ -741,6 +745,7 @@ fn void* gameLoop(void* params) {
} }
} break; } break;
case CommandTransact: { case CommandTransact: {
if (client_handle == 0) break;
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Transact for client_handle=%d, on #%lld", client_handle, state.frame); sprintf(sbuf, "Transact for client_handle=%d, on #%lld", client_handle, state.frame);
addSystemMessage((u8*)sbuf); addSystemMessage((u8*)sbuf);
@@ -797,8 +802,17 @@ fn void* gameLoop(void* params) {
sendMessageTransactionResult(sender, qty_traded, is_buying_from_system, credit_value); sendMessageTransactionResult(sender, qty_traded, is_buying_from_system, credit_value);
} break; } break;
case CommandKeepAlive: { case CommandKeepAlive: {
dbg("KeepAlive for client_handle=%d, %ld", client_handle, state.frame); //MemoryZero(sbuf, SBUFLEN);
state.clients.items[client_handle].last_ping = state.frame; //sprintf(sbuf, "KeepAlive for client_handle=%d on frame %lld", client_handle, state.frame);
//addSystemMessage((u8*)sbuf);
if (client_handle == 0) {
outgoing_message.bytes[0] = (u8)MessageNotAlive;
outgoing_message.bytes_len = 1;
outgoing_message.address = sender;
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
} else {
state.clients.items[client_handle].last_ping = state.frame;
}
} break; } break;
case CommandLogin: { case CommandLogin: {
if (client_handle == 0) { if (client_handle == 0) {
@@ -883,6 +897,7 @@ fn void* gameLoop(void* params) {
addSystemMessage((u8*)sbuf); addSystemMessage((u8*)sbuf);
} break; } break;
case CommandCreateCharacter: { case CommandCreateCharacter: {
if (client_handle == 0) break;
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "creating character for account id=%d, %s\n", account->id, SHIP_TYPE_STRINGS[msg.byte]); sprintf(sbuf, "creating character for account id=%d, %s\n", account->id, SHIP_TYPE_STRINGS[msg.byte]);
+2
View File
@@ -381,6 +381,7 @@ typedef enum Message {
MessageSystemPassengers, MessageSystemPassengers,
MessageJobAcceptResult, MessageJobAcceptResult,
MessageJobComplete, MessageJobComplete,
MessageNotAlive,
Message_Count, Message_Count,
} Message; } Message;
@@ -398,6 +399,7 @@ static const char* MESSAGE_STRINGS[] = {
"PayoffResult", "PayoffResult",
"SystemPassengers", "SystemPassengers",
"JobAcceptResult", "JobAcceptResult",
"MessageNotAlive",
}; };
///// shared helper functions ///// shared helper functions