Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: EasyRPG/Player
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0f98189e443389d2dc95ba0cc990bdfae71020dc
Choose a base ref
..
head repository: EasyRPG/Player
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4479a7e1245565742ee6b60ac025fdb7eec5d181
Choose a head ref
9 changes: 9 additions & 0 deletions src/async_handler.cpp
Original file line number Diff line number Diff line change
@@ -217,6 +217,15 @@ void AsyncHandler::CreateRequestMapping(const std::string& file) {
}

void AsyncHandler::ClearRequests() {
auto it = async_requests.begin();
while (it != async_requests.end()) {
auto& req = *it;
if (it->second.IsReady()) {
it = async_requests.erase(it);
} else {
++it;
}
}
async_requests.clear();
}

2 changes: 1 addition & 1 deletion src/async_handler.h
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ namespace AsyncHandler {
void CreateRequestMapping(const std::string& file);

/**
* Clears all requests. They will hit the server again.
* Clears all finished requests. They will hit the server again.
* Called after changing the language to ensure the assets are replaced.
*/
void ClearRequests();
5 changes: 2 additions & 3 deletions src/audio.cpp
Original file line number Diff line number Diff line change
@@ -50,9 +50,8 @@ int EmptyAudio::BGM_GetTicks() const {
return (Player::GetFrames() - bgm_starttick + 1) / Game_Clock::GetTargetGameFps();
}

void EmptyAudio::vGetConfig(Game_ConfigAudio& cfg) const {
cfg.music_volume.SetOptionVisible(false);
cfg.sound_volume.SetOptionVisible(false);
void EmptyAudio::vGetConfig(Game_ConfigAudio&) const {
// Not supported. The audio menu is disabled.
}

bool EmptyAudio::BGM_PlayedOnce() const {
4 changes: 2 additions & 2 deletions src/config_param.h
Original file line number Diff line number Diff line change
@@ -356,7 +356,7 @@ class EnumConfigParam : public ConfigParamBase<E> {
EnumConfigParam(StringView name, StringView description, StringView config_section, StringView config_key, E value, std::array<StringView, S> values, std::array<StringView, S> tags, std::array<StringView, S> value_descriptions) :
ConfigParamBase<E>(name, description, config_section, config_key, value), _values{ values }, _tags{ tags}, _value_descriptions{ value_descriptions } {
for (size_t i = 0; i < S; ++i) {
_valid[static_cast<E>(S)] = true;
_valid[static_cast<E>(i)] = true;
}
}

@@ -425,7 +425,7 @@ class EnumConfigParam : public ConfigParamBase<E> {
}

private:
lcf::FlagSet<E> _valid = ~lcf::FlagSet<E>();
lcf::FlagSet<E> _valid;
std::array<StringView, S> _values;
std::array<StringView, S> _tags;
std::array<StringView, S> _value_descriptions;
105 changes: 88 additions & 17 deletions src/exe_reader.cpp
Original file line number Diff line number Diff line change
@@ -24,6 +24,12 @@
#include <algorithm>
#include <iostream>
#include <fstream>
#include <zlib.h>

namespace {
// hashes of known RPG_RT startup logos
std::array<uint32_t, 5> logo_crc32 = { 0xdf3d86a7, 0x2ece66f9, 0x2fe0de56, 0x25c4618f, 0x91b2635a };
}

EXEReader::EXEReader(Filesystem_Stream::InputStream core) : corefile(std::move(core)) {
// The Incredibly Dumb PE parser (tm)
@@ -62,7 +68,7 @@ EXEReader::EXEReader(Filesystem_Stream::InputStream core) : corefile(std::move(c
} else if (secName == 0x50454547) { // GEEP
file_info.geep_size = sectVs;
} else if (secName == 0x30585055) { // UPX0
Output::Debug("EXE is UPX compressed. Engine detection could be incorrect.");
Output::Debug("EXEReader: EXE is UPX compressed. Engine detection could be incorrect.");
}

uint32_t sectRva = GetU32(sectionsOfs + 0x0C);
@@ -76,23 +82,15 @@ EXEReader::EXEReader(Filesystem_Stream::InputStream core) : corefile(std::move(c
}
}

static uint32_t djb2_hash(char* str, size_t length) {
uint32_t hash = 5381;
for (size_t i = 0; i < length; ++i) {
hash = ((hash << 5) + hash) + (uint8_t)str[i];
}
return hash;
}

static std::vector<uint8_t> exe_reader_perform_exfont_save(Filesystem_Stream::InputStream& corefile, uint32_t position, uint32_t len) {
static std::vector<uint8_t> ExtractExFont(Filesystem_Stream::InputStream& corefile, uint32_t position, uint32_t len) {
std::vector<uint8_t> exfont;
constexpr int header_size = 14; // Size of BITMAPFILEHEADER
exfont.resize(len + header_size);

corefile.seekg(position, std::ios_base::beg);
corefile.read(reinterpret_cast<char*>(exfont.data()) + header_size, len);
if (corefile.gcount() != len) {
Output::Debug("ExFont: Error reading resource (read {}, expected {})", corefile.gcount(), len);
Output::Debug("EXEReader: ExFont: Error reading resource (read {}, expected {})", corefile.gcount(), len);
return {};
}

@@ -105,7 +103,7 @@ static std::vector<uint8_t> exe_reader_perform_exfont_save(Filesystem_Stream::In
// And the header that's going to be prepended.
int header_len = header_size + header.size;
if (header.depth != 8) {
Output::Debug("ExFont: Unsupported depth {}", header.depth);
Output::Debug("EXEReader: ExFont: Unsupported depth {}", header.depth);
return {};
}
header_len += header.num_colors * 4;
@@ -132,7 +130,8 @@ static std::vector<uint8_t> exe_reader_perform_exfont_save(Filesystem_Stream::In
exfont[pos++] = (header_len >> 24) & 0xFF;

// Check if the ExFont is the original through a fast hash function
if (djb2_hash((char*)exfont.data() + header_size, exfont.size() - header_size) != 0x491e19de) {
auto crc = crc32(0, exfont.data() + header_size, exfont.size() - header_size);
if (crc != 0x86bc6c68) {
Output::Debug("EXEReader: Custom ExFont found");
}
return exfont;
@@ -169,7 +168,7 @@ std::vector<uint8_t> EXEReader::GetExFont() {
uint32_t filebase = (GetU32(dataent) - resource_rva) + resource_ofs;
uint32_t filesize = GetU32(dataent + 0x04);
Output::Debug("EXEReader: EXFONT resource found (DE {:#x}; {:#x}; len {:#x})", dataent, filebase, filesize);
return exe_reader_perform_exfont_save(corefile, filebase, filesize);
return ExtractExFont(corefile, filebase, filesize);
}
}
resourcesNDEbase += 8;
@@ -179,14 +178,87 @@ std::vector<uint8_t> EXEReader::GetExFont() {
return {};
}

std::vector<std::vector<uint8_t>> EXEReader::GetLogos() {
corefile.clear();

if (!resource_ofs) {
return {};
}

if (Player::player_config.show_startup_logos.Get() == StartupLogos::None) {
return {};
}

std::vector<std::vector<uint8_t>> logos;

uint32_t resourcesIDEs = GetU16(resource_ofs + 0x0C);
if (resourcesIDEs == 1) {
uint32_t resourcesIDEbase = resource_ofs + 0x10;
if (ResNameCheck(exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase)), "XYZ")) {
uint32_t xyz_base = exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase + 4));
uint16_t xyz_logos = std::min<uint16_t>(GetU16(xyz_base + 0x0C), 9);
uint32_t xyz_logo_base = xyz_base + 0x10;

bool only_custom_logos = (Player::player_config.show_startup_logos.Get() == StartupLogos::Custom);
std::string res_name = "LOGOX";

for (int i = 0; i <= xyz_logos; ++i) {
uint32_t name = GetU32(xyz_logo_base);
// Actually a name?
if (name & 0x80000000) {
name = exe_reader_roffset(resource_ofs, name);
res_name.back() = '1' + i;

if (ResNameCheck(name, res_name.c_str()) || (i == 0 && ResNameCheck(name, "LOGO"))) {
uint32_t dataent = GetU32(xyz_logo_base + 4);
if (dataent & 0x80000000) {
dataent = exe_reader_roffset(resource_ofs, dataent);
dataent = resource_ofs + GetU32(dataent + 0x14);
}
uint32_t filebase = (GetU32(dataent) - resource_rva) + resource_ofs;
uint32_t filesize = GetU32(dataent + 0x04);
Output::Debug("EXEReader: {} resource found (DE {:#x}; {:#x}; len {:#x})", res_name, dataent, filebase, filesize);
std::vector<uint8_t> logo;
logo.resize(filesize);

corefile.seekg(filebase, std::ios_base::beg);
corefile.read(reinterpret_cast<char*>(logo.data()), filesize);
if (logo.size() < 8 || strncmp(reinterpret_cast<char*>(logo.data()), "XYZ1", 4) != 0) {
Output::Debug("EXEReader: {}: Not a XYZ image", res_name);
return {};
}

if (corefile.gcount() != filesize) {
Output::Debug("EXEReader: {}: Error reading resource (read {}, expected {})", res_name, corefile.gcount(), filesize);
return {};
}

if (only_custom_logos) {
auto crc = static_cast<uint32_t>(crc32(0, logo.data(), logo.size()));
if (std::find(logo_crc32.begin(), logo_crc32.end(), crc) == logo_crc32.end()) {
logos.push_back(logo);
}
} else {
logos.push_back(logo);
}
}
}

xyz_logo_base += 8;
}
}
}

return logos;
}

const EXEReader::FileInfo& EXEReader::GetFileInfo() {
corefile.clear();

file_info.logos = GetLogoCount();

auto versionDBase = ResOffsetByType(16);
if (versionDBase == 0) {
Output::Debug("EXEReader: VERSIONINFO not found");
return file_info;
}

@@ -282,14 +354,13 @@ uint32_t EXEReader::GetLogoCount() {
if (!resource_ofs) {
return 0;
}
// For each ID/Name entry in the outer...

uint32_t resourcesIDEs = GetU16(resource_ofs + 0x0C);
if (resourcesIDEs == 1) {
uint32_t resourcesIDEbase = resource_ofs + 0x10;
if (ResNameCheck(exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase)), "XYZ")) {
uint32_t xyz_logo_base = exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase + 4));
return static_cast<uint32_t>(GetU16(xyz_logo_base + 0x0C));
return exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase + 4));
}
}
return 0;
1 change: 1 addition & 0 deletions src/exe_reader.h
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@ class EXEReader {
// Extracts an EXFONT resource with BMP header if present
// and returns exfont buffer on success.
std::vector<uint8_t> GetExFont();
std::vector<std::vector<uint8_t>> GetLogos();

struct FileInfo {
uint64_t version = 0;
6 changes: 3 additions & 3 deletions src/filefinder.cpp
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ namespace {
constexpr const auto SOUND_TYPES = Utils::MakeSvArray(
".opus", ".oga", ".ogg", ".wav", ".mp3", ".wma");
constexpr const auto FONTS_TYPES = Utils::MakeSvArray(".fon", ".fnt", ".bdf", ".ttf", ".ttc", ".otf", ".woff2", ".woff");
constexpr const auto TEXT_TYPES = Utils::MakeSvArray(".txt", ".csv", ".svg", ".xml", ".json", ".yml", ".yaml");
constexpr const auto TEXT_TYPES = Utils::MakeSvArray(".txt", ".csv", ""); // "" = Complete Filename (incl. extension) provided by the user
}

FilesystemView FileFinder::Game() {
@@ -352,7 +352,7 @@ std::string find_generic(const DirectoryTree::Args& args) {
}

std::string find_generic_with_fallback(DirectoryTree::Args& args) {
std::string found = FileFinder::Save().FindFile(args);
std::string found = FileFinder::Save().FindFile(args);
if (found.empty()) {
return find_generic(args);
}
@@ -406,7 +406,7 @@ Filesystem_Stream::InputStream open_generic(StringView dir, StringView name, Dir
}

Filesystem_Stream::InputStream open_generic_with_fallback(StringView dir, StringView name, DirectoryTree::Args& args) {
auto is = FileFinder::Save().OpenFile(args);
auto is = FileFinder::Save().OpenFile(args);
if (!is) { is = open_generic(dir, name, args); }
if (!is) {
Output::Debug("Unable to open in either Game or Save: {}/{}", dir, name);
2 changes: 2 additions & 0 deletions src/game_config.cpp
Original file line number Diff line number Diff line change
@@ -425,6 +425,7 @@ void Game_Config::LoadFromStream(Filesystem_Stream::InputStream& is) {
player.settings_autosave.FromIni(ini);
player.settings_in_title.FromIni(ini);
player.settings_in_menu.FromIni(ini);
player.show_startup_logos.FromIni(ini);
}

void Game_Config::WriteToStream(Filesystem_Stream::OutputStream& os) const {
@@ -500,6 +501,7 @@ void Game_Config::WriteToStream(Filesystem_Stream::OutputStream& os) const {
player.settings_autosave.ToIni(os);
player.settings_in_title.ToIni(os);
player.settings_in_menu.ToIni(os);
player.show_startup_logos.ToIni(os);

os << "\n";
}
11 changes: 11 additions & 0 deletions src/game_config.h
Original file line number Diff line number Diff line change
@@ -51,12 +51,23 @@ enum class GameResolution {
Ultrawide
};

enum class StartupLogos {
None,
Custom,
All
};

struct Game_ConfigPlayer {
StringConfigParam autobattle_algo{ "", "", "", "", "" };
StringConfigParam enemyai_algo{ "", "", "", "", "" };
BoolConfigParam settings_autosave{ "Save settings on exit", "Automatically save the settings on exit", "Player", "SettingsAutosave", false };
BoolConfigParam settings_in_title{ "Show settings on title screen", "Display settings menu item on the title screen", "Player", "SettingsInTitle", false };
BoolConfigParam settings_in_menu{ "Show settings in menu", "Display settings menu item on the menu screen", "Player", "SettingsInMenu", false };
EnumConfigParam<StartupLogos, 3> show_startup_logos{
"Startup Logos", "Logos that are displayed on startup", "Player", "StartupLogos", StartupLogos::Custom,
Utils::MakeSvArray("None", "Custom", "All"),
Utils::MakeSvArray("none", "custom", "all"),
Utils::MakeSvArray("Do not show any additional logos", "Show custom logos bundled with the game", "Show all logos, including the original from RPG Maker")};

void Hide();
};
1 change: 1 addition & 0 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
@@ -2175,6 +2175,7 @@ bool Game_Interpreter::CommandChangeHeroName(lcf::rpg::EventCommand const& com)
return true;
}

actor->SetName(ToString(CommandStringOrVariableBitfield(com, 1, 1, 2)));
return true;
}

15 changes: 7 additions & 8 deletions src/game_map.cpp
Original file line number Diff line number Diff line change
@@ -226,13 +226,6 @@ void Game_Map::SetupFromSave(

map = std::move(map_in);
map_info = std::move(save_map);

if (!Player::IsRPG2k3E()) {
// RPG_RT bug: Substitutions are not loaded except in 2k3E
std::iota(map_info.lower_tiles.begin(), map_info.lower_tiles.end(), 0);
std::iota(map_info.upper_tiles.begin(), map_info.upper_tiles.end(), 0);
}

panorama = std::move(save_pan);

SetupCommon();
@@ -267,7 +260,13 @@ void Game_Map::SetupFromSave(
}

SetEncounterSteps(map_info.encounter_steps);
SetChipset(map_info.chipset_id);

// RPG_RT bug: Chipset is not loaded. Fixed in 2k3E
if (Player::IsRPG2k3E()) {
SetChipset(map_info.chipset_id);
} else {
SetChipset(0);
}

if (!is_map_save_compat) {
panorama = {};
Loading