#include "libsuicmez.h" #include "raylib.h" #include "rlgl.h" #include "suicmez_gc.h" #include #include #include #define MAX_TRACKED_ALLOCATIONS 10000 typedef struct { void *ptr; size_t size; int in_use; } AllocationInfo; static AllocationInfo tracked_allocations[MAX_TRACKED_ALLOCATIONS]; static int allocation_count = 0; static const char *last_error = NULL; // FPS meter state static bool fps_meter_visible = false; static int fps_meter_x = 0; static int fps_meter_y = 0; // Simple linear search to find allocation static int find_allocation(void *ptr) { for (int i = 0; i < allocation_count; i++) { if (tracked_allocations[i].ptr == ptr && tracked_allocations[i].in_use) { return i; } } return -1; } // GC-aware allocator void *gc_suic_alloc(size_t size) { if (size == 0) { return NULL; } // Use the real GC allocator (for now without type info) void *ptr = gc_alloc(NULL, size); if (!ptr) { last_error = "GC allocation failed"; return NULL; } return ptr; } // Free memory (called by gc_suic_free) // With GC, we don't actually free - just mark as no longer needed void suic_gc_free(void *ptr) { // GC will handle freeing when appropriate // For now, do nothing (void)ptr; } // Error handling const char *suic_last_error(void) { return last_error ? last_error : "No error"; } void suic_clear_error(void) { last_error = NULL; } // Logging static suic_log_level current_log_level = SUIC_LOG_ALL; void suic_set_log_level(suic_log_level level) { current_log_level = level; } // Window management bool suic_init_window(int width, int height, const char *title) { InitWindow(width, height, title); return !WindowShouldClose(); } void suic_close_window(void) { CloseWindow(); } bool suic_window_should_close(void) { return WindowShouldClose(); } void suic_set_target_fps(int fps) { SetTargetFPS(fps); } void suic_enable_msaa_4x(void) { SetConfigFlags(FLAG_MSAA_4X_HINT); } int suic_get_screen_width(void) { return GetScreenWidth(); } int suic_get_screen_height(void) { return GetScreenHeight(); } // Timing float suic_get_frame_time(void) { return GetFrameTime(); } // FPS meter void suic_show_fps_meter(suic_vec2 position) { fps_meter_visible = true; fps_meter_x = (int)position.x; fps_meter_y = (int)position.y; } void suic_hide_fps_meter(void) { fps_meter_visible = false; } // Drawing void suic_begin_drawing(void) { BeginDrawing(); } void suic_end_drawing(void) { // Draw FPS meter if enabled if (fps_meter_visible) { DrawFPS(fps_meter_x, fps_meter_y); } EndDrawing(); } void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { ClearBackground((Color){r, g, b, a}); } // 3D mode Camera3D suic_to_rl_camera3d(suic_camera3d cam) { return (Camera3D){.position = suic_to_rl_vec3(cam.position), .target = suic_to_rl_vec3(cam.target), .up = suic_to_rl_vec3(cam.up), .fovy = cam.fovy, .projection = cam.projection}; } void suic_begin_mode3d(float pos_x, float pos_y, float pos_z, float target_x, float target_y, float target_z, float up_x, float up_y, float up_z, float fovy, int projection) { Camera3D camera = {.position = (Vector3){pos_x, pos_y, pos_z}, .target = (Vector3){target_x, target_y, target_z}, .up = (Vector3){up_x, up_y, up_z}, .fovy = fovy, .projection = projection}; BeginMode3D(camera); } void suic_end_mode3d(void) { EndMode3D(); } // 3D Drawing void suic_draw_cube(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawCube((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); } void suic_draw_cube_wires(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawCubeWires((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); } void suic_draw_sphere(float x, float y, float z, float radius, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawSphere((Vector3){x, y, z}, radius, (Color){r, g, b, a}); } void suic_draw_capsule(float start_x, float start_y, float start_z, float end_x, float end_y, float end_z, float radius, int slices, int rings, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawCapsule((Vector3){start_x, start_y, start_z}, (Vector3){end_x, end_y, end_z}, radius, slices, rings, (Color){r, g, b, a}); } // 2D Drawing (UI Framework Utils) void suic_draw_text(const char *text, int x, int y, int font_size, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawText(text, x, y, font_size, (Color){r, g, b, a}); } void suic_draw_rectangle(int x, int y, int width, int height, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawRectangle(x, y, width, height, (Color){r, g, b, a}); } void suic_draw_rectangle_lines(int x, int y, int width, int height, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawRectangleLines(x, y, width, height, (Color){r, g, b, a}); } int suic_measure_text(const char *text, int font_size) { return MeasureText(text, font_size); } void suic_draw_circle(int center_x, int center_y, float radius, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawCircle(center_x, center_y, radius, (Color){r, g, b, a}); } void suic_draw_line(int start_x, int start_y, int end_x, int end_y, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { DrawLine(start_x, start_y, end_x, end_y, (Color){r, g, b, a}); } void suic_draw_fps(int x, int y) { DrawFPS(x, y); } // Input - Keyboard bool suic_is_key_down(int key) { return IsKeyDown(key); } bool suic_is_key_pressed(int key) { return IsKeyPressed(key); } bool suic_is_key_released(int key) { return IsKeyReleased(key); } // Input - Mouse bool suic_is_mouse_button_down(int b) { return IsMouseButtonDown(b); } bool suic_is_mouse_button_pressed(int b) { return IsMouseButtonPressed(b); } bool suic_is_mouse_button_released(int b) { return IsMouseButtonReleased(b); } suic_vec2 suic_get_mouse_position(void) { Vector2 pos = GetMousePosition(); return (suic_vec2){pos.x, pos.y}; } suic_vec2 suic_get_mouse_delta(void) { Vector2 delta = GetMouseDelta(); return (suic_vec2){delta.x, delta.y}; } float suic_get_mouse_x(void) { return GetMousePosition().x; } float suic_get_mouse_y(void) { return GetMousePosition().y; } float suic_get_mouse_delta_x(void) { return GetMouseDelta().x; } float suic_get_mouse_delta_y(void) { return GetMouseDelta().y; } // Random number generation int suic_get_random_value(int min, int max) { return GetRandomValue(min, max); } // Input - Helper functions for gamedev int suic_is_movement_input(void) { // Returns bitmask: 1=W (forward), 2=A (left), 4=S (backward), 8=D (right) int result = 0; if (IsKeyDown(KEY_W)) result |= 1; if (IsKeyDown(KEY_A)) result |= 2; if (IsKeyDown(KEY_S)) result |= 4; if (IsKeyDown(KEY_D)) result |= 8; return result; } int suic_is_sprint_held(void) { return IsKeyDown(KEY_LEFT_SHIFT) ? 1 : 0; } int suic_is_jump_pressed(void) { return IsKeyPressed(KEY_SPACE) ? 1 : 0; } // ============================================================================ // CURSOR MANAGEMENT // ============================================================================ void suic_disable_cursor(void) { DisableCursor(); } void suic_enable_cursor(void) { EnableCursor(); } bool suic_is_cursor_hidden(void) { return IsCursorHidden(); } // ============================================================================ // MATRIX OPERATIONS FOR 3D TRANSFORMATIONS // ============================================================================ void suic_rl_push_matrix(void) { rlPushMatrix(); } void suic_rl_pop_matrix(void) { rlPopMatrix(); } void suic_rl_translate_f(float x, float y, float z) { rlTranslatef(x, y, z); } void suic_rl_rotate_f(float angle, float x, float y, float z) { rlRotatef(angle, x, y, z); } // Image and Texture suic_image_handle suic_image_load(const char *path) { Image img = LoadImage(path); return (suic_image_handle){img, (img.data != NULL) ? true : false}; } void suic_image_free(suic_image_handle *img) { if (img && img->valid) { UnloadImage(img->value); img->valid = false; } } suic_texture_handle suic_texture_load(const char *path) { Texture2D tex = LoadTexture(path); return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; } suic_texture_handle suic_texture_from_image(suic_image_handle img) { if (!img.valid) { return (suic_texture_handle){0, false}; } Texture2D tex = LoadTextureFromImage(img.value); return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; } void suic_texture_free(suic_texture_handle *tex) { if (tex && tex->valid) { UnloadTexture(tex->value); tex->valid = false; } } void suic_draw_texture(suic_texture_handle tex, int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { if (tex.valid) { DrawTexture(tex.value, x, y, (Color){r, g, b, a}); } } // Audio bool suic_audio_init(void) { InitAudioDevice(); return IsAudioDeviceReady(); } void suic_audio_close(void) { CloseAudioDevice(); } suic_sound_handle suic_sound_load(const char *path) { Sound snd = LoadSound(path); return (suic_sound_handle){snd, (snd.frameCount > 0) ? true : false}; } void suic_sound_play(suic_sound_handle snd) { if (snd.valid) { PlaySound(snd.value); } } void suic_sound_set_volume(suic_sound_handle snd, float volume) { if (snd.valid) { SetSoundVolume(snd.value, volume); } } void suic_sound_free(suic_sound_handle *snd) { if (snd && snd->valid) { UnloadSound(snd->value); snd->valid = false; } } // Raycasting suic_ray suic_get_mouse_ray(suic_vec2 mouse, suic_camera3d cam) { Ray r = GetMouseRay((Vector2){mouse.x, mouse.y}, suic_to_rl_camera3d(cam)); return (suic_ray){ .origin = (suic_vec3){r.position.x, r.position.y, r.position.z}, .direction = (suic_vec3){r.direction.x, r.direction.y, r.direction.z}}; } suic_rayhit suic_raycast_aabb(suic_ray ray, suic_aabb box) { Ray r = (Ray){.position = (Vector3){ray.origin.x, ray.origin.y, ray.origin.z}, .direction = (Vector3){ray.direction.x, ray.direction.y, ray.direction.z}}; BoundingBox bbox = (BoundingBox){.min = (Vector3){box.min.x, box.min.y, box.min.z}, .max = (Vector3){box.max.x, box.max.y, box.max.z}}; RayCollision collision = GetRayCollisionBox(r, bbox); return (suic_rayhit){ .hit = collision.hit, .distance = collision.distance, .point = (suic_vec3){collision.point.x, collision.point.y, collision.point.z}, .normal = (suic_vec3){collision.normal.x, collision.normal.y, collision.normal.z}}; } // ODE Physics Engine Implementation static int ode_initialized = 0; void suic_ode_init(void) { if (!ode_initialized) { dInitODE(); ode_initialized = 1; } } void suic_ode_close(void) { if (ode_initialized) { dCloseODE(); ode_initialized = 0; } } suic_ode_world_id suic_ode_world_create(void) { return dWorldCreate(); } void suic_ode_world_destroy(suic_ode_world_id world) { if (world) { dWorldDestroy(world); } } void suic_ode_world_set_gravity(suic_ode_world_id world, dReal x, dReal y, dReal z) { if (world) { dWorldSetGravity(world, x, y, z); } } void suic_ode_world_step(suic_ode_world_id world, dReal stepsize) { if (world) { dWorldStep(world, stepsize); } } // Body management suic_ode_body_id suic_ode_body_create(suic_ode_world_id world) { return dBodyCreate(world); } void suic_ode_body_destroy(suic_ode_body_id body) { if (body) { dBodyDestroy(body); } } void suic_ode_body_set_position(suic_ode_body_id body, dReal x, dReal y, dReal z) { if (body) { dBodySetPosition(body, x, y, z); } } void suic_ode_body_set_linear_vel(suic_ode_body_id body, dReal x, dReal y, dReal z) { if (body) { dBodySetLinearVel(body, x, y, z); } } void suic_ode_body_get_position(suic_ode_body_id body, float *x, float *y, float *z) { if (body) { const dReal *pos = dBodyGetPosition(body); *x = (float)pos[0]; *y = (float)pos[1]; *z = (float)pos[2]; } } // Mass and geometry void suic_ode_body_set_box_mass(suic_ode_body_id body, dReal density, dReal lx, dReal ly, dReal lz) { if (body) { dMass mass; dMassSetBox(&mass, density, lx, ly, lz); dBodySetMass(body, &mass); } } suic_ode_geom_id suic_ode_create_box_geom(suic_ode_space_id space, dReal lx, dReal ly, dReal lz) { return dCreateBox(space, lx, ly, lz); } suic_ode_geom_id suic_ode_create_plane_geom(suic_ode_space_id space, dReal a, dReal b, dReal c, dReal d) { return dCreatePlane(space, a, b, c, d); } void suic_ode_geom_set_body(suic_ode_geom_id geom, suic_ode_body_id body) { if (geom) { dGeomSetBody(geom, body); } } void suic_ode_geom_destroy(suic_ode_geom_id geom) { if (geom) { dGeomDestroy(geom); } } // Collision space suic_ode_space_id suic_ode_simple_space_create(suic_ode_space_id parent) { return dSimpleSpaceCreate(parent); } void suic_ode_space_destroy(suic_ode_space_id space) { if (space) { dSpaceDestroy(space); } } // ============================================================================ // COLLISION DETECTION AND CONTACT JOINTS // ============================================================================ // Global contact configuration static dReal contact_max_force = 10000.0; static dReal contact_erp = 0.8; // Error reduction parameter static dReal contact_cfm = 0.00001; // Constraint force mixing // Store world and contactgroup for collision callback typedef struct { dWorldID world; dJointGroupID contactgroup; } CollisionContext; // Collision callback for detecting contacts between geometries static void near_callback(void *data, dGeomID o1, dGeomID o2) { CollisionContext *ctx = (CollisionContext *)data; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); // Don't process if both bodies are static or same body if ((b1 && b2 && b1 == b2) || (!b1 && !b2)) { return; } const int N = 4; // Max contacts per collision dContact contact[N]; // Check for collisions int n = dCollide(o1, o2, N, &contact[0].geom, sizeof(dContact)); if (n > 0) { for (int i = 0; i < n; i++) { // Set contact properties contact[i].surface.mu = 0.5; // Friction coefficient contact[i].surface.mu2 = 0.5; contact[i].surface.bounce = 0.1; // Bounciness contact[i].surface.bounce_vel = 0.1; contact[i].surface.mode = dContactBounce | dContactSoftERP | dContactSoftCFM; contact[i].surface.soft_erp = contact_erp; contact[i].surface.soft_cfm = contact_cfm; // Create contact joint dJointID c = dJointCreateContact(ctx->world, ctx->contactgroup, &contact[i]); dJointAttach(c, b1, b2); } } } void suic_ode_space_collide(suic_ode_world_id world, suic_ode_space_id space, suic_ode_joint_group_id contactgroup) { if (space && contactgroup && world) { CollisionContext ctx = {.world = world, .contactgroup = contactgroup}; dSpaceCollide(space, (void *)&ctx, &near_callback); } } suic_ode_joint_group_id suic_ode_joint_group_create(int max_size) { return dJointGroupCreate(max_size); } void suic_ode_joint_group_destroy(suic_ode_joint_group_id group) { if (group) { dJointGroupDestroy(group); } } void suic_ode_joint_group_empty(suic_ode_joint_group_id group) { if (group) { dJointGroupEmpty(group); } } void suic_ode_set_contact_max_force(dReal force) { contact_max_force = force; } void suic_ode_set_contact_erp(dReal erp) { contact_erp = erp; } void suic_ode_set_contact_cfm(dReal cfm) { contact_cfm = cfm; } // ============================================================================ // ADDITIONAL BODY FUNCTIONS // ============================================================================ void suic_ode_body_get_linear_vel(suic_ode_body_id body, float *x, float *y, float *z) { if (body) { const dReal *vel = dBodyGetLinearVel(body); *x = (float)vel[0]; *y = (float)vel[1]; *z = (float)vel[2]; } } void suic_ode_body_get_rotation(suic_ode_body_id body, float *q_w, float *q_x, float *q_y, float *q_z) { if (body) { const dReal *q = dBodyGetQuaternion(body); *q_w = (float)q[0]; *q_x = (float)q[1]; *q_y = (float)q[2]; *q_z = (float)q[3]; } } void suic_ode_body_set_rotation(suic_ode_body_id body, dReal q_w, dReal q_x, dReal q_y, dReal q_z) { if (body) { dQuaternion q; q[0] = q_w; q[1] = q_x; q[2] = q_y; q[3] = q_z; dBodySetQuaternion(body, q); } } // ============================================================================ // GAME OBJECT SYSTEM - Unified Physics & Rendering // ============================================================================ suic_game_object *suic_game_object_create_box( suic_ode_world_id world, suic_ode_space_id space, float x, float y, float z, float width, float height, float length, float density, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { suic_game_object *obj = (suic_game_object *)gc_suic_alloc(sizeof(suic_game_object)); if (!obj) return NULL; // Create physics body obj->body = dBodyCreate(world); if (!obj->body) { suic_gc_free(obj); return NULL; } // Set position dBodySetPosition(obj->body, x, y, z); // Create and attach geometry obj->geom = dCreateBox(space, width, height, length); if (!obj->geom) { dBodyDestroy(obj->body); suic_gc_free(obj); return NULL; } dGeomSetBody(obj->geom, obj->body); // Set mass dMass mass; dMassSetBox(&mass, density, width, height, length); dBodySetMass(obj->body, &mass); // Store rendering data obj->width = width; obj->height = height; obj->length = length; obj->r = r; obj->g = g; obj->b = b; obj->a = a; obj->shape_type = 0; // 0 = box return obj; } void suic_game_object_destroy(suic_game_object *obj) { if (obj) { if (obj->geom) { dGeomDestroy(obj->geom); } if (obj->body) { dBodyDestroy(obj->body); } suic_gc_free(obj); } } void suic_game_object_set_position(suic_game_object *obj, float x, float y, float z) { if (obj && obj->body) { dBodySetPosition(obj->body, x, y, z); } } void suic_game_object_get_position(suic_game_object *obj, float *x, float *y, float *z) { if (obj && obj->body) { const dReal *pos = dBodyGetPosition(obj->body); *x = (float)pos[0]; *y = (float)pos[1]; *z = (float)pos[2]; } } void suic_game_object_set_velocity(suic_game_object *obj, float x, float y, float z) { if (obj && obj->body) { dBodySetLinearVel(obj->body, x, y, z); } } void suic_game_object_get_velocity(suic_game_object *obj, float *x, float *y, float *z) { if (obj && obj->body) { const dReal *vel = dBodyGetLinearVel(obj->body); *x = (float)vel[0]; *y = (float)vel[1]; *z = (float)vel[2]; } } void suic_game_object_draw(suic_game_object *obj) { if (obj && obj->body) { float x, y, z; suic_game_object_get_position(obj, &x, &y, &z); if (obj->shape_type == 0) { // Box DrawCube((Vector3){x, y, z}, obj->width, obj->height, obj->length, (Color){obj->r, obj->g, obj->b, obj->a}); // Draw wireframe for visual clarity DrawCubeWires((Vector3){x, y, z}, obj->width, obj->height, obj->length, (Color){0, 0, 0, 200}); } } } // ============================================================================ // PLAYER CONTROLLER - FPS STYLE MOVEMENT // ============================================================================ suic_player_controller *suic_player_controller_create(float x, float y, float z) { suic_player_controller *player = (suic_player_controller *)gc_suic_alloc(sizeof(suic_player_controller)); if (!player) return NULL; player->position = (suic_vec3){x, y, z}; player->velocity = (suic_vec3){0.0, 0.0, 0.0}; player->forward = (suic_vec3){0.0, 0.0, -1.0}; // Looking down -Z player->right = (suic_vec3){1.0, 0.0, 0.0}; // Right is +X player->move_speed = 5.0; // units per second player->sprint_speed = 10.0; // units per second player->jump_force = 10.0; // units per second player->gravity = -9.81; player->is_grounded = 1; return player; } void suic_player_controller_destroy(suic_player_controller *player) { if (player) { suic_gc_free(player); } } void suic_player_controller_update(suic_player_controller *player, float delta_time) { if (!player) return; // Apply gravity player->velocity.y += player->gravity * delta_time; // Update position player->position.x += player->velocity.x * delta_time; player->position.y += player->velocity.y * delta_time; player->position.z += player->velocity.z * delta_time; } void suic_player_controller_set_direction(suic_player_controller *player, float forward_x, float forward_y, float forward_z, float right_x, float right_y, float right_z) { if (!player) return; player->forward = (suic_vec3){forward_x, forward_y, forward_z}; player->right = (suic_vec3){right_x, right_y, right_z}; } void suic_player_controller_move_forward(suic_player_controller *player, float amount) { if (!player) return; float speed = player->move_speed; if (suic_is_sprint_held()) { speed = player->sprint_speed; } player->velocity.x += player->forward.x * speed * amount; player->velocity.z += player->forward.z * speed * amount; } void suic_player_controller_move_right(suic_player_controller *player, float amount) { if (!player) return; float speed = player->move_speed; if (suic_is_sprint_held()) { speed = player->sprint_speed; } player->velocity.x += player->right.x * speed * amount; player->velocity.z += player->right.z * speed * amount; } void suic_player_controller_jump(suic_player_controller *player) { if (!player || !player->is_grounded) return; player->velocity.y = player->jump_force; player->is_grounded = 0; } void suic_player_controller_get_position(suic_player_controller *player, float *x, float *y, float *z) { if (player) { *x = player->position.x; *y = player->position.y; *z = player->position.z; } } void suic_player_controller_set_position(suic_player_controller *player, float x, float y, float z) { if (player) { player->position.x = x; player->position.y = y; player->position.z = z; } } /* ===== FILE I/O IMPLEMENTATION ===== */ FileHandle suic_file_open(const char* path, FileMode mode) { const char* mode_str; switch (mode) { case FILE_READ: mode_str = "rb"; break; case FILE_WRITE: mode_str = "wb"; break; case FILE_APPEND: mode_str = "ab"; break; default: return NULL; } FILE* f = fopen(path, mode_str); return (FileHandle)f; } void suic_file_close(FileHandle handle) { if (handle) { fclose((FILE*)handle); } } int suic_file_read(FileHandle handle, void* buffer, int size) { if (!handle) return -1; return (int)fread(buffer, 1, size, (FILE*)handle); } int suic_file_write(FileHandle handle, const void* buffer, int size) { if (!handle) return -1; return (int)fwrite(buffer, 1, size, (FILE*)handle); } int suic_file_size(FileHandle handle) { if (!handle) return -1; FILE* f = (FILE*)handle; long current = ftell(f); fseek(f, 0, SEEK_END); long size = ftell(f); fseek(f, current, SEEK_SET); return (int)size; } /* ===== RANDOM NUMBER GENERATION IMPLEMENTATION ===== */ static uint32_t _random_state = 12345; void suic_random_seed(uint32_t seed) { _random_state = seed ? seed : 12345; srand(seed); } /* Linear congruential generator */ uint32_t suic_random_int(void) { _random_state = (_random_state * 1103515245 + 12345) & 0x7fffffff; return _random_state; } int suic_random_int_range(int min, int max) { if (min > max) { int tmp = min; min = max; max = tmp; } uint32_t range = max - min + 1; return min + (suic_random_int() % range); } float suic_random_float(void) { return (float)suic_random_int() / 2147483647.0f; } float suic_random_float_range(float min, float max) { return min + (max - min) * suic_random_float(); } /* ===== TIME IMPLEMENTATION ===== */ #include #include #include static uint64_t _start_time_ms = 0; static void _init_time(void) { if (_start_time_ms == 0) { struct timeval tv; gettimeofday(&tv, NULL); _start_time_ms = (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000; } } uint64_t suic_get_time_ms(void) { _init_time(); struct timeval tv; gettimeofday(&tv, NULL); uint64_t now = (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000; return now - _start_time_ms; } uint64_t suic_get_time_us(void) { _init_time(); struct timeval tv; gettimeofday(&tv, NULL); uint64_t now = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; return now - (_start_time_ms * 1000); } uint64_t suic_get_unix_time(void) { return (uint64_t)time(NULL); } void suic_sleep_ms(uint32_t ms) { usleep(ms * 1000); } /* ===== UUID GENERATION IMPLEMENTATION ===== */ /* Simple UUID v4 generator - not cryptographically secure but good enough for game IDs */ const char* suic_uuid_generate_v4(void) { static char uuid_buffer[37]; // UUID is 36 chars + null terminator uint32_t a = suic_random_int(); uint32_t b = suic_random_int(); uint32_t c = suic_random_int(); uint32_t d = suic_random_int(); /* Set version 4 (random) and variant bits */ b = (b & 0x0fff) | 0x4000; c = (c & 0x3fff) | 0x8000; snprintf(uuid_buffer, sizeof(uuid_buffer), "%08x-%04x-%04x-%04x-%08x%04x", a, (uint16_t)(b >> 16), (uint16_t)b, (uint16_t)(c >> 16), (uint32_t)c, (uint16_t)d); return uuid_buffer; } const char* suic_uuid_generate_v4_seeded(uint64_t seed) { suic_random_seed((uint32_t)seed); return suic_uuid_generate_v4(); } /* ===== FISHSOUP NETWORKING IMPLEMENTATION ===== */ /* Client functions */ fishsoup_client_t* suic_fishsoup_client_create(const char* host, int port) { return fishsoup_client(host, port); } void suic_fishsoup_client_on_packet(fishsoup_client_t* client, suic_fishsoup_client_on_packet_fn on_packet) { fishsoup_client_on_packet(client, on_packet); } int suic_fishsoup_client_poll(fishsoup_client_t* client) { return fishsoup_client_poll(client); } void suic_fishsoup_client_destroy(fishsoup_client_t* client) { fishsoup_client_destroy(client); } /* Server functions */ fishsoup_server_t* suic_fishsoup_server_create(int port) { return fishsoup_server(port); } int suic_fishsoup_server_clients(fishsoup_server_t* server) { return fishsoup_server_clients(server); } void suic_fishsoup_server_loop(fishsoup_server_t* server) { fishsoup_server_loop(server); } void suic_fishsoup_server_on_client(fishsoup_server_t* server, suic_fishsoup_server_on_client_fn on_client) { fishsoup_server_on_client(server, on_client); } void suic_fishsoup_server_destroy(fishsoup_server_t* server) { fishsoup_server_destroy(server); } /* Packet functions */ int suic_fishsoup_packet_send(int fd, fishsoup_packet_t* packet) { return fishsoup_packet_send(fd, packet); } int suic_fishsoup_packet_recv(int fd, fishsoup_packet_t* packet) { return fishsoup_packet_recv(fd, packet); } // ============================================================================ // MATH FUNCTIONS // ============================================================================ float suic_sinf(float x) { return sinf(x); } float suic_cosf(float x) { return cosf(x); } float suic_expf(float x) { return expf(x); } float suic_fmaxf(float a, float b) { return fmaxf(a, b); }