Add chat history #100

Merged
TheBrokenRail merged 6 commits from bigjango13/minecraft-pi-reborn:master into master 2024-03-19 02:06:04 +00:00
8 changed files with 48 additions and 39 deletions
Showing only changes of commit 5e5088e3ef - Show all commits

View File

@ -3,7 +3,7 @@
#include <symbols/minecraft.h>
struct TextInputBox {
static TextInputBox *create(const std::string &placeholder = "", const std::string &text = "", const std::vector<std::string> *history = NULL);
static TextInputBox *create(const std::string &placeholder = "", const std::string &text = "");
bigjango13 marked this conversation as resolved Outdated

IMO the history code should be part of chat, not the text input widget.

IMO the history code should be part of chat, not the text input widget.

I agree, however that makes input trickier and setting the text harder (unless there was isFocused and setText methods). This also has the benefit of being really easy to add history to any other text input, such as for a modded terminal.

I agree, however that makes input trickier and setting the text harder (unless there was `isFocused` and `setText` methods). This also has the benefit of being really easy to add history to any other text input, such as for a modded terminal.

Then, why not just... add setText and isFocused methods? Realistically chat is the only thing that will ever need this code. And if something else does need it, it can also just be re-implemented really easily.

Then, why not just... add `setText` and `isFocused` methods? Realistically chat is the only thing that will ever need this code. And if something else does need it, it can also just be re-implemented really easily.

Right, but what about input?

Right, but what about input?

What do you mean? Just add code to keyPressed in chat/ui.cpp.

What do you mean? Just add code to `keyPressed` in `chat/ui.cpp`.

Done 👍

Done 👍
GuiComponent super;
@ -18,11 +18,10 @@ struct TextInputBox {
void onClick(int x, int y);
bool clicked(int x, int y);
std::string getText();
void setText(std::string text);
bool isFocused();
void setMaxLength(int max_length);
int history_pos;
private:
void recalculateScroll();
@ -40,5 +39,4 @@ private:
Font *m_pFont;
int m_maxLength;
int m_scrollPos;
const std::vector<std::string> *history;
};

View File

@ -15,11 +15,16 @@ static std::vector<std::string> &get_history() {
return history;
}
static std::string index_vec(const std::vector<std::string> &vec, int pos) {
return pos == int(vec.size()) ? "" : vec.at(pos);
}
// Structure
struct ChatScreen {
TextInputScreen super;
TextInputBox *chat;
Button *send;
int history_pos;
};
CUSTOM_VTABLE(chat_screen, Screen) {
TextInputScreen::setup(vtable);
@ -29,10 +34,11 @@ CUSTOM_VTABLE(chat_screen, Screen) {
original_init(super);
ChatScreen *self = (ChatScreen *) super;
// Text Input
self->chat = TextInputBox::create("", "", &get_history());
self->chat = TextInputBox::create();
self->super.m_textInputs->push_back(self->chat);
self->chat->init(super->font);
self->chat->setFocused(true);
self->history_pos = get_history().size();
// Determine Max Length
std::string prefix = _chat_get_prefix(Strings_default_username);
int max_length = MAX_CHAT_MESSAGE_LENGTH - prefix.length();
@ -91,6 +97,24 @@ CUSTOM_VTABLE(chat_screen, Screen) {
_chat_queue_message(text.c_str());
}
Minecraft_setScreen(super->minecraft, NULL);
} else if (key == 0x26 && self->chat->isFocused()) {
// Up
int old_pos = self->history_pos;
self->history_pos -= 1;
if (self->history_pos < 0) self->history_pos = get_history().size();
if (old_pos != self->history_pos) {
self->chat->setText(index_vec(get_history(), self->history_pos));
bigjango13 marked this conversation as resolved
Review

Is this check needed? Because if old_pos == self->history_pos, wouldn't that just call setText with the current text, doing nothing?

Is this check needed? Because if `old_pos == self->history_pos`, wouldn't that just call `setText` with the current text, doing nothing?
Review

Yep, that's left over.

Yep, that's left over.
}
return;
} else if (key == 0x28 && self->chat->isFocused()) {
// Down
int old_pos = self->history_pos;
self->history_pos += 1;
if (self->history_pos > int(get_history().size())) self->history_pos = 0;
if (old_pos != self->history_pos) {
self->chat->setText(index_vec(get_history(), self->history_pos));
}
return;
}
// Call Original Method
original_keyPressed(super, key);

View File

@ -8,7 +8,7 @@
// Death Messages
static const char *monster_names[] = {"Zombie", "Creeper", "Skeleton", "Spider", "Zombie Pigman"};
static std::string get_death_message(Player *player, Entity *cause, bool was_shot = false) {
std::string get_death_message(Player *player, Entity *cause, bool was_shot = false) {
// Prepare Death Message
std::string message = player->username;
if (cause) {

View File

@ -2,16 +2,7 @@
#include <mods/text-input-box/TextInputBox.h>
static int get_vec_size(const std::vector<std::string> *vec) {
return vec ? vec->size() : 0;
}
static std::string index_vec(const std::vector<std::string> *vec, int pos) {
if (vec == NULL || pos == get_vec_size(vec)) return "";
return vec->at(pos);
}
TextInputBox *TextInputBox::create(const std::string &placeholder, const std::string &text, const std::vector<std::string> *history) {
TextInputBox *TextInputBox::create(const std::string &placeholder, const std::string &text) {
// Construct
TextInputBox *self = new TextInputBox;
GuiComponent_constructor(&self->super);
@ -31,8 +22,6 @@ TextInputBox *TextInputBox::create(const std::string &placeholder, const std::st
self->m_pFont = nullptr;
self->m_maxLength = -1;
self->m_scrollPos = 0;
self->history = history;
self->history_pos = get_vec_size(history);
// Return
return self;
@ -99,16 +88,6 @@ void TextInputBox::keyPressed(int key) {
recalculateScroll();
break;
}
case 0x26: {
// Up
int old_pos = history_pos;
history_pos -= 1;
if (history_pos < 0) history_pos = get_vec_size(history);
if (old_pos == history_pos) break;
m_text = index_vec(history, history_pos);
m_insertHead = int(m_text.size());
break;
}
case 0x27: {
// Right
m_insertHead++;
@ -122,16 +101,6 @@ void TextInputBox::keyPressed(int key) {
recalculateScroll();
break;
}
case 0x28: {
// Down
int old_pos = history_pos;
history_pos += 1;
if (history_pos > get_vec_size(history)) history_pos = 0;
if (old_pos == history_pos) break;
m_text = index_vec(history, history_pos);
m_insertHead = int(m_text.size());
break;
}
case 0x0d: {
// Enter
m_bFocused = false;
@ -316,6 +285,11 @@ std::string TextInputBox::getText() {
return m_text;
}
void TextInputBox::setText(std::string str) {
m_text = str;
m_insertHead = int(m_text.size());
}
bool TextInputBox::isFocused() {
return m_bFocused;
}

View File

@ -6,4 +6,4 @@ property Minecraft *mc = 0x18;
method void renderItem(Mob *mob, ItemInstance *item) = 0x4b824;
method void render(float param_1) = 0x4bfcc;
static-property ItemInHandRenderer *instance = 0x137bc0;
static-property ItemInHandRenderer **instance = 0x137bc0;
bigjango13 marked this conversation as resolved Outdated

This seems wrong. I think this address actually refers to an EntityRenderDispatcher. Which then has a first property of ItemInHandRenderer.

  this_00 = (ItemInHandRenderer *)operator.new(0x70dc);
  ItemInHandRenderer::ItemInHandRenderer(this_00,param_1);
  this->field0_0x0 = this_00;
  ppIVar1 = (ItemInHandRenderer **)EntityRenderDispatcher::getInstance();
  *ppIVar1 = this->field0_0x0;
This seems wrong. I think this address actually refers to an `EntityRenderDispatcher`. Which then has a first property of `ItemInHandRenderer`. ```c++ this_00 = (ItemInHandRenderer *)operator.new(0x70dc); ItemInHandRenderer::ItemInHandRenderer(this_00,param_1); this->field0_0x0 = this_00; ppIVar1 = (ItemInHandRenderer **)EntityRenderDispatcher::getInstance(); *ppIVar1 = this->field0_0x0; ```

Yup, it's EntityRenderer::entityRenderDispatcher.

Yup, it's `EntityRenderer::entityRenderDispatcher`.

View File

@ -4,5 +4,6 @@ method void colorABGR(int color) = 0x52b54;
method void color(int r, int g, int b, int a) = 0x52a48;
method void vertex(float x, float y, float z) = 052bc0;
method void vertexUV(float x, float y, float z, float u, float v) = 0x52d40;
method void addOffset(float x, float y, float z) = 0x52d90;
static-property Tesselator instance = 0x137538;

View File

@ -23,6 +23,8 @@ virtual-method void tick(Level *level, int x, int y, int z) = 0x58;
virtual-method void neighborChanged(Level *level, int x, int y, int z, int neighborId) = 0x64;
virtual-method void onPlace(Level *level, int x, int y, int z) = 0x68;
virtual-method void onRemove(Level *level, int x, int y, int z) = 0x6c;
virtual-method int getResource(int data, Random *random) = 0x70;
virtual-method int getResourceCount(Random *random) = 0x74;
virtual-method int getRenderLayer() = 0x94;
virtual-method int use(Level *level, int x, int y, int z, Player *player) = 0x98;
virtual-method void setPlacedBy(Level *level, int x, int y, int z, Mob *placer) = 0xa8;
@ -38,6 +40,12 @@ virtual-method Tile *setDestroyTime(float destroy_time) = 0xf8;
property int texture = 0x4;
property int id = 0x8;
property float x1 = 0xc;
property float y1 = 0x10;
property float z1 = 0x14;
property float x2 = 0x18;
property float y2 = 0x1c;
property float z2 = 0x20;
property int category = 0x3c;
property AABB aabb = 0x40;

View File

@ -2,7 +2,11 @@ size 0xb8;
constructor (Minecraft *minecraft, LevelSource *level) = 0x53e58;
static-method bool canRender(int shape) = 0x5accc;
method bool tesselateBlockInWorld(Tile *tile, int x, int y, int z) = 0x59e30;
method bool tesselateInWorld(Tile *tile, int x, int y, int z) = 0x5e80c;
method void renderGuiTile(Tile *tile, int aux) = 0x5ad0c;
method void renderTile(Tile *tile, int data) = 0x5dcb0;
property LevelSource *level = 0x0;