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

Maniac´s debugging features: GetCommandInterpreterState (GetGameInfo), maniac_event_info & more debugging extensions #3349

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ add_library(${PROJECT_NAME} OBJECT
src/game_interpreter_battle.h
src/game_interpreter_control_variables.cpp
src/game_interpreter_control_variables.h
src/game_interpreter_debug.cpp
src/game_interpreter_debug.h
src/game_interpreter.cpp
src/game_interpreter.h
src/game_interpreter_map.cpp
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ libeasyrpg_player_a_SOURCES = \
src/game_interpreter_battle.h \
src/game_interpreter_control_variables.cpp \
src/game_interpreter_control_variables.h \
src/game_interpreter_debug.cpp \
src/game_interpreter_debug.h \
src/game_interpreter_map.cpp \
src/game_interpreter_map.h \
src/game_interpreter_shared.cpp \
Expand Down
6 changes: 4 additions & 2 deletions src/filefinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ namespace FileFinder {
* Type of the project. Used to differentiate between supported games (2kX or EasyRPG)
* and known but unsupported (i.e. newer RPG Makers).
*/
enum ProjectType {
enum class ProjectType {
Unknown,
// 2kX or EasyRPG
Supported,
Expand All @@ -62,7 +62,8 @@ namespace FileFinder {
WolfRpgEditor,
Encrypted2k3Maniacs,
RpgMaker95,
SimRpgMaker95
SimRpgMaker95,
LAST
};

constexpr auto kProjectType = lcf::makeEnumTags<ProjectType>(
Expand All @@ -77,6 +78,7 @@ namespace FileFinder {
"RPG Maker 95",
"Sim RPG Maker 95"
);
static_assert(kProjectType.size() == static_cast<size_t>(ProjectType::LAST));

/**
* Helper struct combining the project's directory and its type (used by Game Browser)
Expand Down
2 changes: 1 addition & 1 deletion src/game_commonevent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Game_CommonEvent::Game_CommonEvent(int common_event_id) :
if (ce->trigger == lcf::rpg::EventPage::Trigger_parallel
&& !ce->event_commands.empty()) {
interpreter.reset(new Game_Interpreter_Map());
interpreter->Push(this);
interpreter->Push<InterpreterExecutionType::Parallel>(this);
}


Expand Down
3 changes: 2 additions & 1 deletion src/game_commonevent.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// Headers
#include <string>
#include <vector>
#include "game_interpreter_debug.h"
#include "game_interpreter_map.h"
#include <lcf/rpg/commonevent.h>
#include <lcf/rpg/saveeventexecstate.h>
Expand Down Expand Up @@ -120,7 +121,7 @@ class Game_CommonEvent {
/** Interpreter for parallel common events. */
std::unique_ptr<Game_Interpreter_Map> interpreter;

friend class Scene_Debug;
friend class Game_Interpreter_Inspector;
};

#endif
2 changes: 1 addition & 1 deletion src/game_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ AsyncOp Game_Event::Update(bool resume_async) {
// the wait will tick by 1 each time the interpreter is invoked.
if ((resume_async || GetTrigger() == lcf::rpg::EventPage::Trigger_parallel) && interpreter) {
if (!interpreter->IsRunning() && page && !page->event_commands.empty()) {
interpreter->Push(this);
interpreter->Push<InterpreterExecutionType::Parallel>(this);
}
interpreter->Update(!resume_async);

Expand Down
3 changes: 2 additions & 1 deletion src/game_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "game_character.h"
#include <lcf/rpg/event.h>
#include <lcf/rpg/savemapevent.h>
#include "game_interpreter_debug.h"
#include "game_interpreter_map.h"
#include "async_op.h"

Expand Down Expand Up @@ -218,7 +219,7 @@ class Game_Event : public Game_EventBase {
const lcf::rpg::EventPage* page = nullptr;
std::unique_ptr<Game_Interpreter_Map> interpreter;

friend class Scene_Debug;
friend class Game_Interpreter_Inspector;
};

inline int Game_Event::GetNumPages() const {
Expand Down
131 changes: 116 additions & 15 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ bool Game_Interpreter::IsRunning() const {
}

// Setup.
void Game_Interpreter::Push(
void Game_Interpreter::PushInternal(
InterpreterPush push_info,
std::vector<lcf::rpg::EventCommand> _list,
int event_id,
bool started_by_decision_key,
int event_page_id
) {
if (_list.empty()) {
Expand All @@ -114,15 +114,28 @@ void Game_Interpreter::Push(
Output::Error("Call Event limit ({}) has been exceeded", call_stack_limit);
}

auto type_ex = std::get<ExecutionType>(push_info);
auto type_src = std::get<EventType>(push_info);

lcf::rpg::SaveEventExecFrame frame;
frame.ID = _state.stack.size() + 1;
frame.commands = std::move(_list);
frame.current_command = 0;
frame.triggered_by_decision_key = started_by_decision_key;
frame.event_id = event_id;
frame.triggered_by_decision_key = type_ex == ExecutionType::Action;
if (type_src == EventType::MapEvent) {
frame.event_id = event_id;
}
frame.maniac_event_id = event_id;
frame.maniac_event_page_id = event_page_id;

if (type_ex <= ExecutionType::BattleParallel) {
frame.maniac_event_info = static_cast<int>(type_ex);
}

if (type_src <= EventType::BattleEvent) {
frame.maniac_event_info |= (static_cast<int>(type_src) << 4);
}

if (_state.stack.empty() && main_flag && !Game_Battle::IsBattleRunning()) {
Main_Data::game_system->ClearMessageFace();
Main_Data::game_player->SetMenuCalling(false);
Expand Down Expand Up @@ -529,16 +542,22 @@ void Game_Interpreter::Update(bool reset_loop_count) {
}

// Setup Starting Event
void Game_Interpreter::Push(Game_Event* ev) {
Push(ev->GetList(), ev->GetId(), ev->WasStartedByDecisionKey(), ev->GetActivePage() ? ev->GetActivePage()->ID : 0);
void Game_Interpreter::PushInternal(Game_Event* ev, ExecutionType ex_type) {
PushInternal(
{ ex_type, EventType::MapEvent },
ev->GetList(), ev->GetId(), ev->GetActivePage() ? ev->GetActivePage()->ID : 0
);
}

void Game_Interpreter::Push(Game_Event* ev, const lcf::rpg::EventPage* page, bool triggered_by_decision_key) {
Push(page->event_commands, ev->GetId(), triggered_by_decision_key, page->ID);
void Game_Interpreter::PushInternal(Game_Event* ev, const lcf::rpg::EventPage* page, ExecutionType ex_type) {
PushInternal(
{ ex_type, EventType::MapEvent },
page->event_commands, ev->GetId(), page->ID
);
}

void Game_Interpreter::Push(Game_CommonEvent* ev) {
Push(ev->GetList(), 0, false);
void Game_Interpreter::PushInternal(Game_CommonEvent* ev, ExecutionType ex_type) {
PushInternal({ ex_type, EventType::CommonEvent }, ev->GetList(), ev->GetId());
}

bool Game_Interpreter::CheckGameOver() {
Expand Down Expand Up @@ -3921,7 +3940,7 @@ bool Game_Interpreter::CommandCallEvent(lcf::rpg::EventCommand const& com) { //
return true;
}

Push(common_event);
Push<ExecutionType::Call>(common_event);

return true;
}
Expand Down Expand Up @@ -3949,7 +3968,7 @@ bool Game_Interpreter::CommandCallEvent(lcf::rpg::EventCommand const& com) { //
return true;
}

Push(page->event_commands, event->GetId(), false, page->ID);
Push<ExecutionType::Call, EventType::MapEvent>(page->event_commands, event->GetId(), page->ID);

return true;
}
Expand Down Expand Up @@ -4117,8 +4136,30 @@ bool Game_Interpreter::CommandManiacGetGameInfo(lcf::rpg::EventCommand const& co
Output::Warning("GetGameInfo: Option 'Pixel Info' not implemented.");
break;
case 4: // Get command interpreter state
// FIXME: figure out how 'command interpreter state' works
Output::Warning("GetGameInfo: Option 'Command Interpreter State' not implemented.");
{
// Parameter "Nest" in the English version of Maniacs
// This value specifies how far you'd want to go back the stack
int peek = ValueOrVariableBitfield(com.parameters[0], 2, com.parameters[4]);

//First set everything to '0'
Main_Data::game_variables->SetRange(var, var + 4, 0);

int stack_no = _state.stack.size() - peek;
if (stack_no > 0) {
auto frame = &_state.stack[stack_no - 1];

// Note: It looks like for Battles, Maniacs doesn't give out any detailed interpreter
// information via this command (only the current command line: frame->current_command)
// The others are implemented here nonetheless for consistency.
// (This is true for both the normal "Troop" events & the new "Battle Start"/"Battle Parallel" execution types)

Main_Data::game_variables->Set(var, static_cast<int>(ManiacEventType(*frame)));
Main_Data::game_variables->Set(var + 1, frame->maniac_event_id);
Main_Data::game_variables->Set(var + 2, frame->maniac_event_page_id);
Main_Data::game_variables->Set(var + 3, static_cast<int>(ManiacExecutionType(*frame)));
Main_Data::game_variables->Set(var + 4, frame->current_command + 1);
}
}
break;
case 5: // Get tileset ID
Main_Data::game_variables->Set(var, Game_Map::GetChipset());
Expand Down Expand Up @@ -5320,7 +5361,7 @@ bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& co

// Our implementation pushes a new frame containing the command instead of invoking it directly.
// This is incompatible to Maniacs but has a better compatibility with our code.
Push({ cmd }, GetCurrentEventId(), false); //FIXME: add some new flag, so the interpreter debug view (window_interpreter) can differentiate this frame from normal ones
Push<ExecutionType::Eval, EventType::None>({ cmd }, GetCurrentEventId(), 0);

return true;
}
Expand Down Expand Up @@ -5508,3 +5549,63 @@ int Game_Interpreter::ManiacBitmask(int value, int mask) const {

return value;
}

namespace {
lcf::rpg::SaveEventExecState const& empty_state = {};
}


lcf::rpg::SaveEventExecState const& Game_Interpreter_Inspector::GetForegroundExecState() {
return Game_Interpreter::GetForegroundInterpreter()._state;
}

lcf::rpg::SaveEventExecState& Game_Interpreter_Inspector::GetForegroundExecStateUnsafe() {
return Game_Interpreter::GetForegroundInterpreter()._state;
}

lcf::rpg::SaveEventExecState const& Game_Interpreter_Inspector::GetExecState(Game_Event const& ev) {
if (!ev.interpreter) {
return empty_state;
}
return ev.interpreter->GetState();
}

lcf::rpg::SaveEventExecState const& Game_Interpreter_Inspector::GetExecState(Game_CommonEvent const& ce) {
if (!ce.interpreter) {
return empty_state;
}
return ce.interpreter->GetState();
}

lcf::rpg::SaveEventExecState& Game_Interpreter_Inspector::GetExecStateUnsafe(Game_Event& ev) {
assert(ev.interpreter);
return ev.interpreter->_state;
}

lcf::rpg::SaveEventExecState& Game_Interpreter_Inspector::GetExecStateUnsafe(Game_CommonEvent& ce) {
assert(ce.interpreter);
return ce.interpreter->_state;
}

bool Game_Interpreter_Inspector::IsInActiveExcecution(Game_Event const& ev, bool background_only) {
if (!background_only) {
//TODO
}
if (!ev.IsActive() || ev.GetTrigger() != lcf::rpg::EventPage::Trigger_parallel) {
return false;
}
auto pg = ev.GetActivePage();
if (pg == nullptr || pg->event_commands.empty())
return false;
return ev.interpreter && ev.interpreter->IsRunning();
}

bool Game_Interpreter_Inspector::IsInActiveExcecution(Game_CommonEvent const& ce, bool background_only) {
if (!background_only) {
//TODO
}
if (!ce.IsWaitingBackgroundExecution(false)) {
return false;
}
return ce.interpreter && ce.interpreter->IsRunning();
}
75 changes: 69 additions & 6 deletions src/game_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class Game_Event;
class Game_CommonEvent;
class PendingMessage;


using InterpreterPush = std::tuple<InterpreterExecutionType, InterpreterEventType>;

/**
* Game_Interpreter class
*/
Expand All @@ -64,14 +67,20 @@ class Game_Interpreter : public Game_BaseInterpreterContext

void Update(bool reset_loop_count=true);

template<InterpreterExecutionType type_ex, InterpreterEventType type_ev>
void Push(
std::vector<lcf::rpg::EventCommand> _list,
int _event_id,
bool started_by_decision_key = false,
int event_page_id = 0
std::vector<lcf::rpg::EventCommand> _list,
int _event_id,
int event_page_id = 0
);

template<InterpreterExecutionType type_ex>
void Push(Game_Event* ev);
void Push(Game_Event* ev, const lcf::rpg::EventPage* page, bool triggered_by_decision_key);

template<InterpreterExecutionType type_ex>
void Push(Game_Event* ev, const lcf::rpg::EventPage* page);

template<InterpreterExecutionType type_ex>
void Push(Game_CommonEvent* ev);

void InputButton();
Expand Down Expand Up @@ -348,9 +357,63 @@ class Game_Interpreter : public Game_BaseInterpreterContext
KeyInputState _keyinput;
AsyncOp _async_op = {};

friend class Scene_Debug;
private:
void PushInternal(
InterpreterPush push_info,
std::vector<lcf::rpg::EventCommand> _list,
int _event_id,
int event_page_id = 0
);

void PushInternal(Game_Event* ev, InterpreterExecutionType ex_type);
void PushInternal(Game_Event* ev, const lcf::rpg::EventPage* page, InterpreterExecutionType ex_type);
void PushInternal(Game_CommonEvent* ev, InterpreterExecutionType ex_type);

friend class Game_Interpreter_Inspector;
};

class Game_Interpreter_Inspector {
public:
bool IsInActiveExcecution(Game_Event const& ev, bool background_only);

bool IsInActiveExcecution(Game_CommonEvent const& ce, bool background_only);

lcf::rpg::SaveEventExecState const& GetForegroundExecState();
lcf::rpg::SaveEventExecState& GetForegroundExecStateUnsafe();

lcf::rpg::SaveEventExecState const& GetExecState(Game_Event const& ev);
lcf::rpg::SaveEventExecState const& GetExecState(Game_CommonEvent const& ce);

lcf::rpg::SaveEventExecState& GetExecStateUnsafe(Game_Event& ev);
lcf::rpg::SaveEventExecState& GetExecStateUnsafe(Game_CommonEvent& ce);
};

template<InterpreterExecutionType type_ex, InterpreterEventType type_ev>
inline void Game_Interpreter::Push(std::vector<lcf::rpg::EventCommand> _list, int _event_id, int event_page_id) {
PushInternal({ type_ex, type_ev }, _list, _event_id, event_page_id);
}

template<InterpreterExecutionType type_ex>
inline void Game_Interpreter::Push(Game_Event* ev) {
static_assert(type_ex <= InterpreterExecutionType::Call || type_ex == InterpreterExecutionType::DebugCall, "Unexpected ExecutionType for MapEvent");
PushInternal(ev, type_ex);
}

template<InterpreterExecutionType type_ex>
inline void Game_Interpreter::Push(Game_Event* ev, const lcf::rpg::EventPage* page) {
static_assert(type_ex <= InterpreterExecutionType::Call || type_ex == InterpreterExecutionType::DebugCall, "Unexpected ExecutionType for MapEvent");
PushInternal(ev, page, type_ex);
}

template<InterpreterExecutionType type_ex>
inline void Game_Interpreter::Push(Game_CommonEvent* ev) {
static_assert(type_ex == InterpreterExecutionType::AutoStart || type_ex == InterpreterExecutionType::Parallel
|| type_ex == InterpreterExecutionType::Call || type_ex == InterpreterExecutionType::DeathHandler
|| type_ex == InterpreterExecutionType::DebugCall || type_ex == InterpreterExecutionType::ManiacHook, "Unexpected ExecutionType for CommonEvent"
);
PushInternal(ev, type_ex);
}

inline const lcf::rpg::SaveEventExecFrame* Game_Interpreter::GetFramePtr() const {
return !_state.stack.empty() ? &_state.stack.back() : nullptr;
}
Expand Down
Loading
Loading