X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_console.h;h=8d35aa286fdce8933e35b39720cd5dfd6534d850;hp=1024b82ac468b0b6e6c08d557e7561e965ffc387;hb=HEAD;hpb=76d234b7dc5e6500e8a54009b367e7620f11ef97 diff --git a/vg_console.h b/vg_console.h index 1024b82..c24423a 100644 --- a/vg_console.h +++ b/vg_console.h @@ -1,14 +1,7 @@ -/* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved */ +/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */ -#ifndef VG_CONSOLE_H -#define VG_CONSOLE_H - -#ifndef VG_GAME - #define VG_GAME -#endif - -#include "vg/vg_imgui.h" -#include "vg/vg_log.h" +#pragma once +#include "vg_platform.h" #define VG_VAR_F32( NAME, ... ) \ { u32 flags=0x00; __VA_ARGS__ ;\ @@ -20,12 +13,12 @@ #define VG_VAR_PERSISTENT 0x1 #define VG_VAR_CHEAT 0x2 -#define VG_VAR_CHEATTOGGLE 0x4 typedef struct vg_var vg_var; typedef struct vg_cmd vg_cmd; -struct vg_console{ +struct vg_console +{ struct vg_var{ void *data; const char *name; @@ -33,12 +26,11 @@ struct vg_console{ enum vg_var_dtype{ k_var_dtype_i32, k_var_dtype_u32, - k_var_dtype_f32 + k_var_dtype_f32, + k_var_dtype_str } data_type; u32 flags; - - union{ u32 _u32; f32 _f32; i32 _i32; } defaults; } vars[ 128 ]; @@ -71,688 +63,23 @@ struct vg_console{ i32 enabled, cheats; } -static vg_console; +extern vg_console; -static void _vg_console_draw( void ); -void _vg_console_println( const char *str ); -static int _vg_console_list( int argc, char const *argv[] ); -static void _vg_console_init(void); -static void _vg_console_write_persistent(void); -static void _vg_console_free(void); -static void vg_execute_console_input( const char *cmd ); - -/* - * Console interface - */ -static void console_history_get( char* buf, int entry_num ); -static int _vg_console_enabled(void); -static void console_proc_key( SDL_Keysym ev ); - -/* - * Implementation - */ -static int _vg_console_enabled(void){ - return vg_console.enabled; -} - -static void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type, - u32 flags ) -{ - if( vg_console.var_count > vg_list_size(vg_console.vars) ) - vg_fatal_error( "Too many vars registered" ); - - vg_var *var = &vg_console.vars[ vg_console.var_count ++ ]; - var->name = alias; - var->data = ptr; - var->data_type = type; - var->flags = flags; - - if ( type == k_var_dtype_f32 ) var->defaults._f32 = *((f32 *)ptr); - else if( type == k_var_dtype_i32 ) var->defaults._i32 = *((i32 *)ptr); - else if( type == k_var_dtype_u32 ) var->defaults._u32 = *((u32 *)ptr); - - vg_info( "Console variable '%s' registered\n", alias ); -} + u32 flags ); -static void vg_console_reg_cmd( const char *alias, int (*function)(int argc, const char *argv[]), - void (*poll_suggest)(int argc, const char *argv[]) ) -{ - if( vg_console.function_count > vg_list_size(vg_console.functions) ) - vg_fatal_error( "Too many functions registered" ); - - vg_cmd *cmd = &vg_console.functions[ vg_console.function_count ++ ]; - - cmd->function = function; - cmd->poll_suggest = poll_suggest; - cmd->name = alias; - - vg_info( "Console function '%s' registered\n", alias ); -} - -static int _vg_console_list( int argc, char const *argv[] ){ - for( int i=0; iname ); - } - - for( int i=0; iname ); - } - - return 0; -} - -int _test_break( int argc, const char *argv[] ){ - vg_fatal_error( "Test crash from main, after loading (console)" ); - return 0; -} - -int _vg_console_exec( int argc, const char *argv[] ){ - if( argc < 1 ) return 0; - - char path[256]; - strcpy( path, "cfg/" ); - strncat( path, argv[0], 250 ); - - FILE *fp = fopen( path, "r" ); - if( fp ){ - char line[256]; - - while( fgets( line, sizeof( line ), fp ) ){ - line[ strcspn( line, "\r\n#" ) ] = 0x00; - - if( line[0] != 0x00 ){ - vg_execute_console_input( line ); - } - } - - fclose( fp ); - } - else{ - vg_error( "Could not open '%s'\n", path ); - } - - return 0; -} - -int _ccmd_vg_console_defaults( int argc, const char *argv[] ){ - for( int i=0; idata_type; - void *ptr = cv->data; - - if ( type == k_var_dtype_f32 ) *((f32 *)ptr) = cv->defaults._f32; - else if( type == k_var_dtype_i32 ) *((i32 *)ptr) = cv->defaults._i32; - else if( type == k_var_dtype_u32 ) *((u32 *)ptr) = cv->defaults._u32; - } - - return 0; -} - -static void _vg_console_init(void){ - vg_console_reg_cmd( "list", _vg_console_list, NULL ); - vg_console_reg_cmd( "crash", _test_break, NULL ); - vg_console_reg_cmd( "exec", _vg_console_exec, NULL ); - vg_console_reg_cmd( "defaults", _ccmd_vg_console_defaults, NULL ); - vg_console_reg_var( "cheats", &vg_console.cheats, k_var_dtype_i32, -#ifdef VG_DEVWINDOW - VG_VAR_PERSISTENT -#else - 0 -#endif - ); -} - -static void vg_console_load_autos(void){ - _vg_console_exec( 1, (const char *[]){ "auto.conf" } ); -} - -static void _vg_console_write_persistent(void){ - FILE *fp = fopen( "cfg/auto.conf", "w" ); - - for( int i=0; iflags & VG_VAR_PERSISTENT ){ - switch( cv->data_type ){ - case k_var_dtype_i32: - fprintf( fp, "%s %d\n", cv->name, *(i32 *)(cv->data) ); - break; - case k_var_dtype_u32: - fprintf( fp, "%s %u\n", cv->name, *(u32 *)(cv->data) ); - break; - case k_var_dtype_f32: - fprintf( fp, "%s %.5f\n", cv->name, *(float *)(cv->data ) ); - break; - } - } - } - - fclose( fp ); -} - -static void _vg_console_free(void) -{ - _vg_console_write_persistent(); -} - -/* - * splits src into tokens and fills out args as pointers to those tokens - * returns number of tokens - * dst must be as long as src - */ -static int vg_console_tokenize( const char *src, char *dst, - const char *args[8] ) -{ - int arg_count = 0, - in_token = 0; - - for( int i=0;; i ++ ){ - if( src[i] ){ - if( src[i] == ' ' || src[i] == '\t' ){ - if( in_token ) - dst[i] = '\0'; - - in_token = 0; - - if( arg_count == 8 ) - break; - } - else{ - dst[i] = src[i]; - - if( !in_token ){ - args[ arg_count ++ ] = &dst[i]; - in_token = 1; - } - } - } - else{ - dst[i] = '\0'; - break; - } - } - - return arg_count; -} - -static vg_var *vg_console_match_var( const char *kw ) -{ - for( int i=0; iname, kw ) ){ - return cv; - } - } - - return NULL; -} - -static vg_cmd *vg_console_match_cmd( const char *kw ) -{ - for( int i=0; iname, kw ) ){ - return cmd; - } - } - - return NULL; -} - -static void vg_execute_console_input( const char *cmd ) -{ - char temp[512]; - char const *args[8]; - int arg_count = vg_console_tokenize( cmd, temp, args ); - - if( arg_count == 0 ) - return; - - vg_var *cv = vg_console_match_var( args[0] ); - vg_cmd *fn = vg_console_match_cmd( args[0] ); - - assert( !(cv && fn) ); - - if( cv ){ - /* Cvar Matched, try get value */ - if( arg_count >= 2 ){ - if( cv->flags & VG_VAR_CHEAT ){ - if( !vg_console.cheats ){ - vg_error( "variable is cheat protected\n" ); - return; - } - } - - if( (cv->data_type == k_var_dtype_u32) || - (cv->data_type == k_var_dtype_i32) ) - { - int *ptr = cv->data; - *ptr = atoi( args[1] ); - - if( cv->flags & VG_VAR_CHEATTOGGLE ){ - if( *ptr ){ - _ccmd_vg_console_defaults( 0, NULL ); - } - } - } - else if( cv->data_type == k_var_dtype_f32 ){ - float *ptr = cv->data; - *ptr = atof( args[1] ); - } - } - else{ - if( cv->data_type == k_var_dtype_i32 ) - vg_info( "= %d\n", *((int *)cv->data) ); - else if( cv->data_type == k_var_dtype_u32 ) - vg_info( "= %u\n", *((u32 *)cv->data) ); - else if( cv->data_type == k_var_dtype_f32 ) - vg_info( "= %.4f\n", *((float *)cv->data) ); - } - - return; - } - else if( fn ){ - fn->function( arg_count-1, args+1 ); - return; - } - - vg_error( "No command/var named '%s'. Use 'list' to view all\n", args[0] ); -} - -u32 str_lev_distance( const char *s1, const char *s2 ){ - u32 m = strlen( s1 ), - n = strlen( s2 ); - - if( m==0 ) return n; - if( n==0 ) return m; - - assert( n+1 <= 256 ); - - u32 costs[ 256 ]; - - for( u32 k=0; k<=n; k++ ) - costs[k] = k; - - u32 i = 0; - for( u32 i=0; i=0; j -- ) - if( score > vg_console.suggestions[j].lev_score ) - best_pos = j; - - /* insert if good score */ - if( best_pos < vg_list_size( vg_console.suggestions ) ){ - int start = VG_MIN( vg_console.suggestion_count, - vg_list_size( vg_console.suggestions )-1 ); - for( int j=start; j>best_pos; j -- ) - vg_console.suggestions[j] = vg_console.suggestions[j-1]; - - vg_console.suggestions[ best_pos ].str = str; - vg_console.suggestions[ best_pos ].len = strlen( str ); - vg_console.suggestions[ best_pos ].lev_score = score; - - if( vg_console.suggestion_count < - vg_list_size( vg_console.suggestions ) ) - vg_console.suggestion_count ++; - } -} - -static void console_update_suggestions(void) -{ - if( vg_ui.focused_control_type != k_ui_control_textbox || - vg_ui.textbuf != vg_console.input ) - return; - - vg_console.suggestion_count = 0; - vg_console.suggestion_select = -1; - vg_console.suggestion_maxlen = 0; - - /* - * - must be typing something - * - must be at the end - * - prev char must not be a whitespace - * - cursors should match - */ - - if( vg_ui.textbox.cursor_pos == 0 ) return; - if( vg_ui.textbox.cursor_pos != vg_ui.textbox.cursor_user ) return; - if( vg_console.input[ vg_ui.textbox.cursor_pos ] != '\0' ) return; - - if( (vg_console.input[ vg_ui.textbox.cursor_pos -1 ] == ' ') || - (vg_console.input[ vg_ui.textbox.cursor_pos -1 ] == '\t') ) - return; - - char temp[128]; - const char *args[8]; - - int token_count = vg_console_tokenize( vg_console.input, temp, args ); - if( !token_count ) return; - vg_console.suggestion_pastepos = args[token_count-1]-temp; - - /* Score all our commands and cvars */ - if( token_count == 1 ){ - for( int i=0; iname, args[0], 1 ); - } - - for( int i=0; iname, args[0], 1 ); - } - } - else{ - vg_cmd *cmd = vg_console_match_cmd( args[0] ); - vg_var *var = vg_console_match_var( args[0] ); - - assert( !( cmd && var ) ); - - if( cmd ) - if( cmd->poll_suggest ) - cmd->poll_suggest( token_count-1, &args[1] ); - } - - /* some post processing */ - for( int i=0; i= vg_console.suggestion_count ) - vg_console.suggestion_select = -1; - - _console_fetch_suggestion(); - } -} - -static void _console_suggest_prev(void) -{ - if( vg_console.suggestion_count ){ - _console_suggest_store_normal(); - - vg_console.suggestion_select --; - - if( vg_console.suggestion_select < -1 ) - vg_console.suggestion_select = vg_console.suggestion_count-1; - - _console_fetch_suggestion(); - } -} - -static void _vg_console_on_update( char *buf, u32 len ) -{ - if( buf == vg_console.input ){ - console_update_suggestions(); - } -} - -static void console_history_get( char* buf, int entry_num ) -{ - if( !vg_console.history_count ) - return; - - int offset = VG_MIN( entry_num, vg_console.history_count -1 ), - pick = (vg_console.history_last - offset) % - vg_list_size( vg_console.history ); - strcpy( buf, vg_console.history[ pick ] ); -} - -static void _vg_console_on_up( char *buf, u32 len ) -{ - if( buf == vg_console.input ){ - vg_console.history_pos = - VG_MAX - ( - 0, - VG_MIN - ( - vg_console.history_pos+1, - VG_MIN - ( - vg_list_size( vg_console.history ), - vg_console.history_count - 1 - ) - ) - ); - - console_history_get( vg_console.input, vg_console.history_pos ); - _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, - &vg_ui.textbox.cursor_pos, - vg_list_size(vg_console.input)-1, 1); - } -} - -static void _vg_console_on_down( char *buf, u32 len ) -{ - if( buf == vg_console.input ){ - vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 ); - console_history_get( vg_console.input, vg_console.history_pos ); - - _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, - &vg_ui.textbox.cursor_pos, - vg_list_size(vg_console.input)-1, 1 ); - } -} - -static void _vg_console_on_enter( char *buf, u32 len ) -{ - if( buf == vg_console.input ){ - if( !strlen( vg_console.input ) ) - return; - - vg_info( "%s\n", vg_console.input ); - - if( strcmp( vg_console.input, - vg_console.history[ vg_console.history_last ]) ) - { - vg_console.history_last = ( vg_console.history_last + 1) % - vg_list_size(vg_console.history ); - vg_console.history_count = - VG_MIN( vg_list_size( vg_console.history ), - vg_console.history_count + 1 ); - strcpy( vg_console.history[ vg_console.history_last ], - vg_console.input ); - } - - vg_console.history_pos = -1; - vg_execute_console_input( vg_console.input ); - _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, - &vg_ui.textbox.cursor_pos, -10000, 1 ); - - vg_console.input[0] = '\0'; - console_update_suggestions(); - } -} - -static void _vg_console_draw(void) -{ - if( !vg_console.enabled ) return; - - SDL_AtomicLock( &log_print_sl ); - - int ptr = vg_log.log_line_current; - int const fh = vg_ui.font->line_height, log_lines = 32; - int console_lines = VG_MIN( log_lines, vg_log.log_line_count ); - - ui_rect rect_log = { 0, 0, vg.window_x, log_lines*fh }, - rect_input = { 0, log_lines*fh + 1, vg.window_x, fh*2 }, - rect_line = { 0, 0, vg.window_x, fh }; - - /* - * log - */ - u32 bg_colour = (ui_colour( k_ui_bg )&0x00ffffff)|0x9f000000; - - ui_fill( rect_log, bg_colour ); - rect_line[1] = rect_log[1]+rect_log[3]-fh; - - for( int i=0; ispacing*vg_console.suggestion_pastepos; - rect_suggest[1] += rect_input[3]; - rect_suggest[2] = vg_ui.font->spacing * vg_console.suggestion_maxlen; - rect_suggest[3] = vg_console.suggestion_count * fh; - - ui_fill( rect_suggest, bg_colour ); - - rect_suggest[3] = fh; - - for( int i=0; i