Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

console: remember prompt history #1684

Merged
merged 1 commit into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/tr1/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- added `/nextlevel` alias to `/endlevel` console command
- added `/quit` alias to `/exit` console command
- added an option to toggle the in-game UI, such as healthbars and ammo text (#1656)
- added the ability to cycle through console prompt history (#1571)
- changed the easter egg console command to pack more punch
- changed `/set` console command to do fuzzy matching (LostArtefacts/libtrx#38)
- fixed console caret position off by a couple of pixels (regression from 3.0)
Expand Down
1 change: 1 addition & 0 deletions docs/tr2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- added `/sfx` command
- added `/nextlevel` alias to `/endlevel` console command
- added `/quit` alias to `/exit` console command
- added the ability to cycle through console prompt history (#1571)
- changed `/set` console command to do fuzzy matching (LostArtefacts/libtrx#38)
- fixed crash in the `/set` console command (regression from 0.3)
- fixed using console in cutscenes immediately exiting the game (regression from 0.3)
Expand Down
1 change: 1 addition & 0 deletions src/libtrx/config/file.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "config/file.h"

#include "filesystem.h"
#include "game/console/history.h"
#include "log.h"
#include "memory.h"

Expand Down
4 changes: 4 additions & 0 deletions src/libtrx/game/console/common.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "game/console/common.h"

#include "./internal.h"
#include "game/console/extern.h"
#include "game/game_string.h"
#include "game/ui/widgets/console.h"
Expand All @@ -18,6 +19,7 @@ static UI_WIDGET *m_Console;
void Console_Init(void)
{
m_Console = UI_Console_Create();
Console_History_Init();
}

void Console_Shutdown(void)
Expand All @@ -27,6 +29,8 @@ void Console_Shutdown(void)
m_Console = NULL;
}

Console_History_Shutdown();

m_IsOpened = false;
}

Expand Down
91 changes: 91 additions & 0 deletions src/libtrx/game/console/history.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include "game/console/history.h"

#include "config/file.h"
#include "memory.h"
#include "utils.h"
#include "vector.h"

#define MAX_HISTORY_ENTRIES 30

VECTOR *m_History = NULL;
static const char *m_Path = "cfg/" PROJECT_NAME "_console_history.json5";

void M_LoadFromJSON(JSON_OBJECT *const root_obj)
{
JSON_ARRAY *const arr = JSON_ObjectGetArray(root_obj, "entries");
if (arr == NULL) {
return;
}

Console_History_Clear();
for (size_t i = 0; i < arr->length; i++) {
const char *const line = JSON_ArrayGetString(arr, i, NULL);
if (line != NULL) {
Console_History_Append(line);
}
}
}

void M_DumpToJSON(JSON_OBJECT *const root_obj)
{
JSON_ARRAY *const arr = JSON_ArrayNew();

bool has_elements = false;
for (int32_t i = 0; i < Console_History_GetLength(); i++) {
JSON_ArrayAppendString(arr, Console_History_Get(i));
has_elements = true;
}

if (has_elements) {
JSON_ObjectAppendArray(root_obj, "entries", arr);
} else {
JSON_ArrayFree(arr);
}
}

void Console_History_Init(void)
{
m_History = Vector_Create(sizeof(char *));
ConfigFile_Read(m_Path, &M_LoadFromJSON);
}

void Console_History_Shutdown(void)
{
if (m_History != NULL) {
ConfigFile_Write(m_Path, &M_DumpToJSON);
for (int32_t i = m_History->count - 1; i >= 0; i--) {
char *const prompt = *(char **)Vector_Get(m_History, i);
Memory_Free(prompt);
}
Vector_Free(m_History);
m_History = NULL;
}
}

int32_t Console_History_GetLength(void)
{
return m_History->count;
}

void Console_History_Clear(void)
{
Vector_Clear(m_History);
}

void Console_History_Append(const char *const prompt)
{
if (m_History->count == MAX_HISTORY_ENTRIES) {
Vector_RemoveAt(m_History, 0);
}
char *prompt_copy = Memory_DupStr(prompt);
Vector_Add(m_History, &prompt_copy);
}

const char *Console_History_Get(const int32_t idx)
{
if (idx < 0 || idx >= m_History->count) {
return NULL;
}
const char *const prompt = *(char **)Vector_Get(m_History, idx);
return prompt;
}
4 changes: 4 additions & 0 deletions src/libtrx/game/console/internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

void Console_History_Init(void);
void Console_History_Shutdown(void);
76 changes: 64 additions & 12 deletions src/libtrx/game/ui/widgets/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "game/clock.h"
#include "game/console/common.h"
#include "game/console/history.h"
#include "game/text.h"
#include "game/ui/common.h"
#include "game/ui/events.h"
Expand All @@ -16,8 +17,9 @@
#include <string.h>

#define WINDOW_MARGIN 5
#define LOG_MARGIN 10
#define MAX_LOG_LINES 20
#define MAX_LISTENERS 4
#define LOG_MARGIN 10
#define LOG_SCALE 0.8
#define DELAY_PER_CHAR 0.2

Expand All @@ -28,17 +30,17 @@ typedef struct {
UI_WIDGET *spacer;
char *log_lines;
int32_t logs_on_screen;
int32_t history_idx;

int32_t listener1;
int32_t listener2;
int32_t listener3;

int32_t listeners[MAX_LISTENERS];
struct {
double expire_at;
UI_WIDGET *label;
} logs[MAX_LOG_LINES];
} UI_CONSOLE;

static void M_MoveHistoryUp(UI_CONSOLE *self);
static void M_MoveHistoryDown(UI_CONSOLE *self);
static void M_HandlePromptCancel(const EVENT *event, void *data);
static void M_HandlePromptConfirm(const EVENT *event, void *data);
static void M_HandleCanvasResize(const EVENT *event, void *data);
Expand All @@ -51,16 +53,44 @@ static void M_Control(UI_CONSOLE *self);
static void M_Draw(UI_CONSOLE *self);
static void M_Free(UI_CONSOLE *self);

static void M_MoveHistoryUp(UI_CONSOLE *const self)
{
self->history_idx--;
CLAMP(self->history_idx, 0, Console_History_GetLength());
const char *const new_prompt = Console_History_Get(self->history_idx);
if (new_prompt == NULL) {
UI_Prompt_ChangeText(self->prompt, "");
} else {
UI_Prompt_ChangeText(self->prompt, new_prompt);
}
}

static void M_MoveHistoryDown(UI_CONSOLE *const self)
{
self->history_idx++;
CLAMP(self->history_idx, 0, Console_History_GetLength());
const char *const new_prompt = Console_History_Get(self->history_idx);
if (new_prompt == NULL) {
UI_Prompt_ChangeText(self->prompt, "");
} else {
UI_Prompt_ChangeText(self->prompt, new_prompt);
}
}

static void M_HandlePromptCancel(const EVENT *const event, void *const data)
{
Console_Close();
}

static void M_HandlePromptConfirm(const EVENT *const event, void *const data)
{
UI_CONSOLE *const self = (UI_CONSOLE *)data;
const char *text = event->data;
Console_History_Append(text);
Console_Eval(text);
Console_Close();

self->history_idx = Console_History_GetLength();
}

static void M_HandleCanvasResize(const EVENT *event, void *data)
Expand All @@ -69,6 +99,24 @@ static void M_HandleCanvasResize(const EVENT *event, void *data)
UI_Stack_SetSize(self->container, M_GetWidth(self), M_GetHeight(self));
}

static void M_HandleKeyDown(const EVENT *const event, void *const user_data)
{
if (!Console_IsOpened()) {
return;
}

UI_CONSOLE *const self = user_data;
const UI_INPUT key = (UI_INPUT)(uintptr_t)event->data;

// clang-format off
switch (key) {
case UI_KEY_UP: M_MoveHistoryUp(self); break;
case UI_KEY_DOWN: M_MoveHistoryDown(self); break;
default: break;
}
// clang-format on
}

static void M_UpdateLogCount(UI_CONSOLE *const self)
{
self->logs_on_screen = 0;
Expand Down Expand Up @@ -114,9 +162,9 @@ static void M_Free(UI_CONSOLE *const self)
self->spacer->free(self->spacer);
self->prompt->free(self->prompt);
self->container->free(self->container);
UI_Events_Unsubscribe(self->listener1);
UI_Events_Unsubscribe(self->listener2);
UI_Events_Unsubscribe(self->listener3);
for (int32_t i = 0; i < MAX_LISTENERS; i++) {
UI_Events_Unsubscribe(self->listeners[i]);
}
Memory_Free(self);
}

Expand Down Expand Up @@ -151,12 +199,15 @@ UI_WIDGET *UI_Console_Create(void)

M_SetPosition(self, WINDOW_MARGIN, WINDOW_MARGIN);

self->listener1 = UI_Events_Subscribe(
"confirm", self->prompt, M_HandlePromptConfirm, NULL);
self->listener2 =
int32_t i = 0;
self->listeners[i++] = UI_Events_Subscribe(
"confirm", self->prompt, M_HandlePromptConfirm, self);
self->listeners[i++] =
UI_Events_Subscribe("cancel", self->prompt, M_HandlePromptCancel, NULL);
self->listener3 =
self->listeners[i++] =
UI_Events_Subscribe("canvas_resize", NULL, M_HandleCanvasResize, self);
self->listeners[i++] =
UI_Events_Subscribe("key_down", NULL, M_HandleKeyDown, self);

return (UI_WIDGET *)self;
}
Expand All @@ -165,6 +216,7 @@ void UI_Console_HandleOpen(UI_WIDGET *const widget)
{
UI_CONSOLE *const self = (UI_CONSOLE *)widget;
UI_Prompt_SetFocus(self->prompt, true);
self->history_idx = Console_History_GetLength();
}

void UI_Console_HandleClose(UI_WIDGET *const widget)
Expand Down
10 changes: 10 additions & 0 deletions src/libtrx/game/ui/widgets/prompt.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ static void M_HandleKeyDown(const EVENT *const event, void *const user_data)
case UI_KEY_BACK: M_DeleteCharBack(self); break;
case UI_KEY_RETURN: M_Confirm(self); break;
case UI_KEY_ESCAPE: M_Cancel(self); break;
default: break;
}
// clang-format on
}
Expand Down Expand Up @@ -305,3 +306,12 @@ void UI_Prompt_Clear(UI_WIDGET *const widget)
UI_PROMPT *const self = (UI_PROMPT *)widget;
M_Clear(self);
}

void UI_Prompt_ChangeText(UI_WIDGET *widget, const char *new_text)
{
UI_PROMPT *const self = (UI_PROMPT *)widget;
Memory_FreePointer(&self->current_text);
self->current_text = Memory_DupStr(new_text);
self->caret_pos = strlen(new_text);
M_UpdateCaretLabel(self);
}
8 changes: 8 additions & 0 deletions src/libtrx/include/libtrx/game/console/history.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <stdint.h>

int32_t Console_History_GetLength(void);
void Console_History_Clear(void);
void Console_History_Append(const char *prompt);
const char *Console_History_Get(int32_t idx);
2 changes: 2 additions & 0 deletions src/libtrx/include/libtrx/game/ui/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "./events.h"

typedef enum {
UI_KEY_UP,
UI_KEY_DOWN,
UI_KEY_LEFT,
UI_KEY_RIGHT,
UI_KEY_HOME,
Expand Down
1 change: 1 addition & 0 deletions src/libtrx/include/libtrx/game/ui/widgets/prompt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ void UI_Prompt_SetSize(UI_WIDGET *widget, int32_t width, int32_t height);

void UI_Prompt_SetFocus(UI_WIDGET *widget, bool is_focused);
void UI_Prompt_Clear(UI_WIDGET *widget);
void UI_Prompt_ChangeText(UI_WIDGET *widget, const char *new_text);

extern const char *UI_Prompt_GetPromptChar(void);
extern int32_t UI_Prompt_GetCaretFlashRate(void);
6 changes: 6 additions & 0 deletions src/libtrx/include/libtrx/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@

#define MKTAG(a, b, c, d) \
((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))

#if TR_VERSION == 1
#define PROJECT_NAME "TR1X"
#elif TR_VERSION == 2
#define PROJECT_NAME "TR2X"
#endif
1 change: 1 addition & 0 deletions src/libtrx/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ sources = [
'game/console/cmd/sfx.c',
'game/console/cmd/teleport.c',
'game/console/common.c',
'game/console/history.c',
'game/game_string.c',
'game/items.c',
'game/objects/names.c',
Expand Down
2 changes: 2 additions & 0 deletions src/tr1/game/ui/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ UI_INPUT UI_TranslateInput(uint32_t system_keycode)
{
// clang-format off
switch (system_keycode) {
case SDLK_UP: return UI_KEY_UP;
case SDLK_DOWN: return UI_KEY_DOWN;
case SDLK_LEFT: return UI_KEY_LEFT;
case SDLK_RIGHT: return UI_KEY_RIGHT;
case SDLK_HOME: return UI_KEY_HOME;
Expand Down
2 changes: 2 additions & 0 deletions src/tr2/game/ui/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ UI_INPUT UI_TranslateInput(uint32_t system_keycode)
{
// clang-format off
switch (system_keycode) {
case VK_UP: return UI_KEY_UP;
case VK_DOWN: return UI_KEY_DOWN;
case VK_LEFT: return UI_KEY_LEFT;
case VK_RIGHT: return UI_KEY_RIGHT;
case VK_HOME: return UI_KEY_HOME;
Expand Down
Loading