diff options
author | Darkvater <darkvater@openttd.org> | 2005-05-02 15:52:19 +0000 |
---|---|---|
committer | Darkvater <darkvater@openttd.org> | 2005-05-02 15:52:19 +0000 |
commit | d102d0c26dfad035938426ddef5c3194844999d6 (patch) | |
tree | 046b689f2282f62a4969988c6d1b6898c5d25205 | |
parent | 7a012a3465273d3696a243c8d4a5a9561c521fce (diff) | |
download | openttd-d102d0c26dfad035938426ddef5c3194844999d6.tar.xz |
(svn r2243) -Fix: Rework of console. Use 'help command|variable' to get help about it. You can assign variables with =, ++, --, or just new value. Console parser is now lenient towards typed spaces, and more robust in general (at least readable). Removed the 'set' command, instead implemented all such variables as 'variables'.
- Some variables are really special and cannot be assigned normally, use their callback procedure for assignment/querying. This commit also obsoletes "[1172804] Console set command cleanup"
-rw-r--r-- | console.c | 1596 | ||||
-rw-r--r-- | console.h | 222 | ||||
-rw-r--r-- | console_cmds.c | 1498 | ||||
-rw-r--r-- | network.c | 15 | ||||
-rw-r--r-- | network.h | 2 | ||||
-rw-r--r-- | player_gui.c | 2 | ||||
-rw-r--r-- | settings.h | 3 | ||||
-rw-r--r-- | settings_gui.c | 152 |
8 files changed, 1509 insertions, 1981 deletions
@@ -16,17 +16,17 @@ #include "network_server.h" #define ICON_BUFFER 79 -#define ICON_CMDBUF_SIZE 20 -#define ICON_CMDLN_SIZE 255 +#define ICON_HISTORY_SIZE 20 #define ICON_LINE_HEIGHT 12 #define ICON_RIGHT_BORDERWIDTH 10 #define ICON_BOTTOM_BORDERWIDTH 12 #define ICON_MAX_ALIAS_LINES 40 +#define ICON_TOKEN_COUNT 20 // ** main console ** // static Window *_iconsole_win; // Pointer to console window static bool _iconsole_inited; -static char* _iconsole_buffer[ICON_BUFFER + 1]; +static char *_iconsole_buffer[ICON_BUFFER + 1]; static uint16 _iconsole_cbuffer[ICON_BUFFER + 1]; static Textbuf _iconsole_cmdline; static byte _iconsole_scroll; @@ -34,11 +34,11 @@ static byte _iconsole_scroll; // ** stdlib ** // byte _stdlib_developer = 1; bool _stdlib_con_developer = false; -FILE* _iconsole_output_file; +FILE *_iconsole_output_file; // ** main console cmd buffer -static char* _iconsole_cmdbuffer[ICON_CMDBUF_SIZE]; -static byte _iconsole_cmdbufferpos; +static char *_iconsole_history[ICON_HISTORY_SIZE]; +static byte _iconsole_historypos; /* *************** */ /* end of header */ @@ -54,10 +54,12 @@ static void IConsoleClearCommand(void) SetWindowDirty(_iconsole_win); } +static inline void IConsoleResetHistoryPos(void) {_iconsole_historypos = ICON_HISTORY_SIZE - 1;} + // ** console window ** // static void IConsoleWndProc(Window* w, WindowEvent* e) { - switch(e->event) { + switch (e->event) { case WE_PAINT: { int i = _iconsole_scroll; int max = (w->height / ICON_LINE_HEIGHT) - 1; @@ -93,11 +95,11 @@ static void IConsoleWndProc(Window* w, WindowEvent* e) e->keypress.cont = false; switch (e->keypress.keycode) { case WKC_UP: - IConsoleCmdBufferNavigate(+1); + IConsoleHistoryNavigate(+1); SetWindowDirty(w); break; case WKC_DOWN: - IConsoleCmdBufferNavigate(-1); + IConsoleHistoryNavigate(-1); SetWindowDirty(w); break; case WKC_SHIFT | WKC_PAGEUP: @@ -133,8 +135,7 @@ static void IConsoleWndProc(Window* w, WindowEvent* e) break; case WKC_RETURN: case WKC_NUM_ENTER: IConsolePrintF(_iconsole_color_commands, "] %s", _iconsole_cmdline.buf); - _iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1; - IConsoleCmdBufferAdd(_iconsole_cmdline.buf); + IConsoleHistoryAdd(_iconsole_cmdline.buf); IConsoleCmdExec(_iconsole_cmdline.buf); IConsoleClearCommand(); @@ -145,23 +146,28 @@ static void IConsoleWndProc(Window* w, WindowEvent* e) MarkWholeScreenDirty(); break; case (WKC_CTRL | 'V'): - if (InsertTextBufferClipboard(&_iconsole_cmdline)) + if (InsertTextBufferClipboard(&_iconsole_cmdline)) { + IConsoleResetHistoryPos(); SetWindowDirty(w); + } break; case WKC_BACKSPACE: case WKC_DELETE: - if (DeleteTextBufferChar(&_iconsole_cmdline, e->keypress.keycode)) + if (DeleteTextBufferChar(&_iconsole_cmdline, e->keypress.keycode)) { + IConsoleResetHistoryPos(); SetWindowDirty(w); - _iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1; + } break; case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME: - if (MoveTextBufferPos(&_iconsole_cmdline, e->keypress.keycode)) + if (MoveTextBufferPos(&_iconsole_cmdline, e->keypress.keycode)) { + IConsoleResetHistoryPos(); SetWindowDirty(w); + } break; default: if (IsValidAsciiChar(e->keypress.ascii)) { _iconsole_scroll = ICON_BUFFER; InsertTextBufferChar(&_iconsole_cmdline, e->keypress.ascii); - _iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1; + IConsoleResetHistoryPos(); SetWindowDirty(w); } else e->keypress.cont = true; @@ -182,10 +188,9 @@ static const WindowDesc _iconsole_window_desc = { IConsoleWndProc, }; -extern const char _openttd_revision[]; - void IConsoleInit(void) { + extern const char _openttd_revision[]; _iconsole_output_file = NULL; _iconsole_color_default = 1; _iconsole_color_error = 3; @@ -193,7 +198,7 @@ void IConsoleInit(void) _iconsole_color_debug = 5; _iconsole_color_commands = 2; _iconsole_scroll = ICON_BUFFER; - _iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1; + _iconsole_historypos = ICON_HISTORY_SIZE - 1; _iconsole_inited = true; _iconsole_mode = ICONSOLE_CLOSED; _iconsole_win = NULL; @@ -202,19 +207,19 @@ void IConsoleInit(void) _redirect_console_to_client = 0; #endif - memset(_iconsole_cmdbuffer, 0, sizeof(_iconsole_cmdbuffer)); + memset(_iconsole_history, 0, sizeof(_iconsole_history)); memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer)); memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer)); _iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it _iconsole_cmdline.maxlength = ICON_CMDLN_SIZE - 1; + IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision); + IConsolePrint(12, "------------------------------------"); + IConsolePrint(12, "use \"help\" for more information"); + IConsolePrint(12, ""); IConsoleStdLibRegister(); - IConsolePrintF(13, "OpenTTD Game Console Revision 6 - %s", _openttd_revision); - IConsolePrint(12, "---------------------------------"); - IConsolePrint(12, "use \"help\" for more info"); - IConsolePrint(12, ""); IConsoleClearCommand(); - IConsoleCmdBufferAdd(""); + IConsoleHistoryAdd(""); } void IConsoleClear(void) @@ -256,7 +261,6 @@ void IConsoleFree(void) void IConsoleResize(void) { - _iconsole_win = FindWindowById(WC_CONSOLE, 0); switch (_iconsole_mode) { @@ -269,7 +273,7 @@ void IConsoleResize(void) _iconsole_win->width = _screen.width; break; default: - break; + NOT_REACHED(); } MarkWholeScreenDirty(); @@ -283,7 +287,7 @@ void IConsoleSwitch(void) _iconsole_win->height = _screen.height / 3; _iconsole_win->width = _screen.width; _iconsole_mode = ICONSOLE_OPENED; - SETBIT(_no_scroll, SCROLL_CON); + SETBIT(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll break; case ICONSOLE_OPENED: case ICONSOLE_FULL: DeleteWindowById(WC_CONSOLE, 0); @@ -296,44 +300,47 @@ void IConsoleSwitch(void) MarkWholeScreenDirty(); } -void IConsoleClose(void) -{ - if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch(); -} +void IConsoleClose(void) {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();} +void IConsoleOpen(void) {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();} -void IConsoleOpen(void) +/** + * Add the entered line into the history so you can look it back + * scroll, etc. Put it to the beginning as it is the latest text + * @param cmd Text to be entered into the 'history' + */ +void IConsoleHistoryAdd(const char *cmd) { - if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch(); -} + free(_iconsole_history[ICON_HISTORY_SIZE - 1]); -void IConsoleCmdBufferAdd(const char* cmd) -{ - int i; - if (_iconsole_cmdbufferpos != (ICON_CMDBUF_SIZE - 1)) return; - free(_iconsole_cmdbuffer[ICON_CMDBUF_SIZE - 2]); - for (i = (ICON_CMDBUF_SIZE - 2); i > 0; i--) _iconsole_cmdbuffer[i] = _iconsole_cmdbuffer[i - 1]; - _iconsole_cmdbuffer[0] = strdup(cmd); + memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1)); + _iconsole_history[0] = strdup(cmd); + IConsoleResetHistoryPos(); } -void IConsoleCmdBufferNavigate(signed char direction) +/** + * Navigate Up/Down in the history of typed commands + * @param direction Go further back in history (+1), go to recently typed commands (-1) + */ +void IConsoleHistoryNavigate(signed char direction) { - int i; - i = _iconsole_cmdbufferpos + direction; - if (i < 0) i = ICON_CMDBUF_SIZE - 1; - if (i >= ICON_CMDBUF_SIZE) i = 0; + int i = _iconsole_historypos + direction; + + // watch out for overflows, just wrap around + if (i < 0) i = ICON_HISTORY_SIZE - 1; + if (i >= ICON_HISTORY_SIZE) i = 0; + if (direction > 0) - while (_iconsole_cmdbuffer[i] == NULL) { - i++; - if (i >= ICON_CMDBUF_SIZE) i = 0; - } - if (direction < 0) - while (_iconsole_cmdbuffer[i] == NULL) { - --i; - if (i < 0) i = ICON_CMDBUF_SIZE - 1; - } - _iconsole_cmdbufferpos = i; + if (_iconsole_history[i] == NULL) i = 0; + + if (direction < 0) { + while (i > 0 && _iconsole_history[i] == NULL) i--; + } + + _iconsole_historypos = i; IConsoleClearCommand(); - ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_cmdbuffer[i], _iconsole_cmdline.maxlength); + // copy history to 'command prompt / bash' + assert(_iconsole_history[i] != NULL && IS_INT_INSIDE(i, 0, ICON_HISTORY_SIZE)); + ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength); UpdateTextBufferSize(&_iconsole_cmdline); } @@ -348,8 +355,6 @@ void IConsoleCmdBufferNavigate(signed char direction) */ void IConsolePrint(uint16 color_code, const char* string) { - char *i; - #ifdef ENABLE_NETWORK if (_redirect_console_to_client != 0) { /* Redirect the string to the client */ @@ -372,9 +377,11 @@ void IConsolePrint(uint16 color_code, const char* string) memmove(&_iconsole_buffer[0], &_iconsole_buffer[1], sizeof(_iconsole_buffer[0]) * ICON_BUFFER); _iconsole_buffer[ICON_BUFFER] = strdup(string); - // filter out unprintable characters - for (i = _iconsole_buffer[ICON_BUFFER]; *i != '\0'; i++) - if (!IsValidAsciiChar((byte)*i)) *i = ' '; + { // filter out unprintable characters + char *i; + for (i = _iconsole_buffer[ICON_BUFFER]; *i != '\0'; i++) + if (!IsValidAsciiChar((byte)*i)) *i = ' '; + } memmove(&_iconsole_cbuffer[0], &_iconsole_cbuffer[1], sizeof(_iconsole_cbuffer[0]) * ICON_BUFFER); _iconsole_cbuffer[ICON_BUFFER] = color_code; @@ -384,1103 +391,716 @@ void IConsolePrint(uint16 color_code, const char* string) if (_iconsole_win != NULL) SetWindowDirty(_iconsole_win); } - -void CDECL IConsolePrintF(uint16 color_code, const char* s, ...) +/** + * Handle the printing of text entered into the console or redirected there + * by any other means. Uses printf() style format, for more information look + * at @IConsolePrint() + */ +void CDECL IConsolePrintF(uint16 color_code, const char *s, ...) { va_list va; - char buf[1024]; - int len; + char buf[ICON_MAX_STREAMSIZE]; va_start(va, s); - len = vsnprintf(buf, sizeof(buf), s, va); + vsnprintf(buf, sizeof(buf), s, va); va_end(va); IConsolePrint(color_code, buf); } +/** + * It is possible to print debugging information to the console, + * which is achieved by using this function. Can only be used by + * @debug() in debug.c. You need at least a level 2 (developer) for debugging + * messages to show up + */ void IConsoleDebug(const char* string) { if (_stdlib_developer > 1) IConsolePrintF(_iconsole_color_debug, "dbg: %s", string); } -void IConsoleError(const char* string) +/** + * It is possible to print warnings to the console. These are mostly + * errors or mishaps, but non-fatal. You need at least a level 1 (developer) for + * debugging messages to show up + */ +void IConsoleWarning(const char* string) { if (_stdlib_developer > 0) - IConsolePrintF(_iconsole_color_error, "ERROR: %s", string); + IConsolePrintF(_iconsole_color_warning, "WARNING: %s", string); } -void IConsoleWarning(const char* string) +/** + * It is possible to print error information to the console. This can include + * game errors, or errors in general you would want the user to notice + */ +void IConsoleError(const char* string) { - if (_stdlib_developer > 0) - IConsolePrintF(_iconsole_color_warning, "WARNING: %s", string); + IConsolePrintF(_iconsole_color_error, "ERROR: %s", string); } -void IConsoleCmdRegister(const char* name, _iconsole_cmd_addr addr) +/** + * Change a string into its number representation. Supports + * decimal and hexadecimal numbers as well as 'on'/'off' 'true'/'false' + * @param *value the variable a successfull conversion will be put in + * @param *arg the string to be converted + * @return Return true on success or false on failure + */ +bool GetArgumentInteger(uint32 *value, const char *arg) { - char* _new; - _iconsole_cmd* item; - _iconsole_cmd* item_new; - _iconsole_cmd* item_before; + int result = sscanf(arg, "%u", value); - _new = strdup(name); + if (result == 0 && arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) + result = sscanf(arg, "%x", value); - item_new = malloc(sizeof(_iconsole_cmd)); + if (result == 0 && (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0 )) {*value = 1; result = 1;} - item_new->_next = NULL; - item_new->addr = addr; - item_new->name = _new; + if (result == 0 && (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0)) {*value = 0; result = 1;} - item_new->hook_access = NULL; - item_new->hook_after_exec = NULL; - item_new->hook_before_exec = NULL; + return !!result; +} - item_before = NULL; - item = _iconsole_cmds; +/** + * Perhaps ugly macro, but this saves us the trouble of writing the same function + * three types, just with different variables. Yes, templates would be handy. It was + * either this define or an even more ugly void* magic function + */ +#define IConsoleAddSorted(_base, item_new, IConsoleType, type) \ +{ \ + IConsoleType *item, *item_before; \ + /* first command */ \ + if (_base == NULL) { \ + _base = item_new; \ + return; \ + } \ + \ + item_before = NULL; \ + item = _base; \ + \ + /* BEGIN - Alphabetically insert the commands into the linked list */ \ + while (item != NULL) { \ + int i = strcmp(item->name, item_new->name); \ + if (i == 0) { \ + IConsoleError(type " with this name already exists; insertion aborted"); \ + free(item_new); \ + return; \ + } \ + \ + if (i > 0) break; /* insert at this position */ \ + \ + item_before = item; \ + item = item->next; \ + } \ + \ + if (item_before == NULL) { \ + _base = item_new; \ + } else \ + item_before->next = item_new; \ + \ + item_new->next = item; \ + /* END - Alphabetical insert */ \ +} - if (item == NULL) { - _iconsole_cmds = item_new; - } else { - while ((item->_next != NULL) && (strcmp(item->name,item_new->name)<=0)) { - item_before = item; - item = item->_next; - } -// insertion sort - if (item_before==NULL) { - if (strcmp(item->name,item_new->name)<=0) { - // appending - item ->_next = item_new; - } else { - // inserting as startitem - _iconsole_cmds = item_new; - item_new ->_next = item; - } - } else { - if (strcmp(item->name,item_new->name)<=0) { - // appending - item ->_next = item_new; - } else { - // inserting - item_new ->_next = item_before->_next; - item_before ->_next = item_new; - } - } -// insertion sort end - } +/** + * Register a new command to be used in the console + * @param name name of the command that will be used + * @param proc function that will be called upon execution of command + */ +void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc) +{ + char *new_cmd = strdup(name); + IConsoleCmd *item_new = malloc(sizeof(IConsoleCmd)); + + item_new->next = NULL; + item_new->proc = proc; + item_new->name = new_cmd; + + item_new->hook.access = NULL; + item_new->hook.pre = NULL; + item_new->hook.post = NULL; + IConsoleAddSorted(_iconsole_cmds, item_new, IConsoleCmd, "a command"); } -_iconsole_cmd* IConsoleCmdGet(const char* name) +/** + * Find the command pointed to by its string + * @param name command to be found + * @return return Cmdstruct of the found command, or NULL on failure + */ +IConsoleCmd *IConsoleCmdGet(const char *name) { - _iconsole_cmd* item; + IConsoleCmd *item; - item = _iconsole_cmds; - while (item != NULL) { + for (item = _iconsole_cmds; item != NULL; item = item->next) { if (strcmp(item->name, name) == 0) return item; - item = item->_next; } return NULL; } -void IConsoleAliasRegister(const char* name, const char* cmdline) +/** + * Register a an alias for an already existing command in the console + * @param name name of the alias that will be used + * @param cmd name of the command that 'name' will be alias of + */ +void IConsoleAliasRegister(const char *name, const char *cmd) { - char* _new; - char* _newcmd; - _iconsole_alias* item; - _iconsole_alias* item_new; - _iconsole_alias* item_before; - - _new = strdup(name); - _newcmd = strdup(cmdline); - - item_new = malloc(sizeof(_iconsole_alias)); - - item_new->_next = NULL; - item_new->cmdline = _newcmd; - item_new->name = _new; - - item_before = NULL; - item = _iconsole_aliases; - - if (item == NULL) { - _iconsole_aliases = item_new; - } else { - while ((item->_next != NULL) && (strcmp(item->name,item_new->name)<=0)) { - item_before = item; - item = item->_next; - } -// insertion sort - if (item_before==NULL) { - if (strcmp(item->name,item_new->name)<=0) { - // appending - item ->_next = item_new; - } else { - // inserting as startitem - _iconsole_aliases = item_new; - item_new ->_next = item; - } - } else { - if (strcmp(item->name,item_new->name)<=0) { - // appending - item ->_next = item_new; - } else { - // inserting - item_new ->_next = item_before->_next; - item_before ->_next = item_new; - } - } -// insertion sort end - } + char *new_alias = strdup(name); + char *cmd_aliased = strdup(cmd); + IConsoleAlias *item_new = malloc(sizeof(IConsoleAlias)); + item_new->next = NULL; + item_new->cmdline = cmd_aliased; + item_new->name = new_alias; + + IConsoleAddSorted(_iconsole_aliases, item_new, IConsoleAlias, "an alias"); } -_iconsole_alias* IConsoleAliasGet(const char* name) +/** + * Find the alias pointed to by its string + * @param name alias to be found + * @return return Aliasstruct of the found alias, or NULL on failure + */ +IConsoleAlias *IConsoleAliasGet(const char *name) { - _iconsole_alias* item; + IConsoleAlias* item; - item = _iconsole_aliases; - while (item != NULL) { + for (item = _iconsole_aliases; item != NULL; item = item->next) { if (strcmp(item->name, name) == 0) return item; - item = item->_next; } + return NULL; } -static void IConsoleAliasExec(const char* cmdline, char* tokens[20], byte tokentypes[20]) +/** copy in an argument into the aliasstream */ +static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos) { - char* lines[ICON_MAX_ALIAS_LINES]; - char* linestream; - char* linestream_s; + int len = min(ICON_MAX_STREAMSIZE - bufpos, strlen(src)); + strncpy(dst, src, len); - int c; + return len; +} + +/** + * An alias is just another name for a command, or for more commands + * Execute it as well. + * @param *alias is the alias of the command + * @param tokencount the number of parameters passed + * @param *tokens are the parameters given to the original command (0 is the first param) + */ +void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT]) +{ + const char *cmdptr; + char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE]; int i; - int l; - int x; - byte t; + uint a_index, astream_i; - //** clearing buffer **// + memset(&aliases, 0, sizeof(aliases)); + memset(&aliasstream, 0, sizeof(aliasstream)); - for (i = 0; i < 40; i++) { - lines[0] = NULL; - } - linestream_s = linestream = malloc(1024*ICON_MAX_ALIAS_LINES); - memset(linestream, 0, 1024*ICON_MAX_ALIAS_LINES); - - //** parsing **// - - l = strlen(cmdline); - i = 0; - c = 0; - x = 0; - t = 0; - lines[c] = linestream; - - while (i < l && c < ICON_MAX_ALIAS_LINES - 1) { - if (cmdline[i] == '%') { - i++; - if (cmdline[i] == '+') { - // all params seperated: "[param 1]" "[param 2]" - t=1; - while ((tokens[t]!=NULL) && (t<20) && - ((tokentypes[t] == ICONSOLE_VAR_STRING) || (tokentypes[t] == ICONSOLE_VAR_UNKNOWN))) { - int l2 = strlen(tokens[t]); - *linestream = '"'; - linestream++; - memcpy(linestream,tokens[t],l2); - linestream += l2; - *linestream = '"'; - linestream++; - *linestream = ' '; - linestream++; - x += l2+3; - t++; + aliases[0] = aliasstream; + for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; *cmdptr++) { + if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break; + + switch (*cmdptr) { + case '\'': /* ' will double for "" */ + aliasstream[astream_i++] = '"'; + break; + case ';': /* Cmd seperator, start new command */ + aliasstream[astream_i] = '\0'; + aliases[++a_index] = &aliasstream[++astream_i]; + *cmdptr++; + break; + case '%': /* Some or all parameters */ + *cmdptr++; + switch (*cmdptr) { + case '+': { /* All parameters seperated: "[param 1]" "[param 2]" */ + for (i = 0; i != tokencount; i++) { + aliasstream[astream_i++] = '"'; + astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i); + aliasstream[astream_i++] = '"'; + aliasstream[astream_i++] = ' '; } - } else if (cmdline[i] == '!') { - // merge the params to one: "[param 1] [param 2] [param 3...]" - t=1; - *linestream = '"'; - linestream++; - while ((tokens[t]!=NULL) && (t<20) && - ((tokentypes[t] == ICONSOLE_VAR_STRING) || (tokentypes[t] == ICONSOLE_VAR_UNKNOWN))) { - int l2 = strlen(tokens[t]); - memcpy(linestream,tokens[t],l2); - linestream += l2; - *linestream = ' '; - linestream++; - x += l2+1; - t++; + } break; + case '!': { /* Merge the parameters to one: "[param 1] [param 2] [param 3...]" */ + aliasstream[astream_i++] = '"'; + for (i = 0; i != tokencount; i++) { + astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i); + aliasstream[astream_i++] = ' '; } - linestream--; - *linestream = '"'; - linestream++; - x += 1; - } else { - // one specific parameter: %A = [param 1] %B = [param 2] ... - int l2; - t = ((byte)cmdline[i]) - 64; - if ((t<20) && (tokens[t]!=NULL) && - ((tokentypes[t] == ICONSOLE_VAR_STRING) || (tokentypes[t] == ICONSOLE_VAR_UNKNOWN))) { - l2 = strlen(tokens[t]); - *linestream = '"'; - linestream++; - memcpy(linestream,tokens[t],l2); - linestream += l2; - *linestream = '"'; - linestream++; - x += l2+2; + aliasstream[astream_i++] = '"'; + + } break; + default: { /* One specific parameter: %A = [param 1] %B = [param 2] ... */ + int param = *cmdptr - 'A'; + + if (param < 0 || param >= tokencount) { + IConsoleError("too many or wrong amount of parameters passed to alias, aborting"); + IConsolePrintF(_iconsole_color_warning, "Usage of alias '%s': %s", alias->name, alias->cmdline); + return; } - } - } else if (cmdline[i] == '\\') { - // \\ = \ \' = ' \% = % - i++; - if (cmdline[i] == '\\') { - *linestream = '\\'; - linestream++; - } else if (cmdline[i] == '\'') { - *linestream = '\''; - linestream++; - } else if (cmdline[i] == '%') { - *linestream = '%'; - linestream++; - } - } else if (cmdline[i] == '\'') { - // ' = " - *linestream = '"'; - linestream++; - } else if (cmdline[i] == ';') { - // ; = start a new line - c++; - *linestream = '\0'; - linestream += 1024 - (x % 1024); - x += 1024 - (x % 1024); - lines[c] = linestream; - } else { - *linestream = cmdline[i]; - linestream++; - x++; - } - i++; - } - linestream--; - if (*linestream != '\0') { - c++; - linestream++; - *linestream = '\0'; - } + aliasstream[astream_i++] = '"'; + astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i); + aliasstream[astream_i++] = '"'; + } break; + } break; - for (i=0; i<c; i++) { - IConsoleCmdExec(lines[i]); + default: + aliasstream[astream_i++] = *cmdptr; + break; + } } - free(linestream_s); + for (i = 0; i <= (int)a_index; i++) IConsoleCmdExec(aliases[i]); // execute each alias in turn } -void IConsoleVarInsert(_iconsole_var* item_new, const char* name) +/** + * Special function for adding string-type variables. They in addition + * also need a 'size' value saying how long their string buffer is. + * @param size the length of the string buffer + * For more information see @IConsoleVarRegister() + */ +void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help) { - _iconsole_var* item; - _iconsole_var* item_before; - - item_new->_next = NULL; - - item_new->name = malloc(strlen(name) + 2); /* XXX unchecked malloc */ - sprintf(item_new->name, "%s", name); - - item_before = NULL; - item = _iconsole_vars; - - if (item == NULL) { - _iconsole_vars = item_new; - } else { - while ((item->_next != NULL) && (strcmp(item->name,item_new->name)<=0)) { - item_before = item; - item = item->_next; - } -// insertion sort - if (item_before==NULL) { - if (strcmp(item->name,item_new->name)<=0) { - // appending - item ->_next = item_new; - } else { - // inserting as startitem - _iconsole_vars = item_new; - item_new ->_next = item; - } - } else { - if (strcmp(item->name,item_new->name)<=0) { - // appending - item ->_next = item_new; - } else { - // inserting - item_new ->_next = item_before->_next; - item_before ->_next = item_new; - } - } -// insertion sort end - } + IConsoleVar *var; + IConsoleVarRegister(name, addr, ICONSOLE_VAR_STRING, help); + var = IConsoleVarGet(name); + var->size = size; } -void IConsoleVarRegister(const char* name, void* addr, _iconsole_var_types type) +/** + * Register a new variable to be used in the console + * @param name name of the variable that will be used + * @param addr memory location the variable will point to + * @param help the help string shown for the variable + * @param type the type of the variable (simple atomic) so we know which values it can get + */ +void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help) { - _iconsole_var* item_new; - - item_new = malloc(sizeof(_iconsole_var)); /* XXX unchecked malloc */ - - item_new->_next = NULL; - - switch (type) { - case ICONSOLE_VAR_BOOLEAN: - item_new->data.bool_ = addr; - break; - case ICONSOLE_VAR_BYTE: - case ICONSOLE_VAR_UINT8: - item_new->data.byte_ = addr; - break; - case ICONSOLE_VAR_UINT16: - item_new->data.uint16_ = addr; - break; - case ICONSOLE_VAR_UINT32: - item_new->data.uint32_ = addr; - break; - case ICONSOLE_VAR_INT16: - item_new->data.int16_ = addr; - break; - case ICONSOLE_VAR_INT32: - item_new->data.int32_ = addr; - break; - case ICONSOLE_VAR_STRING: - item_new->data.string_ = addr; - break; - default: - error("unknown console variable type"); - break; - } + char *new_cmd = strdup(name); + IConsoleVar *item_new = malloc(sizeof(IConsoleVar)); - IConsoleVarInsert(item_new, name); + item_new->help = (help != NULL) ? strdup(help) : NULL; + item_new->next = NULL; + item_new->name = new_cmd; + item_new->addr = addr; + item_new->proc = NULL; item_new->type = type; - item_new->_malloc = false; - item_new->hook_access = NULL; - item_new->hook_after_change = NULL; - item_new->hook_before_change = NULL; + item_new->hook.access = NULL; + item_new->hook.pre = NULL; + item_new->hook.post = NULL; + IConsoleAddSorted(_iconsole_vars, item_new, IConsoleVar, "a variable"); } -void IConsoleVarMemRegister(const char* name, _iconsole_var_types type) -{ - _iconsole_var* item; - item = IConsoleVarAlloc(type); - IConsoleVarInsert(item, name); -} - -_iconsole_var* IConsoleVarGet(const char* name) +/** + * Find the variable pointed to by its string + * @param name variable to be found + * @return return Varstruct of the found variable, or NULL on failure + */ +IConsoleVar *IConsoleVarGet(const char *name) { - _iconsole_var* item; - for (item = _iconsole_vars; item != NULL; item = item->_next) + IConsoleVar *item; + for (item = _iconsole_vars; item != NULL; item = item->next) { if (strcmp(item->name, name) == 0) return item; + } + return NULL; } -_iconsole_var* IConsoleVarAlloc(_iconsole_var_types type) +/** + * Set a new value to a console variable + * @param *var the variable being set/changed + * @param value the new value given to the variable, cast properly + */ +static void IConsoleVarSetValue(const IConsoleVar *var, uint32 value) { - _iconsole_var* item = malloc(sizeof(_iconsole_var)); /* XXX unchecked malloc */ - item->_next = NULL; - item->name = NULL; - item->type = type; - switch (item->type) { + switch (var->type) { case ICONSOLE_VAR_BOOLEAN: - item->data.bool_ = malloc(sizeof(*item->data.bool_)); - *item->data.bool_ = false; - item->_malloc = true; + *(bool*)var->addr = (value != 0); break; case ICONSOLE_VAR_BYTE: - case ICONSOLE_VAR_UINT8: - item->data.byte_ = malloc(sizeof(*item->data.byte_)); - *item->data.byte_ = 0; - item->_malloc = true; + *(byte*)var->addr = (byte)value; break; case ICONSOLE_VAR_UINT16: - item->data.uint16_ = malloc(sizeof(*item->data.uint16_)); - *item->data.uint16_ = 0; - item->_malloc = true; - break; - case ICONSOLE_VAR_UINT32: - item->data.uint32_ = malloc(sizeof(*item->data.uint32_)); - *item->data.uint32_ = 0; - item->_malloc = true; + *(uint16*)var->addr = (byte)value; break; case ICONSOLE_VAR_INT16: - item->data.int16_ = malloc(sizeof(*item->data.int16_)); - *item->data.int16_ = 0; - item->_malloc = true; - break; - case ICONSOLE_VAR_INT32: - item->data.int32_ = malloc(sizeof(*item->data.int32_)); - *item->data.int32_ = 0; - item->_malloc = true; + *(int16*)var->addr = (int16)value; break; - case ICONSOLE_VAR_POINTER: - case ICONSOLE_VAR_STRING: - // needs no memory ... it gets memory when it is set to an value - item->data.addr = NULL; - item->_malloc = false; + case ICONSOLE_VAR_UINT32: + *(uint32*)var->addr = (uint32)value; break; - default: - error("unknown console variable type"); + case ICONSOLE_VAR_INT32: + *(int32*)var->addr = (int32)value; break; + default: NOT_REACHED(); } - item->hook_access = NULL; - item->hook_after_change = NULL; - item->hook_before_change = NULL; - return item; + IConsoleVarPrintSetValue(var); } - -void IConsoleVarFree(_iconsole_var* var) +/** + * Set a new value to a string-type variable. Basically this + * means to copy the new value over to the container. + * @param *var the variable in question + * @param *value the new value + */ +static void IConsoleVarSetStringvalue(const IConsoleVar *var, char *value) { - if (var->_malloc) - free(var->data.addr); - free(var->name); - free(var); + if (var->type != ICONSOLE_VAR_STRING || var->addr == NULL) return; + + ttd_strlcpy((char*)var->addr, (char*)value, var->size); + IConsoleVarPrintSetValue(var); // print out the new value, giving feedback + return; } -void IConsoleVarSetString(_iconsole_var* var, const char* string) +/** + * Query the current value of a variable and return it + * @param *var the variable queried + * @return current value of the variable + */ +static uint32 IConsoleVarGetValue(const IConsoleVar *var) { - if (string == NULL) return; - - if (var->_malloc) - free(var->data.string_); + uint32 result = 0; - var->data.string_ = strdup(string); - var->_malloc = true; -} - -void IConsoleVarSetValue(_iconsole_var* var, int value) { switch (var->type) { case ICONSOLE_VAR_BOOLEAN: - *var->data.bool_ = (value != 0); + result = *(bool*)var->addr; break; case ICONSOLE_VAR_BYTE: - case ICONSOLE_VAR_UINT8: - *var->data.byte_ = value; + result = *(byte*)var->addr; break; case ICONSOLE_VAR_UINT16: - *var->data.uint16_ = value; - break; - case ICONSOLE_VAR_UINT32: - *var->data.uint32_ = value; + result = *(uint16*)var->addr; break; case ICONSOLE_VAR_INT16: - *var->data.int16_ = value; + result = *(int16*)var->addr; break; - case ICONSOLE_VAR_INT32: - *var->data.int32_ = value; + case ICONSOLE_VAR_UINT32: + result = *(uint32*)var->addr; break; - default: - assert(0); + case ICONSOLE_VAR_INT32: + result = *(int32*)var->addr; break; + default: NOT_REACHED(); } + return result; } -void IConsoleVarDump(const _iconsole_var* var, const char* dump_desc) +/** + * Get the value of the variable and put it into a printable + * string form so we can use it for printing + */ +static char *IConsoleVarGetStringValue(const IConsoleVar *var) { - if (var == NULL) return; - if (dump_desc == NULL) dump_desc = var->name; + static char tempres[50]; + char *value = tempres; switch (var->type) { case ICONSOLE_VAR_BOOLEAN: - IConsolePrintF(_iconsole_color_default, "%s = %s", - dump_desc, *var->data.bool_ ? "true" : "false"); + snprintf(tempres, sizeof(tempres), "%s", (*(bool*)var->addr) ? "on" : "off"); break; case ICONSOLE_VAR_BYTE: - case ICONSOLE_VAR_UINT8: - IConsolePrintF(_iconsole_color_default, "%s = %u", - dump_desc, *var->data.byte_); + snprintf(tempres, sizeof(tempres), "%u", *(byte*)var->addr); break; case ICONSOLE_VAR_UINT16: - IConsolePrintF(_iconsole_color_default, "%s = %u", - dump_desc, *var->data.uint16_); + snprintf(tempres, sizeof(tempres), "%u", *(uint16*)var->addr); break; case ICONSOLE_VAR_UINT32: - IConsolePrintF(_iconsole_color_default, "%s = %u", - dump_desc, *var->data.uint32_); + snprintf(tempres, sizeof(tempres), "%u", *(uint32*)var->addr); break; case ICONSOLE_VAR_INT16: - IConsolePrintF(_iconsole_color_default, "%s = %i", - dump_desc, *var->data.int16_); + snprintf(tempres, sizeof(tempres), "%i", *(int16*)var->addr); break; case ICONSOLE_VAR_INT32: - IConsolePrintF(_iconsole_color_default, "%s = %i", - dump_desc, *var->data.int32_); + snprintf(tempres, sizeof(tempres), "%i", *(int32*)var->addr); break; case ICONSOLE_VAR_STRING: - IConsolePrintF(_iconsole_color_default, "%s = %s", - dump_desc, var->data.string_); - break; - case ICONSOLE_VAR_REFERENCE: - IConsolePrintF(_iconsole_color_default, "%s = @%s", - dump_desc, var->data.reference_); - case ICONSOLE_VAR_UNKNOWN: - case ICONSOLE_VAR_POINTER: - IConsolePrintF(_iconsole_color_default, "%s = @%p", - dump_desc, var->data.addr); - break; - case ICONSOLE_VAR_NONE: - IConsolePrintF(_iconsole_color_default, "%s = [nothing]", - dump_desc); - break; + value = (char*)var->addr; + default: NOT_REACHED(); } -} -// * ************************* * // -// * hooking code * // -// * ************************* * // + return value; +} -void IConsoleVarHook(const char* name, _iconsole_hook_types type, iconsole_var_hook proc) +/** + * Print out the value of the variable when asked + */ +void IConsoleVarPrintGetValue(const IConsoleVar *var) { - _iconsole_var* hook_var = IConsoleVarGet(name); - if (hook_var == NULL) return; - switch (type) { - case ICONSOLE_HOOK_BEFORE_CHANGE: - hook_var->hook_before_change = proc; - break; - case ICONSOLE_HOOK_AFTER_CHANGE: - hook_var->hook_after_change = proc; - break; - case ICONSOLE_HOOK_ACCESS: - hook_var->hook_access = proc; - break; - case ICONSOLE_HOOK_BEFORE_EXEC: - case ICONSOLE_HOOK_AFTER_EXEC: - assert(0); - break; + char *value; + /* Some variables need really specific handling, handle this in its + * callback function */ + if (var->proc != NULL) { + var->proc(0, NULL); + return; } + + value = IConsoleVarGetStringValue(var); + IConsolePrintF(_iconsole_color_warning, "Current value for '%s' is: %s", var->name, value); } -bool IConsoleVarHookHandle(_iconsole_var* hook_var, _iconsole_hook_types type) +/** + * Print out the value of the variable after it has been assigned + * a new value, thus giving us feedback on the action + */ +void IConsoleVarPrintSetValue(const IConsoleVar *var) { - iconsole_var_hook proc; - if (hook_var == NULL) return false; + char *value = IConsoleVarGetStringValue(var); + IConsolePrintF(_iconsole_color_warning, "'%s' changed to: %s", var->name, value); +} - proc = NULL; - switch (type) { - case ICONSOLE_HOOK_BEFORE_CHANGE: - proc = hook_var->hook_before_change; - break; - case ICONSOLE_HOOK_AFTER_CHANGE: - proc = hook_var->hook_after_change; - break; - case ICONSOLE_HOOK_ACCESS: - proc = hook_var->hook_access; - break; - case ICONSOLE_HOOK_BEFORE_EXEC: - case ICONSOLE_HOOK_AFTER_EXEC: - assert(0); - break; +/** + * Execute a variable command. Without any parameters, print out its value + * with parameters it assigns a new value to the variable + * @param *var the variable that we will be querying/changing + * @param tokencount how many additional parameters have been given to the commandline + * @param *token the actual parameters the variable was called with + */ +void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[ICON_TOKEN_COUNT]) +{ + const char *tokenptr = token[0]; + byte t_index = tokencount; + uint32 value; + + if (tokencount == 0) { /* Just print out value */ + IConsoleVarPrintGetValue(var); + return; + } + + /* Use of assignment sign is not mandatory but supported, so just 'ignore it appropiately' */ + if (strcmp(tokenptr, "=") == 0) tokencount--; + + if (tokencount == 1) { + /* Some variables need really special handling, handle it in their callback procedure */ + if (var->proc != NULL) { + var->proc(tokencount, &token[t_index - tokencount]); // set the new value + var->proc(0, NULL); // print out new value + return; + } + /* Strings need special processing. No need to convert the argument to + * an integer value, just copy over the argument on a one-by-one basis */ + if (var->type == ICONSOLE_VAR_STRING) { + IConsoleVarSetStringvalue(var, token[t_index - tokencount]); + return; + } else if (GetArgumentInteger(&value, token[t_index - tokencount])) { + IConsoleVarSetValue(var, value); + return; + } + + /* Increase or decrease the value by one. This of course can only happen to 'number' types */ + if (strcmp(tokenptr, "++") == 0 && var->type != ICONSOLE_VAR_STRING) { + IConsoleVarSetValue(var, IConsoleVarGetValue(var) + 1); + return; + } + + if (strcmp(tokenptr, "--") == 0 && var->type != ICONSOLE_VAR_STRING) { + IConsoleVarSetValue(var, IConsoleVarGetValue(var) - 1); + return; + } } - return proc == NULL ? true : proc(hook_var); + + IConsoleError("invalid variable assignment"); } -void IConsoleCmdHook(const char* name, _iconsole_hook_types type, iconsole_cmd_hook proc) +// * ************************* * // +// * hooking code * // +// * ************************* * // +/** + * General internal hooking code that is the same for both commands and variables + * @param hooks @IConsoleHooks structure that will be set according to + * @param type type access trigger + * @param proc function called when the hook criteria is met + */ +static void IConsoleHookAdd(IConsoleHooks *hooks, IConsoleHookTypes type, IConsoleHook *proc) { - _iconsole_cmd* hook_cmd = IConsoleCmdGet(name); - if (hook_cmd == NULL) return; + if (hooks == NULL || proc == NULL) return; + switch (type) { - case ICONSOLE_HOOK_AFTER_EXEC: - hook_cmd->hook_after_exec = proc; - break; - case ICONSOLE_HOOK_BEFORE_EXEC: - hook_cmd->hook_before_exec = proc; - break; - case ICONSOLE_HOOK_ACCESS: - hook_cmd->hook_access = proc; - break; - case ICONSOLE_HOOK_BEFORE_CHANGE: - case ICONSOLE_HOOK_AFTER_CHANGE: - assert(0); - break; + case ICONSOLE_HOOK_ACCESS: + hooks->access = proc; + break; + case ICONSOLE_HOOK_PRE_ACTION: + hooks->pre = proc; + break; + case ICONSOLE_HOOK_POST_ACTION: + hooks->post = proc; + break; + default: NOT_REACHED(); } } -bool IConsoleCmdHookHandle(_iconsole_cmd* hook_cmd, _iconsole_hook_types type) +/** + * Handle any special hook triggers. If the hook type is met check if + * there is a function associated with that and if so, execute it + * @param hooks @IConsoleHooks structure that will be checked + * @param type type of hook, trigger that needs to be activated + * @return true on a successfull execution of the hook command or if there + * is no hook/trigger present at all. False otherwise + */ +static bool IConsoleHookHandle(IConsoleHooks *hooks, IConsoleHookTypes type) { - iconsole_cmd_hook proc = NULL; + IConsoleHook *proc = NULL; + if (hooks == NULL) return false; + switch (type) { - case ICONSOLE_HOOK_AFTER_EXEC: - proc = hook_cmd->hook_after_exec; - break; - case ICONSOLE_HOOK_BEFORE_EXEC: - proc = hook_cmd->hook_before_exec; - break; - case ICONSOLE_HOOK_ACCESS: - proc = hook_cmd->hook_access; - break; - case ICONSOLE_HOOK_BEFORE_CHANGE: - case ICONSOLE_HOOK_AFTER_CHANGE: - assert(0); - break; + case ICONSOLE_HOOK_ACCESS: + proc = hooks->access; + break; + case ICONSOLE_HOOK_PRE_ACTION: + proc = hooks->pre; + break; + case ICONSOLE_HOOK_POST_ACTION: + proc = hooks->post; + break; + default: NOT_REACHED(); } - return proc == NULL ? true : proc(hook_cmd); + + return (proc == NULL) ? true : proc(); } -void IConsoleCmdExec(const char* cmdstr) +/** + * Add a hook to a command that will be triggered at certain points + * @param name name of the command that the hook is added to + * @param type type of hook that is added (ACCESS, BEFORE and AFTER change) + * @param proc function called when the hook criteria is met + */ +void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc) { - _iconsole_cmd_addr function; - char* tokens[20]; - byte tokentypes[20]; - char* tokenstream; - char* tokenstream_s; - byte execution_mode; - _iconsole_var* var = NULL; - _iconsole_var* result = NULL; - _iconsole_cmd* cmd = NULL; - _iconsole_alias* alias = NULL; - - bool longtoken; - bool valid_token; - bool skip_lt_change; - - uint c; - uint i; - uint l; + IConsoleCmd *cmd = IConsoleCmdGet(name); + if (cmd == NULL) return; + IConsoleHookAdd(&cmd->hook, type, proc); +} - for (; strchr("\n\r \t", *cmdstr) != NULL; ++cmdstr) { - switch (*cmdstr) { - case '\0': - case '#': - return; +/** + * Add a hook to a variable that will be triggered at certain points + * @param name name of the variable that the hook is added to + * @param type type of hook that is added (ACCESS, BEFORE and AFTER change) + * @param proc function called when the hook criteria is met + */ +void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc) +{ + IConsoleVar *var = IConsoleVarGet(name); + if (var == NULL) return; + IConsoleHookAdd(&var->hook, type, proc); +} - default: - break; - } - } +/** + * Add a callback function to the variable. Some variables need + * very special processing, which can only be done with custom code + * @param name name of the variable the callback function is added to + * @param proc the function called + */ +void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc) +{ + IConsoleVar *var = IConsoleVarGet(name); + if (var == NULL) return; + var->proc = proc; +} - if (_stdlib_con_developer) - IConsolePrintF(_iconsole_color_debug, "CONDEBUG: execution_cmdline: %s", cmdstr); +/** + * Execute a given command passed to us. First chop it up into + * individual tokens (seperated by spaces), then execute it if possible + * @param cmdstr string to be parsed and executed + */ +void IConsoleCmdExec(const char *cmdstr) +{ + IConsoleCmd *cmd = NULL; + IConsoleAlias *alias = NULL; + IConsoleVar *var = NULL; - //** clearing buffer **// + const char *cmdptr; + char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE]; + uint t_index, tstream_i; - for (i = 0; i < 20; i++) { - tokens[i] = NULL; - tokentypes[i] = ICONSOLE_VAR_NONE; - } - tokenstream_s = tokenstream = malloc(1024); - memset(tokenstream, 0, 1024); - - //** parsing **// - - longtoken = false; - valid_token = false; - skip_lt_change = false; - l = strlen(cmdstr); - i = 0; - c = 0; - tokens[c] = tokenstream; - tokentypes[c] = ICONSOLE_VAR_UNKNOWN; - while (i < l && c < lengthof(tokens) - 1) { - if (cmdstr[i] == '"') { - if (longtoken) { - if (cmdstr[i + 1] == '"') { - i++; - *tokenstream = '"'; - tokenstream++; - skip_lt_change = true; - } else { - longtoken = !longtoken; - tokentypes[c] = ICONSOLE_VAR_STRING; - } - } else { - longtoken = !longtoken; - tokentypes[c] = ICONSOLE_VAR_STRING; - } - if (!skip_lt_change) { - if (!longtoken) { - if (valid_token) { - c++; - *tokenstream = '\0'; - tokenstream++; - tokens[c] = tokenstream; - tokentypes[c] = ICONSOLE_VAR_UNKNOWN; - valid_token = false; - } - } - skip_lt_change=false; - } - } else if (!longtoken && cmdstr[i] == ' ') { - if (valid_token) { - c++; - *tokenstream = '\0'; - tokenstream++; - tokens[c] = tokenstream; - tokentypes[c] = ICONSOLE_VAR_UNKNOWN; - valid_token = false; - } - } else { - valid_token = true; - *tokenstream = cmdstr[i]; - tokenstream++; + bool longtoken = false; + bool foundtoken = false; + + for (cmdptr = cmdstr; *cmdptr != '\0'; *cmdptr++) { + if (!IsValidAsciiChar(*cmdptr)) { + IConsoleError("command contains malformed characters, aborting"); + return; } - i++; } - tokenstream--; - if (*tokenstream != '\0') { - c++; - tokenstream++; - *tokenstream = '\0'; - } + if (_stdlib_con_developer) + IConsolePrintF(_iconsole_color_debug, "condbg: executing cmdline: '%s'", cmdstr); - //** interpreting **// - - for (i = 0; i < c; i++) { - if (tokens[i] != NULL && i > 0 && strlen(tokens[i]) > 0) { - if (IConsoleVarGet((char *)tokens[i]) != NULL) { - // change the variable to an pointer if execution_mode != 4 is - // being prepared. execution_mode 4 is used to assign - // one variables data to another one - // [token 0 and 2] - if (!((i == 2) && (tokentypes[1] == ICONSOLE_VAR_UNKNOWN) && - (strcmp(tokens[1], "<<") == 0))) { - // only look for another variable if it isnt an longtoken == string with "" - var = NULL; - if (tokentypes[i]!=ICONSOLE_VAR_STRING) var = IConsoleVarGet(tokens[i]); - if (var != NULL) { - // pointer to the data --> token - tokens[i] = (char *) var->data.addr; /* XXX: maybe someone finds an cleaner way to do this */ - tokentypes[i] = var->type; - } - } - } - if (tokens[i] != NULL && tokens[i][0] == '@' && (IConsoleVarGet(tokens[i]+1) != NULL)) { - var = IConsoleVarGet(tokens[i]+1); - if (var != NULL) { - // pointer to the _iconsole_var struct --> token - tokens[i] = (char *) var; /* XXX: maybe someone finds an cleaner way to do this */ - tokentypes[i] = ICONSOLE_VAR_REFERENCE; - } - } - } - } + memset(&tokens, 0, sizeof(tokens)); + memset(&tokenstream, 0, sizeof(tokenstream)); - execution_mode=0; + /* 1. Split up commandline into tokens, seperated by spaces, commands + * enclosed in "" are taken as one token. We can only go as far as the amount + * of characters in our stream or the max amount of tokens we can handle */ + tokens[0] = tokenstream; + for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; *cmdptr++) { + if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break; - function = NULL; - cmd = IConsoleCmdGet(tokens[0]); - if (cmd != NULL) { - function = cmd->addr; - } else { - alias = IConsoleAliasGet(tokens[0]); - if (alias != NULL) execution_mode = 5; // alias handling - } + switch (*cmdptr) { + case ' ': /* Token seperator */ + if (!foundtoken) break; - if (function != NULL) { - execution_mode = 1; // this is a command - } else { - var = IConsoleVarGet(tokens[0]); - if (var != NULL) { - execution_mode = 2; // this is a variable - if (c > 2 && strcmp(tokens[1], "<<") == 0) { - // this is command to variable mode [normal] - - function = NULL; - cmd = IConsoleCmdGet(tokens[2]); - if (cmd != NULL) function = cmd->addr; - - if (function != NULL) { - execution_mode = 3; - } else { - result = IConsoleVarGet(tokens[2]); - if (result != NULL) - execution_mode = 4; - } - } - } - } + tokenstream[tstream_i] = (longtoken) ? *cmdptr : '\0'; - //** executing **// - if (_stdlib_con_developer) - IConsolePrintF(_iconsole_color_debug, "CONDEBUG: execution_mode: %i", - execution_mode); - switch (execution_mode) { - case 0: - // not found - IConsoleError("command or variable not found"); + tstream_i++; + foundtoken = false; break; - case 1: - if (IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_ACCESS)) { - // execution with command syntax - IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_BEFORE_EXEC); - result = function(c, tokens, tokentypes); - if (result != NULL) { - IConsoleVarDump(result, "result"); - IConsoleVarFree(result); - } - IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_AFTER_EXEC); - break; - } - case 2: - { - // execution with variable syntax - if (IConsoleVarHookHandle(var, ICONSOLE_HOOK_ACCESS) && (c == 2 || c == 3)) { - // ** variable modifications ** // - IConsoleVarHookHandle(var, ICONSOLE_HOOK_BEFORE_CHANGE); - switch (var->type) { - case ICONSOLE_VAR_BOOLEAN: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) { - *var->data.bool_ = (atoi(tokens[2]) != 0); - } else { - *var->data.bool_ = false; - } - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - *var->data.bool_ = true; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--") == 0) { - *var->data.bool_ = false; - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_BYTE: - case ICONSOLE_VAR_UINT8: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) - *var->data.byte_ = atoi(tokens[2]); - else - *var->data.byte_ = 0; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - ++*var->data.byte_; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--")==0) { - --*var->data.byte_; - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_UINT16: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) - *var->data.uint16_ = atoi(tokens[2]); - else - *var->data.uint16_ = 0; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - ++*var->data.uint16_; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--") == 0) { - --*var->data.uint16_; - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_UINT32: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) - *var->data.uint32_ = atoi(tokens[2]); - else - *var->data.uint32_ = 0; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - ++*var->data.uint32_; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--") == 0) { - --*var->data.uint32_; - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_INT16: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) - *var->data.int16_ = atoi(tokens[2]); - else - *var->data.int16_ = 0; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - ++*var->data.int16_; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--") == 0) { - --*var->data.int16_; - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_INT32: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) - *var->data.int32_ = atoi(tokens[2]); - else - *var->data.int32_ = 0; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - ++*var->data.int32_; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--") == 0) { - --*var->data.int32_; - IConsoleVarDump(var, NULL); - } - else { IConsoleError("operation not supported"); } - break; - } - case ICONSOLE_VAR_STRING: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) - IConsoleVarSetString(var, tokens[2]); - else - IConsoleVarSetString(var, ""); - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_POINTER: - { - if (strcmp(tokens[1], "=") == 0) { - if (c == 3) { - if (tokentypes[2] == ICONSOLE_VAR_UNKNOWN) - var->data.addr = (void*)atoi(tokens[2]); /* direct access on memory [by address] */ - else - var->data.addr = (void*)tokens[2]; /* direct acces on memory [by variable] */ - } else - var->data.addr = NULL; - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "++") == 0) { - ++*(char*)&var->data.addr; /* change the address + 1 */ - IConsoleVarDump(var, NULL); - } else if (strcmp(tokens[1], "--") == 0) { - --*(char*)&var->data.addr; /* change the address - 1 */ - IConsoleVarDump(var, NULL); - } - else - IConsoleError("operation not supported"); - break; - } - case ICONSOLE_VAR_NONE: - case ICONSOLE_VAR_REFERENCE: - case ICONSOLE_VAR_UNKNOWN: - IConsoleError("operation not supported"); - break; - } - IConsoleVarHookHandle(var, ICONSOLE_HOOK_AFTER_CHANGE); - } - if (c == 1) // ** variable output ** // - IConsoleVarDump(var, NULL); + case '"': /* Tokens enclosed in "" are one token */ + longtoken = !longtoken; break; - } - case 3: - case 4: - { - // execute command with result or assign a variable - if (execution_mode == 3) { - if (IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_ACCESS)) { - int i; - int diff; - void* temp; - byte temp2; - - // tokenshifting - for (diff = 0; diff < 2; diff++) { - temp = tokens[0]; - temp2 = tokentypes[0]; - for (i = 0; i < 19; i++) { - tokens[i] = tokens[i + 1]; - tokentypes[i] = tokentypes[i + 1]; - } - tokens[19] = temp; - tokentypes[19] = temp2; - } - IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_BEFORE_EXEC); - result = function(c, tokens, tokentypes); - IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_AFTER_EXEC); - } else - execution_mode = 255; - } - - if (IConsoleVarHookHandle(var, ICONSOLE_HOOK_ACCESS) && result != NULL) { - if (result->type != var->type) { - IConsoleError("variable type missmatch"); - } else { - IConsoleVarHookHandle(var, ICONSOLE_HOOK_BEFORE_CHANGE); - switch (result->type) { - case ICONSOLE_VAR_BOOLEAN: - *var->data.bool_ = *result->data.bool_; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_BYTE: - case ICONSOLE_VAR_UINT8: - *var->data.byte_ = *result->data.byte_; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_UINT16: - *var->data.uint16_ = *result->data.uint16_; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_UINT32: - *var->data.uint32_ = *result->data.uint32_; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_INT16: - *var->data.int16_ = *result->data.int16_; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_INT32: - *var->data.int32_ = *result->data.int32_; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_POINTER: - var->data.addr = result->data.addr; - IConsoleVarDump(var, NULL); - break; - case ICONSOLE_VAR_STRING: - IConsoleVarSetString(var, result->data.string_); - IConsoleVarDump(var, NULL); - break; - default: - IConsoleError("variable type missmatch"); - break; - } - IConsoleVarHookHandle(var, ICONSOLE_HOOK_AFTER_CHANGE); - } + default: /* Normal character */ + tokenstream[tstream_i++] = *cmdptr; - if (execution_mode == 3) { - IConsoleVarFree(result); - } + if (!foundtoken) { + tokens[t_index++] = &tokenstream[tstream_i - 1]; + foundtoken = true; } break; } - case 5: { - // execute an alias - IConsoleAliasExec(alias->cmdline, tokens,tokentypes); - } - break; - default: - // execution mode invalid - IConsoleError("invalid execution mode"); - break; } - //** freeing the tokenstream **// - free(tokenstream_s); + if (_stdlib_con_developer) { + uint i; + for (i = 0; tokens[i] != NULL; i++) + IConsolePrintF(_iconsole_color_debug, "condbg: token %d is: '%s'", i, tokens[i]); + } + + /* 2. Determine type of command (cmd, alias or variable) and execute + * First try commands, then aliases, and finally variables. Execute + * the found action taking into account its hooking code + */ + cmd = IConsoleCmdGet(tokens[0]); + if (cmd != NULL) { + if (IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_ACCESS)) { + IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_PRE_ACTION); + if (cmd->proc(t_index, tokens)) { // index started with 0 + IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_POST_ACTION); + } else cmd->proc(0, NULL); // if command failed, give help + } + return; + } + + t_index--; // ignore the variable-name for comfort for both aliases and variaables + alias = IConsoleAliasGet(tokens[0]); + if (alias != NULL) { + IConsoleAliasExec(alias, t_index, &tokens[1]); + return; + } + + var = IConsoleVarGet(tokens[0]); + if (var != NULL) { + if (IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_ACCESS)) { + IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION); + IConsoleVarExec(var, t_index, &tokens[1]); + if (t_index != 0) // value has indeed been changed + IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION); + } + return; + } + + IConsoleError("command or variable not found"); } @@ -1,108 +1,118 @@ #ifndef CONSOLE_H #define CONSOLE_H -// ** console parser ** // +// maximum length of a typed in command +#define ICON_CMDLN_SIZE 255 +// maximum length of a totally expanded command +#define ICON_MAX_STREAMSIZE 1024 -typedef enum _iconsole_var_types { - ICONSOLE_VAR_NONE, +typedef enum IConsoleVarTypes { ICONSOLE_VAR_BOOLEAN, ICONSOLE_VAR_BYTE, - ICONSOLE_VAR_UINT8, ICONSOLE_VAR_UINT16, ICONSOLE_VAR_UINT32, ICONSOLE_VAR_INT16, ICONSOLE_VAR_INT32, - ICONSOLE_VAR_STRING, - ICONSOLE_VAR_POINTER, - ICONSOLE_VAR_REFERENCE, - ICONSOLE_VAR_UNKNOWN -} _iconsole_var_types; + ICONSOLE_VAR_STRING +} IConsoleVarTypes; -typedef enum { +typedef enum IConsoleModes { ICONSOLE_FULL, ICONSOLE_OPENED, ICONSOLE_CLOSED -} _iconsole_modes; +} IConsoleModes; -typedef enum _iconsole_hook_types { +typedef enum IConsoleHookTypes { ICONSOLE_HOOK_ACCESS, - ICONSOLE_HOOK_BEFORE_CHANGE, - ICONSOLE_HOOK_BEFORE_EXEC, - ICONSOLE_HOOK_AFTER_CHANGE, - ICONSOLE_HOOK_AFTER_EXEC -} _iconsole_hook_types; - -struct _iconsole_var; -typedef bool (*iconsole_var_hook)(struct _iconsole_var* hook_var); - -typedef struct _iconsole_var { - // --------------- // - union { - void* addr; - bool* bool_; - byte* byte_; - uint16* uint16_; - uint32* uint32_; - int16* int16_; - int32* int32_; - char* string_; - struct _iconsole_var* reference_; - } data; - char* name; - _iconsole_var_types type; - // -------------- // - iconsole_var_hook hook_access; - iconsole_var_hook hook_before_change; - iconsole_var_hook hook_after_change; - // -------------- // - struct _iconsole_var* _next; - bool _malloc; -} _iconsole_var; - -struct _iconsole_cmd; -typedef bool (*iconsole_cmd_hook)(struct _iconsole_cmd* hook_cmd); - -typedef _iconsole_var* (*_iconsole_cmd_addr)(byte argc, char* argv[], byte argt[]); - -typedef struct _iconsole_cmd { - // -------------- // - _iconsole_cmd_addr addr; - char* name; - // -------------- // - iconsole_cmd_hook hook_access; - iconsole_cmd_hook hook_before_exec; - iconsole_cmd_hook hook_after_exec; - // -------------- // - void* _next; -} _iconsole_cmd; - -void IConsoleAliasRegister(const char* name, const char* cmdline); - -typedef struct _iconsole_alias { - // -------------- // - char * cmdline; - char* name; - void* _next; -} _iconsole_alias; - -_iconsole_alias* IConsoleAliasGet(const char* name); + ICONSOLE_HOOK_PRE_ACTION, + ICONSOLE_HOOK_POST_ACTION +} IConsoleHookTypes; + +/** --Hooks-- + * Hooks are certain triggers get get accessed/executed on either + * access, before execution/change or after execution/change. This allows + * for general flow of permissions or special action needed in some cases + */ +typedef bool IConsoleHook(void); +typedef struct IConsoleHooks{ + IConsoleHook *access; // trigger when accessing the variable/command + IConsoleHook *pre; // trigger before the variable/command is changed/executed + IConsoleHook *post; // trigger after the variable/command is changed/executed +} IConsoleHooks; + +/** --Commands-- + * Commands are commands, or functions. They get executed once and any + * effect they produce are carried out. The arguments to the commands + * are given to them, each input word seperated by a double-quote (") is an argument + * If you want to handle multiple words as one, enclose them in double-quotes + * eg. 'say "hello sexy boy"' + */ +typedef bool (IConsoleCmdProc)(byte argc, char *argv[]); + +struct IConsoleCmd; +typedef struct IConsoleCmd { + char *name; // name of command + struct IConsoleCmd *next; // next command in list + + IConsoleCmdProc *proc; // process executed when command is typed + IConsoleHooks hook; // any special trigger action that needs executing +} IConsoleCmd; + +/** --Variables-- + * Variables are pointers to real ingame variables which allow for + * changing while ingame. After changing they keep their new value + * and can be used for debugging, gameplay, etc. It accepts: + * - no arguments; just print out current value + * - '= <new value>' to assign a new value to the variable + * - '++' to increase value by one + * - '--' to decrease value by one + */ +struct IConsoleVar; +typedef struct IConsoleVar { + char *name; // name of the variable + struct IConsoleVar *next; // next variable in list + + void *addr; // the address where the variable is pointing at + uint32 size; // size of the variable, used for strings + char *help; // the optional help string shown when requesting information + IConsoleVarTypes type; // type of variable (for correct assignment/output) + IConsoleCmdProc *proc; // some variables need really special handling, use a callback function for that + IConsoleHooks hook; // any special trigger action that needs executing +} IConsoleVar; + +/** --Aliases-- + * Aliases are like shortcuts for complex functions, variable assignments, + * etc. You can use a simple alias to rename a longer command (eg 'lv' for + * 'list_vars' for example), or concatenate more commands into one + * (eg. 'ng' for 'load %A; unpause; debug_level 5'). Aliases can parse the arguments + * given to them in the command line. + * - "%A - %Z" substitute arguments 1 t/m 26 + * - "%+" lists all parameters keeping them seperated + * - "%!" also lists all parameters but presenting them to the aliased command as one argument + * - ";" allows for combining commands (see example 'ng') + */ +struct IConsoleAlias; +typedef struct IConsoleAlias { + char *name; // name of the alias + struct IConsoleAlias *next; // next alias in list + + char *cmdline; // command(s) that is/are being aliased +} IConsoleAlias; // ** console parser ** // +IConsoleCmd *_iconsole_cmds; // list of registred commands +IConsoleVar *_iconsole_vars; // list of registred vars +IConsoleAlias *_iconsole_aliases; // list of registred aliases -_iconsole_cmd* _iconsole_cmds; // list of registred commands -_iconsole_var* _iconsole_vars; // list of registred vars -_iconsole_alias* _iconsole_aliases; // list of registred aliases - -// ** console colors ** // +// ** console colors/modes ** // VARDEF byte _iconsole_color_default; VARDEF byte _iconsole_color_error; VARDEF byte _iconsole_color_warning; VARDEF byte _iconsole_color_debug; VARDEF byte _iconsole_color_commands; -VARDEF _iconsole_modes _iconsole_mode; +VARDEF IConsoleModes _iconsole_mode; // ** console functions ** // - void IConsoleInit(void); void IConsoleClear(void); void IConsoleFree(void); @@ -112,44 +122,42 @@ void IConsoleClose(void); void IConsoleOpen(void); // ** console cmd buffer ** // -void IConsoleCmdBufferAdd(const char* cmd); -void IConsoleCmdBufferNavigate(signed char direction); +void IConsoleHistoryAdd(const char *cmd); +void IConsoleHistoryNavigate(signed char direction); // ** console output ** // -void IConsolePrint(uint16 color_code, const char* string); -void CDECL IConsolePrintF(uint16 color_code, const char* s, ...); -void IConsoleDebug(const char* string); -void IConsoleError(const char* string); -void IConsoleWarning(const char* string); +void IConsolePrint(uint16 color_code, const char *string); +void CDECL IConsolePrintF(uint16 color_code, const char *s, ...); +void IConsoleDebug(const char *string); +void IConsoleWarning(const char *string); +void IConsoleError(const char *string); // *** Commands *** // - -void IConsoleCmdRegister(const char* name, _iconsole_cmd_addr addr); -_iconsole_cmd* IConsoleCmdGet(const char* name); +void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc); +void IConsoleAliasRegister(const char *name, const char *cmd); +IConsoleCmd *IConsoleCmdGet(const char *name); +IConsoleAlias *IConsoleAliasGet(const char *name); // *** Variables *** // - -void IConsoleVarRegister(const char* name, void* addr, _iconsole_var_types type); -void IConsoleVarMemRegister(const char* name, _iconsole_var_types type); -void IConsoleVarInsert(_iconsole_var* item_new, const char* name); -_iconsole_var* IConsoleVarGet(const char* name); -_iconsole_var* IConsoleVarAlloc(_iconsole_var_types type); -void IConsoleVarFree(_iconsole_var* var); -void IConsoleVarSetString(_iconsole_var* var, const char* string); -void IConsoleVarSetValue(_iconsole_var* var, int value); -void IConsoleVarDump(const _iconsole_var* var, const char* dump_desc); +void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help); +void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help); +IConsoleVar* IConsoleVarGet(const char *name); +void IConsoleVarPrintGetValue(const IConsoleVar *var); +void IConsoleVarPrintSetValue(const IConsoleVar *var); // *** Parser *** // +void IConsoleCmdExec(const char *cmdstr); +void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[]); +void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[]); -void IConsoleCmdExec(const char* cmdstr); - -// ** console std lib ** // +// ** console std lib (register ingame commands/aliases/variables) ** // void IConsoleStdLibRegister(void); -// ** hook code ** // -void IConsoleVarHook(const char* name, _iconsole_hook_types type, iconsole_var_hook proc); -void IConsoleCmdHook(const char* name, _iconsole_hook_types type, iconsole_cmd_hook proc); -bool IConsoleVarHookHandle(_iconsole_var* hook_var, _iconsole_hook_types type); -bool IConsoleCmdHookHandle(_iconsole_cmd* hook_cmd, _iconsole_hook_types type); +// ** Hooking code ** // +void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc); +void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc); +void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc); +// ** Supporting functions **// +bool GetArgumentInteger(uint32 *value, const char *arg); #endif /* CONSOLE_H */ diff --git a/console_cmds.c b/console_cmds.c index 88b7bb3c2..d0c316777 100644 --- a/console_cmds.c +++ b/console_cmds.c @@ -1,4 +1,3 @@ -/* -------------------- dont cross this line --------------------- */ #include "stdafx.h" #include "ttd.h" #include "console.h" @@ -15,93 +14,67 @@ #include "settings.h" #include "hal.h" /* for file list */ - // ** scriptfile handling ** // -static FILE * _script_file; +static FILE *_script_file; static bool _script_running; // ** console command / variable defines ** // - -#define DEF_CONSOLE_CMD(yyyy) static _iconsole_var * yyyy(byte argc, char* argv[], byte argt[]) -#define DEF_CONSOLE_CMD_HOOK(yyyy) static bool yyyy(_iconsole_cmd * hookcmd) -#define DEF_CONSOLE_VAR_HOOK(yyyy) static bool yyyy(_iconsole_var * hookvar) +#define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[]) +#define DEF_CONSOLE_HOOK(function) static bool function(void) -// ** supporting functions ** // - -static uint32 GetArgumentInteger(const char* arg) -{ - uint32 result; - sscanf(arg, "%u", &result); - - if (result == 0 && arg[0] == '0' && arg[1] == 'x') - sscanf(arg, "%x", &result); - - return result; -} - /* **************************** */ /* variable and command hooks */ /* **************************** */ #ifdef ENABLE_NETWORK -DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetwork) +static inline bool NetworkAvailable(void) { - if (_networking) { - IConsoleError("This command is forbidden in multiplayer."); + if (!_network_available) { + IConsoleError("You cannot use this command because there is no network available."); return false; } return true; } -DEF_CONSOLE_VAR_HOOK(ConVarHookNoNetClient) +DEF_CONSOLE_HOOK(ConHookServerOnly) { - if (!_network_available) { - IConsoleError("You can not use this command because there is no network available."); - return false; - } + if (!NetworkAvailable()) return false; + if (!_network_server) { - IConsoleError("This variable only makes sense for a network server."); + IConsoleError("This variable is only available to a network server."); return false; } return true; } -DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetClient) +DEF_CONSOLE_HOOK(ConHookClientOnly) { - if (!_network_available) { - IConsoleError("You can not use this command because there is no network available."); - return false; - } - if (!_network_server) { - IConsoleError("This command is only available for a network server."); + if (!NetworkAvailable()) return false; + + if (_network_server) { + IConsoleError("This command is not available to a network server."); return false; } return true; } -DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetServer) +DEF_CONSOLE_HOOK(ConHookNeedNetwork) { - if (!_network_available) { - IConsoleError("You can not use this command because there is no network available."); - return false; - } - if (_network_server) { - IConsoleError("You can not use this command because you are a network-server."); + if (!NetworkAvailable()) return false; + + if (!_networking) { + IConsoleError("Not connected. This command is only available in multiplayer."); return false; } return true; } -DEF_CONSOLE_CMD_HOOK(ConCmdHookNeedNetwork) +DEF_CONSOLE_HOOK(ConHookNoNetwork) { - if (!_network_available) { - IConsoleError("You can not use this command because there is no network available."); - return false; - } - if (!_networking) { - IConsoleError("Not connected. Multiplayer only command."); + if (_networking) { + IConsoleError("This command is forbidden in multiplayer."); return false; } return true; @@ -109,72 +82,90 @@ DEF_CONSOLE_CMD_HOOK(ConCmdHookNeedNetwork) #endif /* ENABLE_NETWORK */ -/* **************************** */ -/* reset commands */ -/* **************************** */ +static void IConsoleHelp(const char *str) +{ + IConsolePrintF(_iconsole_color_warning, "- %s", str); +} DEF_CONSOLE_CMD(ConResetEngines) { + if (argc == 0) { + IConsoleHelp("Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'"); + return true; + } + StartupEngines(); - return 0; + return true; } #ifdef _DEBUG DEF_CONSOLE_CMD(ConResetTile) { + if (argc == 0) { + IConsoleHelp("Reset a tile to bare land. Usage: 'resettile <tile>'"); + IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)"); + return true; + } + if (argc == 2) { - TileIndex tile = (TileIndex)GetArgumentInteger(argv[1]); - DoClearSquare(tile); + uint32 result; + if (GetArgumentInteger(&result, argv[1])) { + DoClearSquare((TileIndex)result); + return true; + } } - return 0; + return false; } -#endif DEF_CONSOLE_CMD(ConScrollToTile) { + if (argc == 0) { + IConsoleHelp("Center the screen on a given tile. Usage: 'scrollto <tile>'"); + IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)"); + return true; + } + if (argc == 2) { - TileIndex tile = (TileIndex)GetArgumentInteger(argv[1]); - ScrollMainWindowToTile(tile); + uint32 result; + if (GetArgumentInteger(&result, argv[1])) { + ScrollMainWindowToTile((TileIndex)result); + return true; + } } - return 0; + return false; } +#endif /* _DEBUG */ extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm); extern void BuildFileList(void); extern void SetFiosType(const byte fiostype); -/* Save the map to current dir */ -static void SaveMap(const char *filename) -{ - char buf[200]; - - snprintf(buf, lengthof(buf), "%s%s%s.sav", _path.save_dir, PATHSEP, filename); - IConsolePrint(_iconsole_color_default, "Saving map..."); - - if (SaveOrLoad(buf, SL_SAVE) != SL_OK) { - IConsolePrint(_iconsole_color_error, "SaveMap failed"); - } else - IConsolePrintF(_iconsole_color_default, "Map sucessfully saved to %s", buf); -} - /* Save the map to a file */ DEF_CONSOLE_CMD(ConSave) { - /* We need 1 argument */ + if (argc == 0) { + IConsoleHelp("Save the current game. Usage: 'save <filename>'"); + return true; + } + if (argc == 2) { - /* Save the map */ - SaveMap(argv[1]); - return NULL; + char buf[200]; + + snprintf(buf, lengthof(buf), "%s%s%s.sav", _path.save_dir, PATHSEP, argv[1]); + IConsolePrint(_iconsole_color_default, "Saving map..."); + + if (SaveOrLoad(buf, SL_SAVE) != SL_OK) { + IConsolePrint(_iconsole_color_error, "SaveMap failed"); + } else + IConsolePrintF(_iconsole_color_default, "Map sucessfully saved to %s", buf); + return true; } - /* Give usage */ - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: save <filename>"); - return NULL; + return false; } - static const FiosItem* GetFiosItem(const char* file) { int i; @@ -198,104 +189,101 @@ static const FiosItem* GetFiosItem(const char* file) DEF_CONSOLE_CMD(ConLoad) { - const FiosItem* item; - const char* file; + const FiosItem *item; + const char *file; - if (argc != 2) { - IConsolePrint(_iconsole_color_default, "Usage: load <file | number>"); - return NULL; + if (argc == 0) { + IConsoleHelp("Load a game by name or index. Usage: 'load <file | number>'"); + return true; } + if (argc != 2) return false; + file = argv[1]; item = GetFiosItem(file); if (item != NULL) { switch (item->type) { - case FIOS_TYPE_FILE: - case FIOS_TYPE_OLDFILE: + case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: _switch_mode = SM_LOAD; SetFiosType(item->type); strcpy(_file_to_saveload.name, FiosBrowseTo(item)); break; - - default: - IConsolePrintF(_iconsole_color_error, "%s: Not a map.", file); - break; + default: IConsolePrintF(_iconsole_color_error, "%s: Not a savegame.", file); } - } else { - IConsolePrintF(_iconsole_color_error, "%s: No such file or directory.", - file); - } + } else + IConsolePrintF(_iconsole_color_error, "%s: No such file or directory.", file); FiosFreeSavegameList(); - return NULL; + return true; } - /* List all the files in the current dir via console */ DEF_CONSOLE_CMD(ConListFiles) { int i; + if (argc == 0) { + IConsoleHelp("List all the files in the current dir via console. Usage: 'ls | dir'"); + return true; + } + BuildFileList(); for (i = 0; i < _fios_num; i++) { - const FiosItem* item = &_fios_list[i]; - - IConsolePrintF(_iconsole_color_default, "%d) %s", - i, item->title[0] != '\0' ? item->title : item->name); + const FiosItem *item = &_fios_list[i]; + IConsolePrintF(_iconsole_color_default, "%d) %s", i, (item->title[0] != '\0') ? item->title : item->name); } FiosFreeSavegameList(); - return NULL; + return true; } - /* Change the dir via console */ DEF_CONSOLE_CMD(ConChangeDirectory) { - const FiosItem* item; - const char* file; + const FiosItem *item; + const char *file; - if (argc != 2) { - IConsolePrint(_iconsole_color_default, "Usage: cd <directory | number>"); - return NULL; + if (argc == 0) { + IConsoleHelp("Change the dir via console. Usage: 'cd <directory | number>'"); + return true; } + if (argc != 2) return false; + file = argv[1]; item = GetFiosItem(file); if (item != NULL) { switch (item->type) { - case FIOS_TYPE_DIR: - case FIOS_TYPE_DRIVE: - case FIOS_TYPE_PARENT: + case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT: FiosBrowseTo(item); break; - - default: - IConsolePrintF(_iconsole_color_error, "%s: Not a directory.", file); - break; + default: IConsolePrintF(_iconsole_color_error, "%s: Not a directory.", file); } - } else { - IConsolePrintF(_iconsole_color_error, "%s: No such file or directory.", - file); - } + } else + IConsolePrintF(_iconsole_color_error, "%s: No such file or directory.", file); FiosFreeSavegameList(); - return NULL; + return true; } DEF_CONSOLE_CMD(ConPrintWorkingDirectory) { - const char* path; + const char *path; + + if (argc == 0) { + IConsoleHelp("Print out the current working directory. Usage: 'pwd'"); + return true; + } - // XXX Workaround for broken file handling + // XXX - Workaround for broken file handling FiosGetSavegameList(&_fios_num, SLD_LOAD_GAME); FiosFreeSavegameList(); FiosGetDescText(&path, NULL); IConsolePrint(_iconsole_color_default, path); - return NULL; + return true; } @@ -307,72 +295,81 @@ DEF_CONSOLE_CMD(ConPrintWorkingDirectory) DEF_CONSOLE_CMD(ConBan) { NetworkClientInfo *ci; + uint32 index; - if (argc == 2) { - uint32 index = atoi(argv[1]); - if (index == NETWORK_SERVER_INDEX) { - IConsolePrint(_iconsole_color_default, "Silly boy, you can not ban yourself!"); - return NULL; - } - if (index == 0) { - IConsoleError("Invalid Client-ID"); - return NULL; - } + if (argc == 0) { + IConsoleHelp("Ban a player from a network game. Usage: 'ban <client-id>'"); + IConsoleHelp("For client-id's, see the command 'clients'"); + return true; + } - ci = NetworkFindClientInfoFromIndex(index); + if (argc != 2) return false; - if (ci != NULL) { - uint i; - /* Add user to ban-list */ - for (i = 0; i < lengthof(_network_ban_list); i++) { - if (_network_ban_list[i] == NULL || _network_ban_list[i][0] == '\0') { - _network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ci->client_ip)); - break; - } - } + index = atoi(argv[1]); - SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED); - return NULL; - } else { - IConsoleError("Client-ID not found"); - return NULL; - } + if (index == NETWORK_SERVER_INDEX) { + IConsolePrint(_iconsole_color_default, "Silly boy, you can not ban yourself!"); + return true; + } + if (index == 0) { + IConsoleError("Invalid Client-ID"); + return true; } - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: ban <client-id>. For client-ids, see 'clients'."); - - return NULL; -} + ci = NetworkFindClientInfoFromIndex(index); -DEF_CONSOLE_CMD(ConUnBan) -{ - if (argc == 2) { + if (ci != NULL) { uint i; + /* Add user to ban-list */ for (i = 0; i < lengthof(_network_ban_list); i++) { - if (_network_ban_list[i] == NULL || _network_ban_list[i][0] == '\0') - continue; - - if (strncmp(_network_ban_list[i], argv[1], strlen(_network_ban_list[i])) == 0) { - _network_ban_list[i][0] = '\0'; - IConsolePrint(_iconsole_color_default, "IP unbanned."); - return NULL; + if (_network_ban_list[i] == NULL || _network_ban_list[i][0] == '\0') { + _network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ci->client_ip)); + break; } } - IConsolePrint(_iconsole_color_default, "IP not in ban-list."); + SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED); + } else + IConsoleError("Client-ID not found"); - return NULL; + return true; +} + +DEF_CONSOLE_CMD(ConUnBan) +{ + uint i; + + if (argc == 0) { + IConsoleHelp("Unban a player from a network game. Usage: 'unban <ip>'"); + return true; } - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: unban <ip>."); + if (argc != 2) return false; + + for (i = 0; i < lengthof(_network_ban_list); i++) { + if (_network_ban_list[i] == NULL || _network_ban_list[i][0] == '\0') + continue; + + if (strncmp(_network_ban_list[i], argv[1], strlen(_network_ban_list[i])) == 0) { + _network_ban_list[i][0] = '\0'; + IConsolePrint(_iconsole_color_default, "IP unbanned."); + return true; + } + } - return NULL; + IConsolePrint(_iconsole_color_default, "IP not in ban-list."); + return true; } DEF_CONSOLE_CMD(ConBanList) { uint i; + if (argc == 0) { + IConsoleHelp("List the IP's of banned clients: Usage 'banlist'"); + return true; + } + IConsolePrint(_iconsole_color_default, "Banlist: "); for (i = 0; i < lengthof(_network_ban_list); i++) { @@ -382,115 +379,109 @@ DEF_CONSOLE_CMD(ConBanList) IConsolePrintF(_iconsole_color_default, " %d) %s", i + 1, _network_ban_list[i]); } - return NULL; + return true; } DEF_CONSOLE_CMD(ConPauseGame) { + if (argc == 0) { + IConsoleHelp("Pause a network game. Usage: 'pause'"); + return true; + } + if (_pause == 0) { DoCommandP(0, 1, 0, NULL, CMD_PAUSE); IConsolePrint(_iconsole_color_default, "Game paused."); } else IConsolePrint(_iconsole_color_default, "Game is already paused."); - return NULL; + return true; } DEF_CONSOLE_CMD(ConUnPauseGame) { + if (argc == 0) { + IConsoleHelp("Unpause a network game. Usage: 'unpause'"); + return true; + } + if (_pause != 0) { DoCommandP(0, 0, 0, NULL, CMD_PAUSE); IConsolePrint(_iconsole_color_default, "Game unpaused."); } else IConsolePrint(_iconsole_color_default, "Game is already unpaused."); - return NULL; + return true; } DEF_CONSOLE_CMD(ConRcon) { - if (argc < 3) { - IConsolePrint(_iconsole_color_default, "Usage: rcon <password> <command>"); - return NULL; + if (argc == 0) { + IConsoleHelp("Remote control the server from another client. Usage: 'rcon <password> <command>'"); + IConsoleHelp("Remember to enclose the command in quotes, otherwise only the first parameter is sent"); + return true; } - SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]); + if (argc < 3) return false; - return NULL; + SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]); + return true; } DEF_CONSOLE_CMD(ConStatus) { + static const char *stat_str[] = {"inactive", "authorized", "waiting", "loading map", "map done", "ready", "active"}; const char *status; - int lag; const NetworkClientState *cs; - const NetworkClientInfo *ci; + + if (argc == 0) { + IConsoleHelp("List the status of all clients connected to the server: Usage 'status'"); + return true; + } + FOR_ALL_CLIENTS(cs) { - lag = NetworkCalculateLag(cs); - ci = DEREF_CLIENT_INFO(cs); + int lag = NetworkCalculateLag(cs); + const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); - switch (cs->status) { - case STATUS_INACTIVE: - status = "inactive"; - break; - case STATUS_AUTH: - status = "authorized"; - break; - case STATUS_MAP_WAIT: - status = "waiting"; - break; - case STATUS_MAP: - status = "loading map"; - break; - case STATUS_DONE_MAP: - status = "done map"; - break; - case STATUS_PRE_ACTIVE: - status = "ready"; - break; - case STATUS_ACTIVE: - status = "active"; - break; - default: - status = "unknown"; - break; - } + status = (cs->status <= STATUS_ACTIVE) ? stat_str[cs->status] : "unknown"; IConsolePrintF(8, "Client #%d/%s status: %s frame-lag: %d play-as: %d unique-id: %s", cs->index, ci->client_name, status, lag, ci->client_playas, ci->unique_id); } - return NULL; + return true; } DEF_CONSOLE_CMD(ConKick) { NetworkClientInfo *ci; + uint32 index; - if (argc == 2) { - uint32 index = atoi(argv[1]); - if (index == NETWORK_SERVER_INDEX) { - IConsolePrint(_iconsole_color_default, "Silly boy, you can not kick yourself!"); - return NULL; - } - if (index == 0) { - IConsoleError("Invalid Client-ID"); - return NULL; - } + if (argc == 0) { + IConsoleHelp("Kick a player from a network game. Usage: 'kick <client-id>'"); + IConsoleHelp("For client-id's, see the command 'clients'"); + return true; + } - ci = NetworkFindClientInfoFromIndex(index); + if (argc != 2) return false; - if (ci != NULL) { - SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED); - return NULL; - } else { - IConsoleError("Client-ID not found"); - return NULL; - } + index = atoi(argv[1]); + if (index == NETWORK_SERVER_INDEX) { + IConsolePrint(_iconsole_color_default, "Silly boy, you can not kick yourself!"); + return true; } + if (index == 0) { + IConsoleError("Invalid Client-ID"); + return true; + } + + ci = NetworkFindClientInfoFromIndex(index); - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: kick <client-id>. For client-ids, see 'clients'."); + if (ci != NULL) { + SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED); + } else + IConsoleError("Client-ID not found"); - return NULL; + return true; } DEF_CONSOLE_CMD(ConResetCompany) @@ -498,79 +489,92 @@ DEF_CONSOLE_CMD(ConResetCompany) Player *p; NetworkClientState *cs; NetworkClientInfo *ci; + byte index; - if (argc == 2) { - byte index = atoi(argv[1]); + if (argc == 0) { + IConsoleHelp("Remove an (idle) company from the game. Usage: 'reset_company <company-id>'"); + return true; + } - /* Check valid range */ - if (index < 1 || index > MAX_PLAYERS) { - IConsolePrintF(_iconsole_color_error, "Company does not exist. Company-ID must be between 1 and %d.", MAX_PLAYERS); - return NULL; - } + if (argc != 2) return false; - /* Check if company does exist */ - index--; - p = DEREF_PLAYER(index); - if (!p->is_active) { - IConsolePrintF(_iconsole_color_error, "Company does not exist."); - return NULL; - } + index = atoi(argv[1]); - if (p->is_ai) { - IConsolePrintF(_iconsole_color_error, "Company is owned by an AI."); - return NULL; - } + /* Check valid range */ + if (index < 1 || index > MAX_PLAYERS) { + IConsolePrintF(_iconsole_color_error, "Company does not exist. Company-ID must be between 1 and %d.", MAX_PLAYERS); + return true; + } - /* Check if the company has active players */ - FOR_ALL_CLIENTS(cs) { - ci = DEREF_CLIENT_INFO(cs); - if (ci->client_playas-1 == index) { - IConsolePrintF(_iconsole_color_error, "Cannot remove company: a client is connected to that company."); - return NULL; - } - } - ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + /* Check if company does exist */ + index--; + p = DEREF_PLAYER(index); + if (!p->is_active) { + IConsolePrintF(_iconsole_color_error, "Company does not exist."); + return true; + } + + if (p->is_ai) { + IConsolePrintF(_iconsole_color_error, "Company is owned by an AI."); + return true; + } + + /* Check if the company has active players */ + FOR_ALL_CLIENTS(cs) { + ci = DEREF_CLIENT_INFO(cs); if (ci->client_playas-1 == index) { IConsolePrintF(_iconsole_color_error, "Cannot remove company: a client is connected to that company."); - return NULL; + return true; } - - /* It is safe to remove this company */ - DoCommandP(0, 2, index, NULL, CMD_PLAYER_CTRL); - IConsolePrint(_iconsole_color_default, "Company deleted."); - return NULL; + } + ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + if (ci->client_playas - 1 == index) { + IConsolePrintF(_iconsole_color_error, "Cannot remove company; a client is connected to that company."); + return true; } - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: reset_company <company-id>."); + /* It is safe to remove this company */ + DoCommandP(0, 2, index, NULL, CMD_PLAYER_CTRL); + IConsolePrint(_iconsole_color_default, "Company deleted."); - return NULL; + return true; } DEF_CONSOLE_CMD(ConNetworkClients) { NetworkClientInfo *ci; + + if (argc == 0) { + IConsoleHelp("Get a list of connected clients including their ID, name, and company-id. Usage: 'clients'"); + return true; + } + for (ci = _network_client_info; ci != &_network_client_info[MAX_CLIENT_INFO]; ci++) { if (ci->client_index != NETWORK_EMPTY_INDEX) { IConsolePrintF(8,"Client #%d name: %s play-as: %d", ci->client_index, ci->client_name, ci->client_playas); } } - return NULL; + return true; } DEF_CONSOLE_CMD(ConNetworkConnect) { - char* ip; + char *ip; const char *port = NULL; const char *player = NULL; uint16 rport; - if (argc<2) return NULL; + if (argc == 0) { + IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'"); + IConsoleHelp("IP can contain port and player: 'IP#Player:Port', eg: 'server.ottd.org#2:443'"); + return true; + } - if (_networking) { - // We are in network-mode, first close it! + if (argc < 2) return false; + + if (_networking) // We are in network-mode, first close it! NetworkDisconnect(); - } ip = argv[1]; rport = NETWORK_DEFAULT_PORT; @@ -589,7 +593,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect) NetworkClientConnectGame(ip, rport); - return NULL; + return true; } #endif /* ENABLE_NETWORK */ @@ -600,36 +604,44 @@ DEF_CONSOLE_CMD(ConNetworkConnect) DEF_CONSOLE_CMD(ConExec) { - char cmd[1024]; + char cmdline[ICON_CMDLN_SIZE]; - if (argc < 2) return NULL; + if (argc == 0) { + IConsoleHelp("Execute a local script file. Usage: 'exec <script> <?>'"); + return true; + } + + if (argc < 2) return false; _script_file = fopen(argv[1], "r"); if (_script_file == NULL) { - if (argc <= 2 || atoi(argv[2]) != 0) IConsoleError("script file not found"); - return NULL; + if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found"); + return true; } _script_running = true; - while (_script_running && fgets(cmd, sizeof(cmd), _script_file) != NULL) { - IConsoleCmdExec(cmd); - } + while (_script_running && fgets(cmdline, sizeof(cmdline), _script_file) != NULL) + IConsoleCmdExec(cmdline); - if (ferror(_script_file)) { + if (ferror(_script_file)) IConsoleError("Encountered errror while trying to read from script file"); - } _script_running = false; fclose(_script_file); - return NULL; + return true; } DEF_CONSOLE_CMD(ConReturn) { + if (argc == 0) { + IConsoleHelp("Stop executing a running script. Usage: 'return'"); + return true; + } + _script_running = false; - return NULL; + return true; } /* **************************** */ @@ -640,591 +652,482 @@ extern bool CloseConsoleLogIfActive(void); DEF_CONSOLE_CMD(ConScript) { extern FILE* _iconsole_output_file; + + if (argc == 0) { + IConsoleHelp("Start or stop logging console output to a file. Usage: 'script <filename>'"); + IConsoleHelp("If filename is omitted, a running log is stopped if it is active"); + return true; + } + if (!CloseConsoleLogIfActive()) { - if (argc < 2) return NULL; + if (argc < 2) return false; + IConsolePrintF(_iconsole_color_default, "file output started to: %s", argv[1]); _iconsole_output_file = fopen(argv[1], "ab"); if (_iconsole_output_file == NULL) IConsoleError("could not open file"); } - return NULL; + return true; } DEF_CONSOLE_CMD(ConEcho) { - if (argc < 2) return NULL; + if (argc == 0) { + IConsoleHelp("Print back the first argument to the console. Usage: 'echo <arg>'"); + return true; + } + + if (argc < 2) return false; IConsolePrint(_iconsole_color_default, argv[1]); - return NULL; + return true; } DEF_CONSOLE_CMD(ConEchoC) { - if (argc < 3) return NULL; + if (argc == 0) { + IConsoleHelp("Print back the first argument to the console in a given colour. Usage: 'echoc <colour> <arg2>'"); + return true; + } + + if (argc < 3) return false; IConsolePrint(atoi(argv[1]), argv[2]); - return NULL; + return true; } extern void SwitchMode(int new_mode); DEF_CONSOLE_CMD(ConNewGame) { + if (argc == 0) { + IConsoleHelp("Start a new game. Usage: 'newgame'"); + return true; + } + _docommand_recursive = 0; _random_seeds[0][0] = Random(); _random_seeds[0][1] = InteractiveRandom(); SwitchMode(SM_NEWGAME); - return NULL; -} - -DEF_CONSOLE_CMD(ConPrintF) -{ - if (argc < 3) return NULL; - IConsolePrintF(_iconsole_color_default, argv[1] , argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19]); /* XXX ugh... */ - return NULL; -} - -DEF_CONSOLE_CMD(ConPrintFC) -{ - if (argc < 3) return NULL; - IConsolePrintF(atoi(argv[1]), argv[2] , argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19]); /* XXX ugh... */ - return NULL; + return true; } DEF_CONSOLE_CMD(ConAlias) { - _iconsole_alias* alias; + IConsoleAlias *alias; - if (argc < 3) return NULL; + if (argc == 0) { + IConsoleHelp("Add a new alias, or redefine the behaviour of an existing alias . Usage: 'alias <name> <command>'"); + return true; + } + + if (argc < 3) return false; alias = IConsoleAliasGet(argv[1]); if (alias == NULL) { - IConsoleAliasRegister(argv[1],argv[2]); + IConsoleAliasRegister(argv[1], argv[2]); } else { free(alias->cmdline); alias->cmdline = strdup(argv[2]); } - return NULL; + return true; } DEF_CONSOLE_CMD(ConScreenShot) { + if (argc == 0) { + IConsoleHelp("Create a screenshot of the game. Usage: 'screenshot [big|no_con]'"); + IConsoleHelp("'big' makes a screenshot of the whole map, 'no_con' hides the console to create the screenshot"); + return true; + } + if (argc < 2) { _make_screenshot = 1; } else { if (strcmp(argv[1], "big") == 0) - _make_screenshot=2; + _make_screenshot = 2; + if (strcmp(argv[1], "no_con") == 0) { IConsoleClose(); _make_screenshot = 1; } } - return NULL; + return true; } DEF_CONSOLE_CMD(ConInfoVar) { - if (argc < 2) return NULL; - if (argt[1] != ICONSOLE_VAR_REFERENCE) { - IConsoleError("first argument has to be a variable reference"); - } else { - _iconsole_var* item; - item = (_iconsole_var*)argv[1]; - IConsolePrintF(_iconsole_color_default, "var_name: %s", item->name); - IConsolePrintF(_iconsole_color_default, "var_type: %i", item->type); - IConsolePrintF(_iconsole_color_default, "var_addr: %i", item->data.addr); - if (item->_malloc) - IConsolePrintF(_iconsole_color_default, "var_malloc: internal"); - else - IConsolePrintF(_iconsole_color_default, "var_malloc: external"); - if (item->hook_access) IConsoleWarning("var_access hooked"); - if (item->hook_before_change) IConsoleWarning("var_before_change hooked"); - if (item->hook_after_change) IConsoleWarning("var_after_change hooked"); - } - return NULL; + static const char *_icon_vartypes[] = {"boolean", "byte", "uint16", "uint32", "int16", "int32", "string"}; + const IConsoleVar *var; + + if (argc == 0) { + IConsoleHelp("Print out debugging information about a variable. Usage: 'info_var <var>'"); + return true; + } + + if (argc < 2) return false; + + var = IConsoleVarGet(argv[1]); + if (var == NULL) { + IConsoleError("the given variable was not found"); + return true; + } + + IConsolePrintF(_iconsole_color_default, "variable name: %s", var->name); + IConsolePrintF(_iconsole_color_default, "variable type: %s", _icon_vartypes[var->type]); + IConsolePrintF(_iconsole_color_default, "variable addr: 0x%X", var->addr); + + if (var->hook.access) IConsoleWarning("variable is access hooked"); + if (var->hook.pre) IConsoleWarning("variable is pre hooked"); + if (var->hook.post) IConsoleWarning("variable is post hooked"); + return true; } DEF_CONSOLE_CMD(ConInfoCmd) { - if (argc < 2) return NULL; - if (argt[1] != ICONSOLE_VAR_UNKNOWN) { - IConsoleError("first argument has to be a command name"); - } else { - _iconsole_cmd* item; - item = IConsoleCmdGet(argv[1]); - if (item == NULL) { - IConsoleError("the given command was not found"); - return NULL; - } - IConsolePrintF(_iconsole_color_default, "cmd_name: %s", item->name); - IConsolePrintF(_iconsole_color_default, "cmd_addr: %i", item->addr); - if (item->hook_access) IConsoleWarning("cmd_access hooked"); - if (item->hook_before_exec) IConsoleWarning("cmd_before_exec hooked"); - if (item->hook_after_exec) IConsoleWarning("cmd_after_exec hooked"); + const IConsoleCmd *cmd; + + if (argc == 0) { + IConsoleHelp("Print out debugging information about a command. Usage: 'info_cmd <cmd>'"); + return true; + } + + if (argc < 2) return false; + + cmd = IConsoleCmdGet(argv[1]); + if (cmd == NULL) { + IConsoleError("the given command was not found"); + return true; } - return NULL; + + IConsolePrintF(_iconsole_color_default, "command name: %s", cmd->name); + IConsolePrintF(_iconsole_color_default, "command proc: 0x%X", cmd->proc); + + if (cmd->hook.access) IConsoleWarning("command is access hooked"); + if (cmd->hook.pre) IConsoleWarning("command is pre hooked"); + if (cmd->hook.post) IConsoleWarning("command is post hooked"); + + return true; } DEF_CONSOLE_CMD(ConDebugLevel) { - if (argc < 2) return NULL; + if (argc == 0) { + IConsoleHelp("Set the default debugging level for the game. Usage: 'debug_level <level>'"); + IConsoleHelp("Level can be any combination of names, levels. Eg 'net=5 ms=4'. Remember to enclose it in \"'s"); + return true; + } + + if (argc < 2) return false; SetDebugString(argv[1]); - return NULL; + return true; } DEF_CONSOLE_CMD(ConExit) { + if (argc == 0) { + IConsoleHelp("Exit the game. Usage: 'exit'"); + return true; + } + _exit_game = true; - return NULL; + return true; } DEF_CONSOLE_CMD(ConHelp) { - IConsolePrint(13, " -- console help -- "); - IConsolePrint( 1, " variables: [command to list them: list_vars]"); - IConsolePrint( 1, " temp_string = \"my little \""); + if (argc == 2) { + IConsoleCmd *cmd; + IConsoleVar *var; + + cmd = IConsoleCmdGet(argv[1]); + if (cmd != NULL) { + cmd->proc(0, NULL); + return true; + } + + var = IConsoleVarGet(argv[1]); + if (var != NULL && var->help != NULL) { + IConsolePrintF(_iconsole_color_warning, "%s.", var->help); + return true; + } + + IConsoleError("command or variable not found"); + return true; + } + + IConsolePrint(13, " -- OpenTTD Console Help -- "); + IConsolePrint( 1, " variables: [command to list all variables: list_vars]"); + IConsolePrint( 1, " set value with '<var> = <value>', use '++/--' to in-or decrement"); + IConsolePrint( 1, " or omit '=' and just '<var> <value>'. get value with typing '<var>'"); IConsolePrint( 1, ""); - IConsolePrint( 1, " commands: [command to list them: list_cmds]"); - IConsolePrint( 1, " [command] [\"string argument with spaces\"] [argument 2] ..."); - IConsolePrint( 1, " printf \"%s world\" temp_string"); + IConsolePrint( 1, " commands: [command to list all commands: list_cmds]"); + IConsolePrint( 1, " call commands with '<command> <arg2> <arg3>...'"); IConsolePrint( 1, ""); - IConsolePrint( 1, " command/variable returning a value into an variable:"); - IConsolePrint( 1, " temp_uint16 << random"); - IConsolePrint( 1, " temp_uint16 << temp_uint16_2"); + IConsolePrint( 1, " to assign strings, or use them as arguments, enclose it within quotes"); + IConsolePrint( 1, " like this: '<command> \"string argument with spaces\"'"); + IConsolePrint( 1, " use 'help <command>|<variable>' to get specific information"); IConsolePrint( 1, ""); - return NULL; -} - -DEF_CONSOLE_CMD(ConRandom) -{ - _iconsole_var* result; - result = IConsoleVarAlloc(ICONSOLE_VAR_UINT16); - IConsoleVarSetValue(result, rand()); - return result; + return true; } DEF_CONSOLE_CMD(ConListCommands) { - const _iconsole_cmd* item; + const IConsoleCmd *cmd; size_t l = 0; + if (argc == 0) { + IConsoleHelp("List all registered commands. Usage: 'list_cmds [<pre-filter>]'"); + return true; + } + if (argv[1] != NULL) l = strlen(argv[1]); - for (item = _iconsole_cmds; item != NULL; item = item->_next) - if (argv[1] == NULL || strncmp(item->name, argv[1], l) == 0) - IConsolePrintF(_iconsole_color_default, "%s", item->name); + for (cmd = _iconsole_cmds; cmd != NULL; cmd = cmd->next) { + if (argv[1] == NULL || strncmp(cmd->name, argv[1], l) == 0) { + IConsolePrintF(_iconsole_color_default, "%s", cmd->name); + } + } - return NULL; + return true; } DEF_CONSOLE_CMD(ConListVariables) { - const _iconsole_var* item; + const IConsoleVar *var; size_t l = 0; + if (argc == 0) { + IConsoleHelp("List all registered variables. Usage: 'list_vars [<pre-filter>]'"); + return true; + } + if (argv[1] != NULL) l = strlen(argv[1]); - for (item = _iconsole_vars; item != NULL; item = item->_next) - if (argv[1] == NULL || strncmp(item->name, argv[1], l) == 0) - IConsolePrintF(_iconsole_color_default, "%s", item->name); + for (var = _iconsole_vars; var != NULL; var = var->next) { + if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0) + IConsolePrintF(_iconsole_color_default, "%s", var->name); + } - return NULL; + return true; } DEF_CONSOLE_CMD(ConListAliases) { - const _iconsole_alias* item; + const IConsoleAlias *alias; size_t l = 0; - if (argv[1] != NULL) l = strlen(argv[1]); - - for (item = _iconsole_aliases; item != NULL; item = item->_next) - if (argv[1] == NULL || strncmp(item->name, argv[1], l) == 0) - IConsolePrintF(_iconsole_color_default, "%s => %s", item->name, item->cmdline); - - return NULL; -} - -DEF_CONSOLE_CMD(ConListDumpVariables) -{ - const _iconsole_var* item; - size_t l = 0; + if (argc == 0) { + IConsoleHelp("List all registered aliases. Usage: 'list_aliases [<pre-filter>]'"); + return true; + } if (argv[1] != NULL) l = strlen(argv[1]); - for (item = _iconsole_vars; item != NULL; item = item->_next) - if (argv[1] == NULL || strncmp(item->name, argv[1], l) == 0) - IConsoleVarDump(item, NULL); + for (alias = _iconsole_aliases; alias != NULL; alias = alias->next) { + if (argv[1] == NULL || strncmp(alias->name, argv[1], l) == 0) + IConsolePrintF(_iconsole_color_default, "%s => %s", alias->name, alias->cmdline); + } - return NULL; + return true; } #ifdef ENABLE_NETWORK DEF_CONSOLE_CMD(ConSay) { - if (argc == 2) { - if (!_network_server) - SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]); - else - NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX); + if (argc == 0) { + IConsoleHelp("Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'"); + return true; + } + + if (argc != 2) return false; + + if (!_network_server) { + SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]); } else - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: say \"<msg>\""); - return NULL; + NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX); + + return true; } DEF_CONSOLE_CMD(ConSayPlayer) { - if (argc == 3) { - if (atoi(argv[1]) < 1 || atoi(argv[1]) > MAX_PLAYERS) { - IConsolePrintF(_iconsole_color_default, "Unknown player. Player range is between 1 and %d.", MAX_PLAYERS); - return NULL; - } + if (argc == 0) { + IConsoleHelp("Chat to a certain player in a multiplayer game. Usage: 'say_player <player-no> \"<msg>\"'"); + IConsoleHelp("PlayerNo is the player that plays as company <playerno>, 1 through max_players"); + return true; + } + + if (argc != 3) return false; - if (!_network_server) - SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2]); - else - NetworkServer_HandleChat(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX); + if (atoi(argv[1]) < 1 || atoi(argv[1]) > MAX_PLAYERS) { + IConsolePrintF(_iconsole_color_default, "Unknown player. Player range is between 1 and %d.", MAX_PLAYERS); + return true; + } + + if (!_network_server) { + SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2]); } else - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: say_player <playerno> \"<msg>\""); - return NULL; + NetworkServer_HandleChat(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX); + + return true; } DEF_CONSOLE_CMD(ConSayClient) { - if (argc == 3) { - if (!_network_server) - SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]); - else - NetworkServer_HandleChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX); + if (argc == 0) { + IConsoleHelp("Chat to a certain player in a multiplayer game. Usage: 'say_client <client-no> \"<msg>\"'"); + IConsoleHelp("For client-id's, see the command 'clients'"); + return true; + } + + if (argc != 3) return false; + + if (!_network_server) { + SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]); } else - IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: say_client <clientno> \"<msg>\""); - return NULL; + NetworkServer_HandleChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX); + + return true; } -#endif /* ENABLE_NETWORK */ +DEF_CONSOLE_HOOK(ConHookServerPW) +{ + if (strncmp(_network_server_password, "*", NETWORK_PASSWORD_LENGTH) == 0) { + _network_server_password[0] = '\0'; + _network_game_info.use_password = 0; + } else + _network_game_info.use_password = 1; -/* **************************** */ -/* the "set" command */ -/* **************************** */ + return true; +} -extern void ConsoleSetPatchSetting(char *name, char *value); -extern void ConsoleGetPatchSetting(char *name); +DEF_CONSOLE_HOOK(ConHookRconPW) +{ + if (strncmp(_network_rcon_password, "*", NETWORK_PASSWORD_LENGTH) == 0) + _network_rcon_password[0] = '\0'; -DEF_CONSOLE_CMD(ConSet) { - if (argc < 2) { - IConsolePrint(_iconsole_color_warning, "Unknonw usage. Usage: set [setting] [value]."); - return NULL; - } + ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_game_info.rcon_password)); -#ifdef ENABLE_NETWORK + return true; +} - // setting the server password - if ((strcmp(argv[1],"server_pw") == 0) || (strcmp(argv[1],"server_password") == 0)) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - // Change server password - if (strncmp(argv[2], "*", NETWORK_PASSWORD_LENGTH) == 0) { - _network_server_password[0] = '\0'; - _network_game_info.use_password = 0; - } else { - ttd_strlcpy(_network_server_password, argv[2], sizeof(_network_server_password)); - _network_game_info.use_password = 1; - } - IConsolePrintF(_iconsole_color_warning, "Game-password changed to '%s'", _network_server_password); - ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_game_info.server_password)); - } else { - IConsolePrintF(_iconsole_color_default, "Current game-password is set to '%s'", _network_game_info.server_password); - IConsolePrint(_iconsole_color_warning, "Usage: set server_pw \"<password>\". Use * as <password> to set no password."); - } - return NULL; +/* Also use from within player_gui to change the password graphically */ +bool NetworkChangeCompanyPassword(byte argc, char *argv[]) +{ + if (argc == 0) { + IConsolePrintF(_iconsole_color_warning, "Current value of 'company_pw': %s", _network_player_info[_local_player].password); + return true; } - // setting the rcon password - if ((strcmp(argv[1], "rcon_pw") == 0) || (strcmp(argv[1], "rcon_password") == 0)) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - // Change server password - if (strncmp(argv[2], "*", NETWORK_PASSWORD_LENGTH) == 0) { - _network_rcon_password[0] = '\0'; - } else { - ttd_strlcpy(_network_rcon_password, argv[2], sizeof(_network_rcon_password)); - } - IConsolePrintF(_iconsole_color_warning, "Rcon-password changed to '%s'", _network_rcon_password); - ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_game_info.rcon_password)); - } else { - IConsolePrintF(_iconsole_color_default, "Current rcon-password is set to '%s'", _network_game_info.rcon_password); - IConsolePrint(_iconsole_color_warning, "Usage: set rcon_pw \"<password>\". Use * as <password> to disable rcon."); - } - return NULL; + if (_local_player >= MAX_PLAYERS) { + IConsoleError("You have to own a company to make use of this command."); + return false; } - // setting the company password - if ((strcmp(argv[1],"company_pw") == 0) || (strcmp(argv[1],"company_password") == 0)) { - if (!_networking) { - IConsolePrintF(_iconsole_color_error,"No network game running"); - return NULL; - } - if (_local_player >= MAX_PLAYERS) { - IConsolePrintF(_iconsole_color_default, "You have to own a company to make use of this command."); - return NULL; - } - if (argc == 3) { - NetworkChangeCompanyPassword(argv[2]); - } else { - IConsolePrint(_iconsole_color_default, "'set company_pw' sets a password for your company, so no-one without the correct password can join."); - IConsolePrint(_iconsole_color_warning, "Usage: set company_pw \"<password>\". Use * as <password> to set no password."); - } - return NULL; - } + if (argc != 1) return false; - // setting the player name - if (strcmp(argv[1],"name") == 0) { - NetworkClientInfo *ci; + if (strncmp(argv[0], "*", sizeof(_network_player_info[_local_player].password)) == 0) + argv[0][0] = '\0'; - if (!_networking) { - IConsolePrintF(_iconsole_color_error,"No network game running"); - return NULL; - } + ttd_strlcpy(_network_player_info[_local_player].password, argv[0], sizeof(_network_player_info[_local_player].password)); - ci = NetworkFindClientInfoFromIndex(_network_own_client_index); - - if (argc == 3 && ci != NULL) { - // Don't change the name if it is the same as the old name - if (strcmp(ci->client_name, argv[2]) != 0) { - if (!_network_server) { - SEND_COMMAND(PACKET_CLIENT_SET_NAME)(argv[2]); - } else { - if (NetworkFindName(argv[2])) { - NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, argv[2]); - ttd_strlcpy(ci->client_name, argv[2], sizeof(ci->client_name)); - NetworkUpdateClientInfo(NETWORK_SERVER_INDEX); - } - } - /* Also keep track of the new name on the client itself */ - ttd_strlcpy(_network_player_name, argv[2], sizeof(_network_player_name)); - } - } else { - IConsolePrint(_iconsole_color_default, "With 'set name' you can change your network-player name."); - IConsolePrint(_iconsole_color_warning, "Usage: set name \"<name>\"."); - } - return NULL; - } + if (!_network_server) + SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password); + + return true; +} - // setting the server name - if (strcmp(argv[1],"server_name") == 0) { +DEF_CONSOLE_HOOK(ConProcPlayerName) +{ + NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index); + + if (ci == NULL) return false; + + // Don't change the name if it is the same as the old name + if (strcmp(ci->client_name, _network_player_name) != 0) { if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - ttd_strlcpy(_network_server_name, argv[2], sizeof(_network_server_name)); - IConsolePrintF(_iconsole_color_warning, "Server-name changed to '%s'", _network_server_name); - ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name)); + SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_network_player_name); } else { - IConsolePrintF(_iconsole_color_default, "Current server-name is '%s'", _network_server_name); - IConsolePrint(_iconsole_color_warning, "Usage: set server_name \"<GameName>\"."); + if (NetworkFindName(_network_player_name)) { + NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, _network_player_name); + ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name)); + NetworkUpdateClientInfo(NETWORK_SERVER_INDEX); + } } - return NULL; } - // setting the server port - if (strcmp(argv[1],"server_port") == 0) { - if (argc == 3 && atoi(argv[2]) != 0) { - _network_server_port = atoi(argv[2]); - IConsolePrintF(_iconsole_color_warning, "Server-port changed to '%d'", _network_server_port); - IConsolePrintF(_iconsole_color_warning, "Changes will take effect the next time you start a server."); - } else { - IConsolePrintF(_iconsole_color_default, "Current server-port is '%d'", _network_server_port); - IConsolePrint(_iconsole_color_warning, "Usage: set server_port <port>."); - } - return NULL; - } + return true; +} - // setting the server ip - if (strcmp(argv[1],"server_bind_ip") == 0 || strcmp(argv[1],"server_ip_bind") == 0 || - strcmp(argv[1],"server_ip") == 0 || strcmp(argv[1],"server_bind") == 0) { - if (argc == 3) { - _network_server_bind_ip = inet_addr(argv[2]); - snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip)); - IConsolePrintF(_iconsole_color_warning, "Server-bind-ip changed to '%s'", _network_server_bind_ip_host); - IConsolePrintF(_iconsole_color_warning, "Changes will take effect the next time you start a server."); - } else { - IConsolePrintF(_iconsole_color_default, "Current server-bind-ip is '%s'", _network_server_bind_ip_host); - IConsolePrint(_iconsole_color_warning, "Usage: set server_bind_ip <ip>."); - } - return NULL; - } +DEF_CONSOLE_HOOK(ConHookServerName) +{ + ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name)); + return true; +} - // setting max-join-time - if (strcmp(argv[1],"max_join_time") == 0) { - if (argc == 3 && atoi(argv[2]) != 0) { - _network_max_join_time = atoi(argv[2]); - IConsolePrintF(_iconsole_color_warning, "Max-join-time changed to '%d'", _network_max_join_time); - IConsolePrintF(_iconsole_color_warning, "Changes will take effect immediatly."); - } else { - IConsolePrintF(_iconsole_color_default, "Current max-join-time is '%d'", _network_max_join_time); - IConsolePrint(_iconsole_color_warning, "Usage: set max_join_time <ticks> (default = 500)."); - } - return NULL; - } +DEF_CONSOLE_HOOK(ConHookServerAdvertise) +{ + if (!_network_advertise) + NetworkUDPRemoveAdvertise(); + return true; +} - // setting the server advertising on/off - if (strcmp(argv[1],"server_advertise") == 0) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - if (strcmp(argv[2], "on") == 0 || atoi(argv[2]) == 1) - _network_advertise = true; - else { - NetworkUDPRemoveAdvertise(); - _network_advertise = false; - } - IConsolePrintF(_iconsole_color_warning, "Server-advertise changed to '%s'", (_network_advertise)?"on":"off"); - } else { - IConsolePrintF(_iconsole_color_default, "Current server-advertise is '%s'", (_network_advertise)?"on":"off"); - IConsolePrint(_iconsole_color_warning, "Usage: set server_advertise on/off."); - } - return NULL; +DEF_CONSOLE_CMD(ConProcServerIP) +{ + if (argc == 0) { + IConsolePrintF(_iconsole_color_warning, "Current value of 'server_ip': %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip)); + return true; } - // setting the server 'pause on client join' on/off - if (strcmp(argv[1],"pause_on_join") == 0) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - if (strcmp(argv[2], "on") == 0 || atoi(argv[2]) == 1) - _network_pause_on_join = true; - else - _network_pause_on_join = false; - IConsolePrintF(_iconsole_color_warning, "Pause-on-join changed to '%s'", (_network_pause_on_join)?"on":"off"); - } else { - IConsolePrintF(_iconsole_color_default, "Current pause-on-join is '%s'", (_network_pause_on_join)?"on":"off"); - IConsolePrint(_iconsole_color_warning, "Usage: set pause_on_join on/off."); - } - return NULL; - } + if (argc != 1) return false; - // setting the server autoclean on/off - if (strcmp(argv[1],"autoclean_companies") == 0) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - if (strcmp(argv[2], "on") == 0 || atoi(argv[2]) == 1) - _network_autoclean_companies = true; - else - _network_autoclean_companies = false; - IConsolePrintF(_iconsole_color_warning, "Autoclean-companies changed to '%s'", (_network_autoclean_companies)?"on":"off"); - } else { - IConsolePrintF(_iconsole_color_default, "Current autoclean-companies is '%s'", (_network_autoclean_companies)?"on":"off"); - IConsolePrint(_iconsole_color_warning, "Usage: set autoclean_companies on/off."); - } - return NULL; - } + _network_server_bind_ip = inet_addr(argv[0]); + snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip)); + return true; +} - // setting the server autoclean protected - if (strcmp(argv[1],"autoclean_protected") == 0) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - _network_autoclean_protected = atoi(argv[2]); - IConsolePrintF(_iconsole_color_warning, "Autoclean-protected changed to '%d'", _network_autoclean_protected); - } else { - IConsolePrintF(_iconsole_color_default, "Current autoclean-protected is '%d'", _network_autoclean_protected); - IConsolePrint(_iconsole_color_warning, "Usage: set autoclean_protected <months>."); - } - return NULL; +DEF_CONSOLE_CMD(ConPatch) +{ + if (argc == 0) { + IConsoleHelp("Change patch variables for all players. Usage: 'patch <name> [<value>]'"); + IConsoleHelp("Omitting <value> will print out the current value of the patch-setting."); + return true; } - // setting the server autoclean protected - if (strcmp(argv[1],"autoclean_unprotected") == 0) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - _network_autoclean_unprotected = atoi(argv[2]); - IConsolePrintF(_iconsole_color_warning, "Autoclean-unprotected changed to '%d'", _network_autoclean_unprotected); - } else { - IConsolePrintF(_iconsole_color_default, "Current autoclean-unprotected is '%d'", _network_autoclean_unprotected); - IConsolePrint(_iconsole_color_warning, "Usage: set autoclean_unprotected <months>."); - } - return NULL; - } + if (argc == 1 || argc > 3) return false; - // setting the server auto restart date - if (strcmp(argv[1],"restart_game_date") == 0) { - if (!_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) { - _network_restart_game_date = atoi(argv[2]); - IConsolePrintF(_iconsole_color_warning, "Restart Game Date changed to '%d'", _network_restart_game_date); - } else { - IConsolePrintF(_iconsole_color_default, "Current Restart Game Date is '%d'", _network_restart_game_date); - IConsolePrint(_iconsole_color_warning, "Usage: set restart_game_date <year>. '0' means disabled."); - IConsolePrint(_iconsole_color_warning, " Auto-restart the server when 1 jan of this year is reached (e.g.: 2030)."); - } - return NULL; - } + if (argc == 2) { + IConsoleGetPatchSetting(argv[1]); + } else + IConsoleSetPatchSetting(argv[1], argv[2]); + return true; +} #endif /* ENABLE_NETWORK */ - // Patch-options - if (strcmp(argv[1],"patch") == 0) { - if (_networking && !_network_server) { - IConsolePrintF(_iconsole_color_error, "You are not the server"); - return NULL; - } - if (argc == 3) - ConsoleGetPatchSetting(argv[2]); - else if (argc == 4) - ConsoleSetPatchSetting(argv[2], argv[3]); - else - IConsolePrint(_iconsole_color_warning, "Usage: set patch <patch_name> [<value>]."); - return NULL; +DEF_CONSOLE_CMD(ConListDumpVariables) +{ + const IConsoleVar *var; + size_t l = 0; + + if (argc == 0) { + IConsoleHelp("List all variables with their value. Usage: 'dump_vars [<pre-filter>]'"); + return true; } + if (argv[1] != NULL) l = strlen(argv[1]); - IConsolePrint(_iconsole_color_error, "Unknown setting"); - IConsolePrint(_iconsole_color_error, "Known settings are:"); -#ifdef ENABLE_NETWORK - IConsolePrint(_iconsole_color_error, " - autoclean_companies on/off"); - IConsolePrint(_iconsole_color_error, " - autoclean_protected <months>"); - IConsolePrint(_iconsole_color_error, " - autoclean_unprotected <months>"); - IConsolePrint(_iconsole_color_error, " - company_pw \"<password>\""); - IConsolePrint(_iconsole_color_error, " - max_join_time <frames>"); - IConsolePrint(_iconsole_color_error, " - name \"<playername>\""); - IConsolePrint(_iconsole_color_error, " - pause_on_join on/off"); - IConsolePrint(_iconsole_color_error, " - rcon_pw \"<password>\""); - IConsolePrint(_iconsole_color_error, " - server_name \"<name>\""); - IConsolePrint(_iconsole_color_error, " - server_advertise on/off"); - IConsolePrint(_iconsole_color_error, " - server_bind_ip <ip>"); - IConsolePrint(_iconsole_color_error, " - server_port <port>"); - IConsolePrint(_iconsole_color_error, " - server_pw \"<password>\""); - IConsolePrint(_iconsole_color_error, " - restart_game_date \"<year>\""); -#endif /* ENABLE_NETWORK */ - IConsolePrint(_iconsole_color_error, " - patch <patch_name> [<value>]"); + for (var = _iconsole_vars; var != NULL; var = var->next) { + if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0) + IConsoleVarPrintGetValue(var); + } - return NULL; + return true; } @@ -1238,12 +1141,10 @@ static void IConsoleDebugLibRegister(void) // debugging variables and functions extern bool _stdlib_con_developer; /* XXX extern in .c */ - IConsoleVarRegister("con_developer", &_stdlib_con_developer, ICONSOLE_VAR_BOOLEAN); - IConsoleVarMemRegister("temp_string2", ICONSOLE_VAR_STRING); - IConsoleVarMemRegister("temp_uint16_2", ICONSOLE_VAR_UINT16); - IConsoleCmdRegister("resettile", ConResetTile); - IConsoleAliasRegister("dbg_echo","echo %A; echo %B"); - IConsoleAliasRegister("dbg_echo2","echo %+"); + IConsoleVarRegister("con_developer", &_stdlib_con_developer, ICONSOLE_VAR_BOOLEAN, "Enable/disable console debugging information (internal)"); + IConsoleCmdRegister("resettile", ConResetTile); + IConsoleAliasRegister("dbg_echo", "echo %A; echo %B"); + IConsoleAliasRegister("dbg_echo2", "echo %!"); } #endif @@ -1268,86 +1169,129 @@ void IConsoleStdLibRegister(void) IConsoleCmdRegister("info_var", ConInfoVar); IConsoleCmdRegister("list_cmds", ConListCommands); IConsoleCmdRegister("list_vars", ConListVariables); - IConsoleCmdRegister("list_aliases", ConListAliases); - IConsoleCmdRegister("newgame", ConNewGame); - IConsoleCmdRegister("printf", ConPrintF); - IConsoleCmdRegister("printfc", ConPrintFC); + IConsoleCmdRegister("list_aliases", ConListAliases); + IConsoleCmdRegister("newgame", ConNewGame); IConsoleCmdRegister("quit", ConExit); - IConsoleCmdRegister("random", ConRandom); IConsoleCmdRegister("resetengines", ConResetEngines); - IConsoleCmdRegister("return", ConReturn); - IConsoleCmdRegister("screenshot", ConScreenShot); - IConsoleCmdRegister("script", ConScript); - IConsoleCmdRegister("scrollto", ConScrollToTile); - IConsoleCmdRegister("set", ConSet); - IConsoleCmdRegister("alias", ConAlias); - IConsoleCmdRegister("load", ConLoad); - IConsoleCmdRegister("save", ConSave); - IConsoleCmdRegister("ls", ConListFiles); - IConsoleCmdRegister("cd", ConChangeDirectory); - IConsoleCmdRegister("pwd", ConPrintWorkingDirectory); - IConsoleAliasRegister("dir", "ls"); + IConsoleCmdRegister("return", ConReturn); + IConsoleCmdRegister("screenshot", ConScreenShot); + IConsoleCmdRegister("script", ConScript); + IConsoleCmdRegister("scrollto", ConScrollToTile); + IConsoleCmdRegister("alias", ConAlias); + IConsoleCmdRegister("load", ConLoad); + IConsoleCmdRegister("save", ConSave); + IConsoleCmdRegister("ls", ConListFiles); + IConsoleCmdRegister("cd", ConChangeDirectory); + IConsoleCmdRegister("pwd", ConPrintWorkingDirectory); + + IConsoleAliasRegister("dir", "ls"); + IConsoleAliasRegister("newmap", "newgame"); + IConsoleAliasRegister("new_map", "newgame"); IConsoleAliasRegister("new_game", "newgame"); - IConsoleAliasRegister("newmap", "newgame"); - IConsoleAliasRegister("new_map", "newgame"); - IConsoleVarRegister("developer", &_stdlib_developer, ICONSOLE_VAR_BYTE); - // temporary data containers for alias scripting - IConsoleVarMemRegister("temp_string", ICONSOLE_VAR_STRING); - IConsoleVarMemRegister("temp_bool", ICONSOLE_VAR_BOOLEAN); - IConsoleVarMemRegister("temp_int16", ICONSOLE_VAR_INT16); - IConsoleVarMemRegister("temp_int32", ICONSOLE_VAR_INT32); - IConsoleVarMemRegister("temp_pointer", ICONSOLE_VAR_POINTER); - IConsoleVarMemRegister("temp_uint16", ICONSOLE_VAR_UINT16); - IConsoleVarMemRegister("temp_uint32", ICONSOLE_VAR_UINT32); + IConsoleVarRegister("developer", &_stdlib_developer, ICONSOLE_VAR_BYTE, "Redirect debugging output from the console/command line to the ingame console (value 2). Default value: 1"); - - // networking variables and functions + /* networking variables and functions */ #ifdef ENABLE_NETWORK - IConsoleCmdRegister("say", ConSay); - IConsoleCmdHook("say", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork); - IConsoleCmdRegister("say_player", ConSayPlayer); - IConsoleCmdHook("say_player", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork); - IConsoleCmdRegister("say_client", ConSayClient); - IConsoleCmdHook("say_client", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork); - IConsoleCmdRegister("kick", ConKick); - IConsoleCmdHook("kick", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdRegister("reset_company", ConResetCompany); - IConsoleCmdHook("reset_company", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdRegister("connect", ConNetworkConnect); - IConsoleCmdHook("connect", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetServer); - IConsoleCmdRegister("clients", ConNetworkClients); - IConsoleCmdRegister("status", ConStatus); - IConsoleCmdHook("status", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdHook("resetengines", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetwork); - - IConsoleCmdRegister("rcon", ConRcon); - IConsoleCmdHook("rcon", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork); - - IConsoleCmdRegister("ban", ConBan); - IConsoleCmdHook("ban", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdRegister("unban", ConUnBan); - IConsoleCmdHook("unban", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdRegister("banlist", ConBanList); - IConsoleCmdHook("banlist", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdRegister("pause", ConPauseGame); - IConsoleCmdHook("pause", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - IConsoleCmdRegister("unpause", ConUnPauseGame); - IConsoleCmdHook("unpause", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient); - - IConsoleAliasRegister("clean_company", "reset_company %A"); - - IConsoleVarRegister("net_frame_freq", &_network_frame_freq, ICONSOLE_VAR_UINT8); - IConsoleVarHook("net_frame_freq", ICONSOLE_HOOK_ACCESS, ConVarHookNoNetClient); - IConsoleVarRegister("net_sync_freq", &_network_sync_freq, ICONSOLE_VAR_UINT16); - IConsoleVarHook("net_sync_freq", ICONSOLE_HOOK_ACCESS, ConVarHookNoNetClient); + /*** Networking commands ***/ + IConsoleCmdRegister("say", ConSay); + IConsoleCmdHookAdd("say", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + IConsoleCmdRegister("say_player", ConSayPlayer); + IConsoleCmdHookAdd("say_player", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + IConsoleCmdRegister("say_client", ConSayClient); + IConsoleCmdHookAdd("say_client", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + IConsoleCmdRegister("kick", ConKick); + IConsoleCmdHookAdd("kick", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleCmdRegister("reset_company", ConResetCompany); + IConsoleCmdHookAdd("reset_company", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleAliasRegister("clean_company", "reset_company %A"); + IConsoleCmdRegister("connect", ConNetworkConnect); + IConsoleCmdHookAdd("connect", ICONSOLE_HOOK_ACCESS, ConHookClientOnly); + IConsoleCmdRegister("clients", ConNetworkClients); + IConsoleCmdRegister("status", ConStatus); + IConsoleCmdHookAdd("status", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleCmdHookAdd("resetengines", ICONSOLE_HOOK_ACCESS, ConHookNoNetwork); + + IConsoleCmdRegister("rcon", ConRcon); + IConsoleCmdHookAdd("rcon", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + + IConsoleCmdRegister("ban", ConBan); + IConsoleCmdHookAdd("ban", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleCmdRegister("unban", ConUnBan); + IConsoleCmdHookAdd("unban", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleCmdRegister("banlist", ConBanList); + IConsoleCmdHookAdd("banlist", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleCmdRegister("pause", ConPauseGame); + IConsoleCmdHookAdd("pause", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleCmdRegister("unpause", ConUnPauseGame); + IConsoleCmdHookAdd("unpause", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + IConsoleCmdRegister("patch", ConPatch); + IConsoleCmdHookAdd("patch", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + /*** Networking variables ***/ + IConsoleVarRegister("net_frame_freq", &_network_frame_freq, ICONSOLE_VAR_BYTE, "The amount of frames before a command will be (visibly) executed. Default value: 1"); + IConsoleVarHookAdd("net_frame_freq", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleVarRegister("net_sync_freq", &_network_sync_freq, ICONSOLE_VAR_UINT16, "The amount of frames to check if the game is still in sync. Default value: 100"); + IConsoleVarHookAdd("net_sync_freq", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + IConsoleVarStringRegister("server_pw", &_network_server_password, sizeof(_network_server_password), "Set the server password to protect your server. Use '*' to clear the password"); + IConsoleVarHookAdd("server_pw", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleVarHookAdd("server_pw", ICONSOLE_HOOK_POST_ACTION, ConHookServerPW); + IConsoleAliasRegister("server_password", "server_pw %+"); + + IConsoleVarStringRegister("rcon_pw", &_network_rcon_password, sizeof(_network_rcon_password), "Set the rcon-password to change server behaviour. Use '*' to disable rcon"); + IConsoleVarHookAdd("rcon_pw", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleVarHookAdd("rcon_pw", ICONSOLE_HOOK_POST_ACTION, ConHookRconPW); + IConsoleAliasRegister("rcon_password", "rcon_pw %+"); + + IConsoleVarStringRegister("company_pw", NULL, 0, "Set a password for your company, so no one without the correct password can join. Use '*' to clear the password"); + IConsoleVarHookAdd("company_pw", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + IConsoleVarProcAdd("company_pw", NetworkChangeCompanyPassword); + IConsoleAliasRegister("company_password", "company_pw %+"); + + IConsoleVarStringRegister("name", &_network_player_name, sizeof(_network_player_name), "Set your name for multiplayer"); + IConsoleVarHookAdd("name", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + IConsoleVarHookAdd("name", ICONSOLE_HOOK_POST_ACTION, ConProcPlayerName); + + IConsoleVarStringRegister("server_name", &_network_server_name, sizeof(_network_server_name), "Set the name of the server for multiplayer"); + IConsoleVarHookAdd("server_name", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleVarHookAdd("server_name", ICONSOLE_HOOK_POST_ACTION, ConHookServerName); + + IConsoleVarRegister("server_port", &_network_server_port, ICONSOLE_VAR_UINT32, "Set the server port. Changes take effect the next time you start a server"); + + IConsoleVarRegister("server_ip", &_network_server_bind_ip, ICONSOLE_VAR_UINT32, "Set the IP the server binds to. Changes take effect the next time you start a server"); + IConsoleVarProcAdd("server_ip", ConProcServerIP); + IConsoleAliasRegister("server_bind_ip", "server_ip %+"); + IConsoleAliasRegister("server_ip_bind", "server_ip %+"); + IConsoleAliasRegister("server_bind", "server_ip %+"); + + IConsoleVarRegister("max_join_time", &_network_max_join_time, ICONSOLE_VAR_UINT16, "Set the maximum amount of time (ticks) a client is allowed to join. Default value: 500"); + + IConsoleVarRegister("server_advertise", &_network_advertise, ICONSOLE_VAR_BOOLEAN, "Set if the server will advertise to the master server and show up there"); + IConsoleVarHookAdd("server_advertise", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + IConsoleVarHookAdd("server_advertise", ICONSOLE_HOOK_POST_ACTION, ConHookServerAdvertise); + + IConsoleVarRegister("pause_on_join", &_network_pause_on_join, ICONSOLE_VAR_BOOLEAN, "Set if the server should pause gameplay while a client is joining. This might help slow users"); + IConsoleVarHookAdd("pause_on_join", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + IConsoleVarRegister("autoclean_companies", &_network_autoclean_companies, ICONSOLE_VAR_BOOLEAN, "Automatically shut down inactive companies to free them up for other players. Customize with 'autoclean_(un)protected'"); + IConsoleVarHookAdd("autoclean_companies", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + IConsoleVarRegister("autoclean_protected", &_network_autoclean_protected, ICONSOLE_VAR_BYTE, "Automatically remove the password from an inactive company after the given amount of months"); + IConsoleVarHookAdd("autoclean_protected", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + IConsoleVarRegister("autoclean_unprotected", &_network_autoclean_protected, ICONSOLE_VAR_BYTE, "Automatically shut down inactive companies after the given amount of months"); + IConsoleVarHookAdd("autoclean_unprotected", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + + IConsoleVarRegister("restart_game_date", &_network_restart_game_date, ICONSOLE_VAR_BYTE, "Auto-restart the server when Jan 1st of the set year is reached. Use '0' to disable this"); + IConsoleVarHookAdd("restart_game_date", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); + #endif /* ENABLE_NETWORK */ // debugging stuff #ifdef _DEBUG IConsoleDebugLibRegister(); #endif - } -/* -------------------- don't cross this line --------------------- */ @@ -1370,21 +1370,6 @@ void NetworkShutDown(void) } #endif } - -void NetworkChangeCompanyPassword(const char *str) -{ - if (strncmp(str, "*", sizeof(_network_player_info[_local_player].password)) == 0) { - _network_player_info[_local_player].password[0] = '\0'; - IConsolePrint(_iconsole_color_warning, "Company password protection removed."); - } else { - ttd_strlcpy(_network_player_info[_local_player].password, str, sizeof(_network_player_info[_local_player].password)); - IConsolePrintF(_iconsole_color_warning, "Company protected with password '%s'.", _network_player_info[_local_player].password); - } - - if (!_network_server) - SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password); -} - #else void ParseConnectionString(const char **player, const char **port, char *connection_string) {} @@ -217,6 +217,6 @@ void ParseConnectionString(const char **player, const char **port, char *connect void NetworkUpdateClientInfo(uint16 client_index); void NetworkAddServer(const char *b); void NetworkRebuildHostList(void); -void NetworkChangeCompanyPassword(const char *str); +bool NetworkChangeCompanyPassword(byte argc, char *argv[]); #endif /* NETWORK_H */ diff --git a/player_gui.c b/player_gui.c index c4910b327..da7de978c 100644 --- a/player_gui.c +++ b/player_gui.c @@ -656,7 +656,7 @@ static void PlayerCompanyWndProc(Window *w, WindowEvent *e) #ifdef ENABLE_NETWORK case 2: /* Change company password */ if (*b == 0) *b = '*'; // empty password is a '*' because of console argument - NetworkChangeCompanyPassword(b); + NetworkChangeCompanyPassword(1, &b); #endif } } break; diff --git a/settings.h b/settings.h index e4bf27601..2d7f0bf8f 100644 --- a/settings.h +++ b/settings.h @@ -42,4 +42,7 @@ typedef struct SettingDesc { const void *b; } SettingDesc; +void IConsoleSetPatchSetting(const char *name, const char *value); +void IConsoleGetPatchSetting(const char *name); + #endif /* SETTINGS_H */ diff --git a/settings_gui.c b/settings_gui.c index c64a56d9f..d18bd37c1 100644 --- a/settings_gui.c +++ b/settings_gui.c @@ -1033,17 +1033,22 @@ static void PatchesSelectionWndProc(Window *w, WindowEvent *e) } } +/** + * Network-safe changing of patch-settings. + * @param p1 bytes 0 - 7: the patches type (page) that is being changed (construction, network, ai) + * @param p1 bytes 8 - ..: the actual patch (entry) being set inside the category + * @param p2 the new value for the patch + */ int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - const PatchPage *page; - const PatchEntry *pe; + byte pcat = p1 & 0xFF; + byte pel = (p1 >> 8) & 0xFF; - if (flags & DC_EXEC) { - page = &_patches_page[(byte)p1]; - if (page == NULL) return 0; - pe = &page->entries[(byte)(p1 >> 8)]; - if (pe == NULL) return 0; + if (pcat >= lengthof(_patches_page)) return 0; + if (pel >= _patches_page[pcat].num) return 0; + if (flags & DC_EXEC) { + const PatchEntry *pe = &_patches_page[pcat].entries[pel]; WritePE(pe, (int32)p2); InvalidateWindow(WC_GAME_OPTIONS, 0); @@ -1052,116 +1057,79 @@ int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2) return 0; } +static const PatchEntry *IConsoleGetPatch(const char *name, uint *page, uint *entry) +{ + const PatchPage *pp; + const PatchEntry *pe; + + for (*page = 0; *page < lengthof(_patches_page); (*page)++) { + pp = &_patches_page[*page]; + for (*entry = 0; *entry < pp->num; (*entry)++) { + pe = &pp->entries[*entry]; + if (strncmp(pe->console_name, name, sizeof(pe->console_name)) == 0) + return pe; + } + } + + return NULL; +} + /* Those 2 functions need to be here, else we have to make some stuff non-static and besides, it is also better to keep stuff like this at the same place */ -void ConsoleSetPatchSetting(char *name, char *value) +void IConsoleSetPatchSetting(char *name, const char *value) { - const PatchPage *page; - const PatchEntry *pe = NULL; - bool found = false; - uint i; - unsigned int j; + const PatchEntry *pe; + uint page, entry; int val; - /* Search for the name in the patch-settings */ - for (i = 0; i < lengthof(_patches_page); i++) { - page = &_patches_page[i]; - for (j = 0; j < page->num; j++) { - pe = &page->entries[j]; - if (strncmp(pe->console_name, name, sizeof(pe->console_name)) == 0) { - /* We found the name */ - found = true; - break; - } - } - if (found) - break; - } + pe = IConsoleGetPatch(name, &page, &entry); - /* We did not found the patch setting */ - if (!found || pe == NULL) { - IConsolePrintF(_iconsole_color_warning, "'%s' is an unkown patch setting", name); + if (pe == NULL) { + IConsolePrintF(_iconsole_color_warning, "'%s' is an unknown patch setting.", name); return; } - val = atoi(value); + sscanf(value, "%d", &val); - if (pe->type == PE_CURRENCY) { + if (pe->type == PE_CURRENCY) // currency can be different on each client val /= GetCurrentCurrencyRate(); - } // If an item is playerbased, we do not send it over the network (if any) if (pe->flags & PF_PLAYERBASED) { WritePE(pe, val); - } else { - // Else we do - DoCommandP(0, i + (j << 8), val, NULL, CMD_CHANGE_PATCH_SETTING); - } + } else // Else we do + DoCommandP(0, page + (entry << 8), val, NULL, CMD_CHANGE_PATCH_SETTING); + + { + char tval[20]; + const char *tval2 = value; + if (pe->type == PE_BOOL) { + snprintf(tval, sizeof(tval), (val == 1) ? "on" : "off"); + tval2 = tval; + } - switch(pe->type) { - case PE_BOOL: - if (val == 1) - snprintf(value, sizeof(value), "enabled"); - else - snprintf(value, sizeof(value), "disabled"); - break; - default: - break; + IConsolePrintF(_iconsole_color_warning, "'%s' changed to: %s", name, tval2); } - - IConsolePrintF(_iconsole_color_warning, "'%s' changed in:", name); - IConsolePrintF(_iconsole_color_warning, " '%s'", value); } -void ConsoleGetPatchSetting(char *name) +void IConsoleGetPatchSetting(const char *name) { - const PatchPage *page; - const PatchEntry *pe = NULL; - char value[50]; - bool found = false; - uint i; - unsigned int j; - - /* Search for the name in the patch-settings */ - for (i = 0; i < lengthof(_patches_page); i++) { - page = &_patches_page[i]; - for (j = 0; j < page->num; j++) { - pe = &page->entries[j]; - if (strncmp(pe->console_name, name, sizeof(pe->console_name)) == 0) { - /* We found the name */ - found = true; - break; - } - } - if (found) - break; - } + char value[20]; + uint page, entry; + const PatchEntry *pe = IConsoleGetPatch(name, &page, &entry); - /* We did not found the patch setting */ - if (!found || pe == NULL) { - IConsolePrintF(_iconsole_color_warning, "'%s' is an unkown patch setting", name); + /* We did not find the patch setting */ + if (pe == NULL) { + IConsolePrintF(_iconsole_color_warning, "'%s' is an unknown patch setting.", name); return; } - /* 'pe' is now the correct patch setting */ - switch(pe->type) { - case PE_BOOL: - if (ReadPE(pe) == 1) - snprintf(value, sizeof(value), "enabled"); - else - snprintf(value, sizeof(value), "disabled"); - break; - case PE_UINT8: - case PE_INT16: - case PE_UINT16: - case PE_INT32: - case PE_CURRENCY: - snprintf(value, sizeof(value), "%d", ReadPE(pe)); - break; - } + if (pe->type == PE_BOOL) { + snprintf(value, sizeof(value), (ReadPE(pe) == 1) ? "on" : "off"); + } else + snprintf(value, sizeof(value), "%d", ReadPE(pe)); - IConsolePrintF(_iconsole_color_warning, "Current value for '%s' is:", name); - IConsolePrintF(_iconsole_color_warning, " '%s'", value); + IConsolePrintF(_iconsole_color_warning, "Current value for '%s' is: '%s'", name, value); } static const Widget _patches_selection_widgets[] = { |