internal void incenter_handle_interface_msg(Incenter_State* ins, Data msg); void incenter_interface_connection_cleanup(Incenter_State* ins) { if (ins->interface_socket.value == 0) return; if (!os_socket_close(ins->interface_socket)) { printf("Error closing interface connection socket\n"); } ins->interface_socket = (Socket_Handle){0}; printf("Incenter Interface Socket Connection Closed.\n"); } Thread_Result incenter_interface_connection_thread_proc(u8* user_data) { Incenter_State* ins = (Incenter_State*)user_data; // Open Socket Connection To Server ins->interface_socket = os_socket_create( AF_INET, // IPv4 SOCK_DGRAM, 0 ); // Bind the socket to the correct address if (!os_socket_bind(ins->interface_socket, 1337)) { printf("ERROR: Unable to bind incenter interface socket\n"); return (Thread_Result){ 0 }; } // Message Recv Loop while (ins->running) { u32 next_msg_i = ins->interface_messages_write_next; Data* next_msg = ins->interface_messages + next_msg_i; next_msg->size = INTERFACE_MESSAGE_SIZE; // reset buffer of known size Socket_Error err = SocketError_NOERROR; *next_msg = os_socket_recvfrom(ins->interface_socket, next_msg->base, next_msg->size, &err); if (err == SocketError_EBADF && ins->running) { if (!os_socket_close(ins->interface_socket)) { printf("Trying to close interface socket before reopening. Socket was already closed.\n"); } ins->interface_socket = os_socket_create(AF_INET, SOCK_DGRAM, 0); } if (err == SocketError_EINTR) { printf("Recvfrom returned EINTR, trying again\n"); continue; // retry the same operation, as it was interrupted } if (err == SocketError_NOERROR) { next_msg->base[next_msg->size] = 0; // write_next isn't incremented until here because the message // is not ready to be read until this point ins->interface_messages_write_next = (ins->interface_messages_write_next + 1) % INTERFACE_MESSAGES_CAP; } else { char* errstr = (char*)"Invalid"; if (err > SocketError_Invalid && err < SocketError_Count) { errstr = socket_error_strings[err]; } // TODO: if you hit an EFAULT, go check how big the buffer // recvfrom was trying to write into printf("Socket Error: %s - code: %d\n", errstr, (s32)err); } } // Close Down once Incenter indicates it's time to stop running incenter_interface_connection_cleanup(ins); return (Thread_Result){ 0 }; } internal void incenter_interface_connection_init(App_State* state, Incenter_State* ins) { // Start Thread to handle blocking socket calls ins->interface_thread = os_thread_begin(incenter_interface_connection_thread_proc, (u8*)ins); for (u32 msg_i = 0; msg_i < INTERFACE_MESSAGES_CAP; msg_i++) { ins->interface_messages[msg_i] = (Data){ .base = allocator_alloc(permanent, INTERFACE_MESSAGE_SIZE), .size = INTERFACE_MESSAGE_SIZE, }; } } internal void incenter_interface_connection_frame(App_State* state, Incenter_State* ins) { while (ins->interface_messages_write_next != ins->interface_messages_read_next) { u32 read_next = ins->interface_messages_read_next; ins->interface_messages_read_next = (read_next + 1) % INTERFACE_MESSAGES_CAP; Data msg_read = ins->interface_messages[read_next]; printf("Handling message on the main thread\n"); printf(" %s\n", (char*)msg_read.base); incenter_handle_interface_msg(ins, msg_read); } } #define INCENTER_CMP3(base, str) ((base[0] == str[0]) && (base[1] == str[1]) && (base[2] == str[2])) internal void incenter_handle_sliding_scale_msg(Incenter_State* ins, Incenter_Scene scene, char msg) { assert(scene.kind == Incenter_SceneKind_SlidingScale); if (msg != 'M' && msg != 'L' && msg != 'C') { printf("Invalid input sent to sliding scale scene: %c\n", msg); printf(" Scene: %s\n", scene.name); return; } switch (msg) { case 'M': { ins->input_pct += 0.1f; } break; case 'L': { ins->input_pct -= 0.1f; } break; case 'C': { live_answers_input_r32(ins, scene, ins->input_pct); } break; } ins->scene_mode = Incenter_SceneMode_Passive; ins->scene_time = 0; ins->input_pct = clamp(0, ins->input_pct, 1); } internal void incenter_handle_yes_no_msg(Incenter_State* ins, Incenter_Scene scene, char msg) { assert(scene.kind == Incenter_SceneKind_YesOrNo); if (msg != 'Y' && msg != 'N') { printf("Invalid input sent to yes no scene: %c\n", msg); printf(" Scene: %s\n", scene.name); return; } switch (msg) { case 'Y': { ins->input_option = 1; } break; case 'N': { ins->input_option = 0; } break; } live_answers_input_u32(ins, scene, ins->input_option); ins->scene_mode = Incenter_SceneMode_Passive; ins->scene_time = 0; } internal void incenter_handle_three_option_msg(Incenter_State* ins, Incenter_Scene scene, char msg) { assert(scene.kind == Incenter_SceneKind_ThreeOption); if (msg != '1' && msg != '2' && msg != '3') { printf("Invalid input sent to 3 option scene: %c\n", msg); printf(" Scene: %s\n", scene.name); return; } ins->input_option = (msg - '0') - 1; live_answers_input_u32(ins, scene, ins->input_option); ins->scene_mode = Incenter_SceneMode_Passive; ins->scene_time = 0; } internal void incenter_handle_interface_msg(Incenter_State* ins, Data msg) { u32 msg_kind = Incenter_InterfaceMessage_Invalid; u32 scene_id = 0; if (INCENTER_CMP3(msg.base, "UIN")) { msg_kind = Incenter_InterfaceMessage_UserInput; } else if (INCENTER_CMP3(msg.base, "GTS")){ msg_kind = Incenter_InterfaceMessage_GoToScene; char* scene_id_start = (char*)(msg.base + 3); scene_id = scene_id_start[0] - '0'; if (scene_id_start[1] != 0) { scene_id *= 10; scene_id += scene_id_start[1] - '0'; } } switch (msg_kind) { case Incenter_InterfaceMessage_GoToScene: { if (scene_id > Incenter_Scene_Invalid && scene_id < Incenter_Scene_Count) { if (scene_id != ins->scene_at) { incenter_scene_go_to(ins, scene_id); } } else { printf("Unknown Scene ID Requested: %d\n", scene_id); } } break; case Incenter_InterfaceMessage_UserInput: { Incenter_Scene scene = ins->scenes[ins->scene_at]; char input_kind = msg.base[3]; switch (scene.kind) { case Incenter_SceneKind_SlidingScale: { incenter_handle_sliding_scale_msg(ins, scene, input_kind); } break; case Incenter_SceneKind_YesOrNo: { incenter_handle_yes_no_msg(ins, scene, input_kind); } break; case Incenter_SceneKind_ThreeOption: { incenter_handle_three_option_msg(ins, scene, input_kind); } break; } } break; default: { printf("Unknown message kind: %d\n", msg_kind); // TODO: Print the actual message received } break; } }