Add an un-ordered chunk for extra company settings: PLYX.

This is similar to the PATX chunk.
Minor refactoring to enable some code sharing between two chunks.
Fix MakeSettingsPatxList always regenerating cache.
Update documentation of PATX chunk structure.
This commit is contained in:
Jonathan G Rennison 2015-10-25 21:35:40 +00:00
parent d6395b97a7
commit e606a847c6
3 changed files with 223 additions and 39 deletions

View File

@ -16,6 +16,7 @@
#include "../tunnelbridge_map.h"
#include "../tunnelbridge.h"
#include "../station_base.h"
#include "../settings_func.h"
#include "saveload.h"
@ -486,6 +487,7 @@ static void Load_PLYR()
int index;
while ((index = SlIterateArray()) != -1) {
Company *c = new (index) Company();
SetDefaultCompanySettings(c->index);
SaveLoad_PLYR(c);
_company_colours[index] = (Colours)c->colour;
}
@ -529,7 +531,25 @@ static void Ptrs_PLYR()
}
}
extern void LoadSettingsPlyx(bool skip);
extern void SaveSettingsPlyx();
static void Load_PLYX()
{
LoadSettingsPlyx(false);
}
static void Check_PLYX()
{
LoadSettingsPlyx(true);
}
static void Save_PLYX()
{
SaveSettingsPlyx();
}
extern const ChunkHandler _company_chunk_handlers[] = {
{ 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY | CH_LAST},
{ 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY },
{ 'PLYX', Save_PLYX, Load_PLYX, NULL, Check_PLYX, CH_RIFF | CH_LAST},
};

View File

@ -2235,10 +2235,10 @@ static void SaveSettings(const SettingDesc *sd, void *object)
*
* The PATX chunk contents has the following format:
*
* uint32 chunk flags
* uint32 chunk flags (unused)
* uint32 number of settings
* For each of N settings:
* uint32 setting flags
* uint32 setting flags (unused)
* SLE_STR setting name
* uint32 length of setting field
* N bytes setting field
@ -2269,6 +2269,7 @@ static void MakeSettingsPatxList(const SettingDesc *sd)
static const SettingDesc *previous = NULL;
if (sd == previous) return;
previous = sd;
_sorted_patx_settings.clear();
for (const SettingDesc *desc = sd; desc->save.cmd != SL_END; desc++) {
@ -2279,16 +2280,6 @@ static void MakeSettingsPatxList(const SettingDesc *sd)
std::sort(_sorted_patx_settings.begin(), _sorted_patx_settings.end(), StringSorter());
}
/**
* Internal structure used in LoadSettingsPatx()
* placed outside for legacy compiler compatibility
*/
struct SettingsPatxLoad {
uint32 flags;
char name[256];
uint32 setting_length;
};
/**
* Internal structure used in LoadSettingsPatx()
* placed outside for legacy compiler compatibility
@ -2308,6 +2299,38 @@ struct StringSearcher {
}
};
/**
* Internal structure used in LoadSettingsPatx() and LoadSettingsPlyx()
*/
struct SettingsExtLoad {
uint32 flags;
char name[256];
uint32 setting_length;
};
static const SaveLoad _settings_ext_load_desc[] = {
SLE_VAR(SettingsExtLoad, flags, SLE_UINT32),
SLE_STR(SettingsExtLoad, name, SLE_STRB, 256),
SLE_VAR(SettingsExtLoad, setting_length, SLE_UINT32),
SLE_END()
};
/**
* Internal structure used in SaveSettingsPatx() and SaveSettingsPlyx()
*/
struct SettingsExtSave {
uint32 flags;
const char *name;
uint32 setting_length;
};
static const SaveLoad _settings_ext_save_desc[] = {
SLE_VAR(SettingsExtSave, flags, SLE_UINT32),
SLE_STR(SettingsExtSave, name, SLE_STR, 0),
SLE_VAR(SettingsExtSave, setting_length, SLE_UINT32),
SLE_END()
};
/**
* Load handler for settings which go in the PATX chunk
* @param osd SettingDesc struct containing all information
@ -2318,14 +2341,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object)
{
MakeSettingsPatxList(sd);
SettingsPatxLoad current_setting;
static const SaveLoad _settings_patx_desc[] = {
SLE_VAR(SettingsPatxLoad, flags, SLE_UINT32),
SLE_STR(SettingsPatxLoad, name, SLE_STRB, 256),
SLE_VAR(SettingsPatxLoad, setting_length, SLE_UINT32),
SLE_END()
};
SettingsExtLoad current_setting;
uint32 flags = SlReadUint32();
// flags are not in use yet, reserve for future expansion
@ -2333,7 +2349,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object)
uint32 settings_count = SlReadUint32();
for (uint32 i = 0; i < settings_count; i++) {
SlObject(&current_setting, _settings_patx_desc);
SlObject(&current_setting, _settings_ext_load_desc);
// flags are not in use yet, reserve for future expansion
if (current_setting.flags != 0) SlErrorCorruptFmt("PATX chunk: unknown setting header flags: 0x%X", current_setting.flags);
@ -2377,19 +2393,7 @@ struct SettingToAdd {
*/
static void SaveSettingsPatx(const SettingDesc *sd, void *object)
{
struct SettingsPatxSave {
uint32 flags;
const char *name;
uint32 setting_length;
};
SettingsPatxSave current_setting;
static const SaveLoad _settings_patx_desc[] = {
SLE_VAR(SettingsPatxSave, flags, SLE_UINT32),
SLE_STR(SettingsPatxSave, name, SLE_STR, 0),
SLE_VAR(SettingsPatxSave, setting_length, SLE_UINT32),
SLE_END()
};
SettingsExtSave current_setting;
std::vector<SettingToAdd> settings_to_add;
@ -2402,7 +2406,7 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object)
current_setting.name = desc->patx_name;
// add length of setting header
length += SlCalcObjLength(&current_setting, _settings_patx_desc);
length += SlCalcObjLength(&current_setting, _settings_ext_save_desc);
// add length of actual setting
length += setting_length;
@ -2421,12 +2425,171 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object)
current_setting.flags = 0;
current_setting.name = desc->patx_name;
current_setting.setting_length = settings_to_add[i].setting_length;
SlObject(&current_setting, _settings_patx_desc);
SlObject(&current_setting, _settings_ext_save_desc);
void *ptr = GetVariableAddress(object, &desc->save);
SlObjectMember(ptr, &desc->save);
}
}
/** @file
*
* The PLYX chunk stores additional company settings in an unordered
* format which is tolerant of extra, missing or reordered settings.
* The format is similar to the PATX chunk.
* Additional settings generally means those that aren't in trunk.
*
* The PLYX chunk contents has the following format:
*
* uint32 chunk flags (unused)
* uint32 number of companies
* For each of N companies:
* uint32 company ID
* uint32 company flags (unused)
* uint32 number of settings
* For each of N settings:
* uint32 setting flags (unused)
* SLE_STR setting name
* uint32 length of setting field
* N bytes setting field
*/
/**
* Load handler for company settings which go in the PLYX chunk
* @param check_mode Whether to skip over settings without reading
*/
void LoadSettingsPlyx(bool skip)
{
SettingsExtLoad current_setting;
uint32 chunk_flags = SlReadUint32();
// flags are not in use yet, reserve for future expansion
if (chunk_flags != 0) SlErrorCorruptFmt("PLYX chunk: unknown chunk header flags: 0x%X", chunk_flags);
uint32 company_count = SlReadUint32();
for (uint32 i = 0; i < company_count; i++) {
uint32 company_id = SlReadUint32();
if (company_id >= MAX_COMPANIES) SlErrorCorruptFmt("PLYX chunk: invalid company ID: %u", company_id);
const Company *c = NULL;
if (!skip) {
c = Company::GetIfValid(company_id);
if (c == NULL) SlErrorCorruptFmt("PLYX chunk: non-existant company ID: %u", company_id);
}
uint32 company_flags = SlReadUint32();
// flags are not in use yet, reserve for future expansion
if (company_flags != 0) SlErrorCorruptFmt("PLYX chunk: unknown company flags: 0x%X", company_flags);
uint32 settings_count = SlReadUint32();
for (uint32 j = 0; j < settings_count; j++) {
SlObject(&current_setting, _settings_ext_load_desc);
// flags are not in use yet, reserve for future expansion
if (current_setting.flags != 0) SlErrorCorruptFmt("PLYX chunk: unknown setting header flags: 0x%X", current_setting.flags);
if (skip) {
SlSkipBytes(current_setting.setting_length);
continue;
}
const SettingDesc *setting = NULL;
// not many company settings, so perform a linear scan
for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) {
if (desc->patx_name != NULL && strcmp(desc->patx_name, current_setting.name) == 0) {
setting = desc;
break;
}
}
if (setting != NULL) {
// found setting
const SaveLoad *sld = &(setting->save);
size_t read = SlGetBytesRead();
void *ptr = GetVariableAddress(&(c->settings), sld);
SlObjectMember(ptr, sld);
if (SlGetBytesRead() != read + current_setting.setting_length) {
SlErrorCorruptFmt("PLYX chunk: setting read length mismatch for setting: '%s'", current_setting.name);
}
if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, setting, ReadValue(ptr, sld->conv));
} else {
DEBUG(sl, 1, "PLYX chunk: Could not find company setting: '%s', ignoring", current_setting.name);
SlSkipBytes(current_setting.setting_length);
}
}
}
}
/**
* Save handler for settings which go in the PLYX chunk
*/
void SaveSettingsPlyx()
{
SettingsExtSave current_setting;
static const SaveLoad _settings_plyx_desc[] = {
SLE_VAR(SettingsExtSave, flags, SLE_UINT32),
SLE_STR(SettingsExtSave, name, SLE_STR, 0),
SLE_VAR(SettingsExtSave, setting_length, SLE_UINT32),
SLE_END()
};
std::vector<uint32> company_setting_counts;
size_t length = 8;
uint32 companies_count = 0;
Company *c;
FOR_ALL_COMPANIES(c) {
length += 12;
companies_count++;
uint32 setting_count = 0;
for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) {
if (desc->patx_name == NULL) continue;
uint32 setting_length = SlCalcObjMemberLength(&(c->settings), &desc->save);
if (!setting_length) continue;
current_setting.name = desc->patx_name;
// add length of setting header
length += SlCalcObjLength(&current_setting, _settings_ext_save_desc);
// add length of actual setting
length += setting_length;
setting_count++;
}
company_setting_counts.push_back(setting_count);
}
SlSetLength(length);
SlWriteUint32(0); // flags
SlWriteUint32(companies_count); // companies count
size_t index = 0;
FOR_ALL_COMPANIES(c) {
length += 12;
companies_count++;
SlWriteUint32(c->index); // company ID
SlWriteUint32(0); // flags
SlWriteUint32(company_setting_counts[index]); // setting count
index++;
for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) {
if (desc->patx_name == NULL) continue;
uint32 setting_length = SlCalcObjMemberLength(&(c->settings), &desc->save);
if (!setting_length) continue;
current_setting.flags = 0;
current_setting.name = desc->patx_name;
current_setting.setting_length = setting_length;
SlObject(&current_setting, _settings_plyx_desc);
void *ptr = GetVariableAddress(&(c->settings), &desc->save);
SlObjectMember(ptr, &desc->save);
}
}
}
static void Load_OPTS()
{
/* Copy over default setting since some might not get loaded in

View File

@ -18,8 +18,8 @@ static const SettingDesc _company_settings[] = {
[post-amble]
};
[templates]
SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, NULL),
SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, NULL),
SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, $patxname),
SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, $patxname),
SDT_END = SDT_END()
[defaults]
@ -35,6 +35,7 @@ from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
extver = SlXvFeatureTest()
patxname = NULL