suicmez/libsuicmez/libsuicmez.c
2025-12-20 17:11:21 +05:30

1029 lines
29 KiB
C

#include "libsuicmez.h"
#include "raylib.h"
#include "rlgl.h"
#include "suicmez_gc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <time.h>
#include <sys/time.h>
#include <unistd.h>
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); }