Changeset - r27109:b9db4345aeec
[Not reviewed]
master
0 3 0
PeterN - 14 months ago 2023-04-16 20:24:54
peter1138@openttd.org
Codechange: Use std:: features for NewGRF town names (#10631)

This removes manual memory (de-)allocation and list counting.
3 files changed with 88 insertions and 115 deletions:
0 comments (0 inline, 0 general)
src/newgrf.cpp
Show inline comments
 
@@ -7725,8 +7725,8 @@ static void FeatureTownName(ByteReader *
 
		bool new_scheme = _cur.grffile->grf_version >= 7;
 

	
 
		byte lang = buf->ReadByte();
 

	
 
		byte nb_gen = townname->nb_gen;
 
		StringID style = STR_UNDEFINED;
 

	
 
		do {
 
			ClrBit(lang, 7);
 

	
 
@@ -7735,53 +7735,48 @@ static void FeatureTownName(ByteReader *
 
			std::string lang_name = TranslateTTDPatchCodes(grfid, lang, false, name);
 
			grfmsg(6, "FeatureTownName: lang 0x%X -> '%s'", lang, lang_name.c_str());
 

	
 
			townname->name[nb_gen] = AddGRFString(grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
 
			style = AddGRFString(grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
 

	
 
			lang = buf->ReadByte();
 
		} while (lang != 0);
 
		townname->id[nb_gen] = id;
 
		townname->nb_gen++;
 
	}
 

	
 
	byte nb = buf->ReadByte();
 
	grfmsg(6, "FeatureTownName: %u parts", nb);
 

	
 
	townname->nbparts[id] = nb;
 
	townname->partlist[id] = CallocT<NamePartList>(nb);
 

	
 
	for (int i = 0; i < nb; i++) {
 
		byte nbtext =  buf->ReadByte();
 
		townname->partlist[id][i].bitstart  = buf->ReadByte();
 
		townname->partlist[id][i].bitcount  = buf->ReadByte();
 
		townname->partlist[id][i].maxprob   = 0;
 
		townname->partlist[id][i].partcount = nbtext;
 
		townname->partlist[id][i].parts     = CallocT<NamePart>(nbtext);
 
		grfmsg(6, "FeatureTownName: part %d contains %d texts and will use GB(seed, %d, %d)", i, nbtext, townname->partlist[id][i].bitstart, townname->partlist[id][i].bitcount);
 

	
 
		for (int j = 0; j < nbtext; j++) {
 
			byte prob = buf->ReadByte();
 

	
 
			if (HasBit(prob, 7)) {
 
		townname->styles.emplace_back(style, id);
 
	}
 

	
 
	uint8 parts = buf->ReadByte();
 
	grfmsg(6, "FeatureTownName: %u parts", parts);
 

	
 
	townname->partlists[id].reserve(parts);
 
	for (uint partnum = 0; partnum < parts; partnum++) {
 
		NamePartList &partlist = townname->partlists[id].emplace_back();
 
		uint8 texts = buf->ReadByte();
 
		partlist.bitstart = buf->ReadByte();
 
		partlist.bitcount = buf->ReadByte();
 
		partlist.maxprob  = 0;
 
		grfmsg(6, "FeatureTownName: part %u contains %u texts and will use GB(seed, %u, %u)", partnum, texts, partlist.bitstart, partlist.bitcount);
 

	
 
		partlist.parts.reserve(texts);
 
		for (uint textnum = 0; textnum < texts; textnum++) {
 
			NamePart &part = partlist.parts.emplace_back();
 
			part.prob = buf->ReadByte();
 

	
 
			if (HasBit(part.prob, 7)) {
 
				byte ref_id = buf->ReadByte();
 

	
 
				if (townname->nbparts[ref_id] == 0) {
 
				if (ref_id >= GRFTownName::MAX_LISTS || townname->partlists[ref_id].empty()) {
 
					grfmsg(0, "FeatureTownName: definition 0x%02X doesn't exist, deactivating", ref_id);
 
					DelGRFTownName(grfid);
 
					DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
 
					return;
 
				}
 

	
 
				grfmsg(6, "FeatureTownName: part %d, text %d, uses intermediate definition 0x%02X (with probability %d)", i, j, ref_id, prob & 0x7F);
 
				townname->partlist[id][i].parts[j].data.id = ref_id;
 
				part.id = ref_id;
 
				grfmsg(6, "FeatureTownName: part %u, text %u, uses intermediate definition 0x%02X (with probability %u)", partnum, textnum, ref_id, part.prob & 0x7F);
 
			} else {
 
				const char *text = buf->ReadString();
 
				townname->partlist[id][i].parts[j].data.text = stredup(TranslateTTDPatchCodes(grfid, 0, false, text).c_str());
 
				grfmsg(6, "FeatureTownName: part %d, text %d, '%s' (with probability %d)", i, j, townname->partlist[id][i].parts[j].data.text, prob);
 
			}
 
			townname->partlist[id][i].parts[j].prob = prob;
 
			townname->partlist[id][i].maxprob += GB(prob, 0, 7);
 
		}
 
		grfmsg(6, "FeatureTownName: part %d, total probability %d", i, townname->partlist[id][i].maxprob);
 
				part.text = TranslateTTDPatchCodes(grfid, 0, false, text);
 
				grfmsg(6, "FeatureTownName: part %u, text %u, '%s' (with probability %u)", partnum, textnum, part.text.c_str(), part.prob);
 
			}
 
			partlist.maxprob += GB(part.prob, 0, 7);
 
		}
 
		grfmsg(6, "FeatureTownName: part %u, total probability %u", partnum, partlist.maxprob);
 
	}
 
}
 

	
src/newgrf_townname.cpp
Show inline comments
 
@@ -21,15 +21,13 @@
 

	
 
#include "safeguards.h"
 

	
 
static GRFTownName *_grf_townnames = nullptr;
 
static std::vector<GRFTownName> _grf_townnames;
 
static std::vector<StringID> _grf_townname_names;
 

	
 
GRFTownName *GetGRFTownName(uint32 grfid)
 
{
 
	GRFTownName *t = _grf_townnames;
 
	for (; t != nullptr; t = t->next) {
 
		if (t->grfid == grfid) return t;
 
	}
 
	auto found = std::find_if(std::begin(_grf_townnames), std::end(_grf_townnames), [&grfid](const GRFTownName &t){ return t.grfid == grfid; });
 
	if (found != std::end(_grf_townnames)) return &*found;
 
	return nullptr;
 
}
 

	
 
@@ -37,53 +35,31 @@ GRFTownName *AddGRFTownName(uint32 grfid
 
{
 
	GRFTownName *t = GetGRFTownName(grfid);
 
	if (t == nullptr) {
 
		t = CallocT<GRFTownName>(1);
 
		t = &_grf_townnames.emplace_back();
 
		t->grfid = grfid;
 
		t->next = _grf_townnames;
 
		_grf_townnames = t;
 
	}
 
	return t;
 
}
 

	
 
void DelGRFTownName(uint32 grfid)
 
{
 
	GRFTownName *t = _grf_townnames;
 
	GRFTownName *p = nullptr;
 
	for (;t != nullptr; p = t, t = t->next) if (t->grfid == grfid) break;
 
	if (t != nullptr) {
 
		for (int i = 0; i < 128; i++) {
 
			for (int j = 0; j < t->nbparts[i]; j++) {
 
				for (int k = 0; k < t->partlist[i][j].partcount; k++) {
 
					if (!HasBit(t->partlist[i][j].parts[k].prob, 7)) free(t->partlist[i][j].parts[k].data.text);
 
				}
 
				free(t->partlist[i][j].parts);
 
			}
 
			free(t->partlist[i]);
 
		}
 
		if (p != nullptr) {
 
			p->next = t->next;
 
		} else {
 
			_grf_townnames = t->next;
 
		}
 
		free(t);
 
	}
 
	_grf_townnames.erase(std::find_if(std::begin(_grf_townnames), std::end(_grf_townnames), [&grfid](const GRFTownName &t){ return t.grfid == grfid; }));
 
}
 

	
 
static char *RandomPart(char *buf, GRFTownName *t, uint32 seed, byte id, const char *last)
 
static char *RandomPart(char *buf, const GRFTownName *t, uint32 seed, byte id, const char *last)
 
{
 
	assert(t != nullptr);
 
	for (int i = 0; i < t->nbparts[id]; i++) {
 
		byte count = t->partlist[id][i].bitcount;
 
		uint16 maxprob = t->partlist[id][i].maxprob;
 
		uint32 r = (GB(seed, t->partlist[id][i].bitstart, count) * maxprob) >> count;
 
		for (int j = 0; j < t->partlist[id][i].partcount; j++) {
 
			byte prob = t->partlist[id][i].parts[j].prob;
 
			maxprob -= GB(prob, 0, 7);
 
	for (const auto &partlist : t->partlists[id]) {
 
		byte count = partlist.bitcount;
 
		uint16 maxprob = partlist.maxprob;
 
		uint32 r = (GB(seed, partlist.bitstart, count) * maxprob) >> count;
 
		for (const auto &part : partlist.parts) {
 
			maxprob -= GB(part.prob, 0, 7);
 
			if (maxprob > r) continue;
 
			if (HasBit(prob, 7)) {
 
				buf = RandomPart(buf, t, seed, t->partlist[id][i].parts[j].data.id, last);
 
			if (HasBit(part.prob, 7)) {
 
				buf = RandomPart(buf, t, seed, part.id, last);
 
			} else {
 
				buf = strecat(buf, t->partlist[id][i].parts[j].data.text, last);
 
				buf = strecat(buf, part.text.c_str(), last);
 
			}
 
			break;
 
		}
 
@@ -94,12 +70,10 @@ static char *RandomPart(char *buf, GRFTo
 
char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last)
 
{
 
	strecpy(buf, "", last);
 
	for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) {
 
		if (t->grfid == grfid) {
 
			assert(gen < t->nb_gen);
 
			buf = RandomPart(buf, t, seed, t->id[gen], last);
 
			break;
 
		}
 
	const GRFTownName *t = GetGRFTownName(grfid);
 
	if (t != nullptr) {
 
		assert(gen < t->styles.size());
 
		buf = RandomPart(buf, t, seed, t->styles[gen].id, last);
 
	}
 
	return buf;
 
}
 
@@ -109,8 +83,10 @@ char *GRFTownNameGenerate(char *buf, uin
 
void InitGRFTownGeneratorNames()
 
{
 
	_grf_townname_names.clear();
 
	for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) {
 
		for (int j = 0; j < t->nb_gen; j++) _grf_townname_names.push_back(t->name[j]);
 
	for (const auto &t : _grf_townnames) {
 
		for (const auto &style : t.styles) {
 
			_grf_townname_names.push_back(style.name);
 
		}
 
	}
 
}
 

	
 
@@ -119,31 +95,31 @@ const std::vector<StringID>& GetGRFTownN
 
	return _grf_townname_names;
 
}
 

	
 
StringID GetGRFTownNameName(uint gen)
 
StringID GetGRFTownNameName(uint16 gen)
 
{
 
	return gen < _grf_townname_names.size() ? _grf_townname_names[gen] : STR_UNDEFINED;
 
}
 

	
 
void CleanUpGRFTownNames()
 
{
 
	while (_grf_townnames != nullptr) DelGRFTownName(_grf_townnames->grfid);
 
	_grf_townnames.clear();
 
}
 

	
 
uint32 GetGRFTownNameId(int gen)
 
uint32 GetGRFTownNameId(uint16 gen)
 
{
 
	for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) {
 
		if (gen < t->nb_gen) return t->grfid;
 
		gen -= t->nb_gen;
 
	for (const auto &t : _grf_townnames) {
 
		if (gen < t.styles.size()) return t.grfid;
 
		gen -= static_cast<uint16>(t.styles.size());
 
	}
 
	/* Fallback to no NewGRF */
 
	return 0;
 
}
 

	
 
uint16 GetGRFTownNameType(int gen)
 
uint16 GetGRFTownNameType(uint16 gen)
 
{
 
	for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) {
 
		if (gen < t->nb_gen) return gen;
 
		gen -= t->nb_gen;
 
	for (const auto &t : _grf_townnames) {
 
		if (gen < t.styles.size()) return gen;
 
		gen -= static_cast<uint16>(t.styles.size());
 
	}
 
	/* Fallback to english original */
 
	return SPECSTR_TOWNNAME_ENGLISH;
src/newgrf_townname.h
Show inline comments
 
@@ -17,29 +17,31 @@
 
#include "strings_type.h"
 

	
 
struct NamePart {
 
	byte prob;     ///< The relative probability of the following name to appear in the bottom 7 bits.
 
	union {
 
		char *text;    ///< If probability bit 7 is clear
 
		byte id;       ///< If probability bit 7 is set
 
	} data;
 
	std::string text; ///< If probability bit 7 is clear
 
	byte id;          ///< If probability bit 7 is set
 
	byte prob;        ///< The relative probability of the following name to appear in the bottom 7 bits.
 
};
 

	
 
struct NamePartList {
 
	byte partcount;
 
	byte bitstart;
 
	byte bitcount;
 
	uint16 maxprob;
 
	NamePart *parts;
 
	byte bitstart;  ///< Start of random seed bits to use.
 
	byte bitcount;  ///< Number of bits of random seed to use.
 
	uint16 maxprob; ///< Total probability of all parts.
 
	std::vector<NamePart> parts; ///< List of parts to choose from.
 
};
 

	
 
struct TownNameStyle {
 
	StringID name; ///< String ID of this town name style.
 
	byte id;       ///< Index within partlist for this town name style.
 

	
 
	TownNameStyle(StringID name, byte id) : name(name), id(id) { }
 
};
 

	
 
struct GRFTownName {
 
	uint32 grfid;
 
	byte nb_gen;
 
	byte id[128];
 
	StringID name[128];
 
	byte nbparts[128];
 
	NamePartList *partlist[128];
 
	GRFTownName *next;
 
	static const uint MAX_LISTS = 128; ///< Maximum number of town name lists that can be defined per GRF.
 

	
 
	uint32 grfid;                                   ///< GRF ID of NewGRF.
 
	std::vector<TownNameStyle> styles;              ///< Style names defined by the Town Name NewGRF.
 
	std::vector<NamePartList> partlists[MAX_LISTS]; ///< Lists of town name parts.
 
};
 

	
 
GRFTownName *AddGRFTownName(uint32 grfid);
 
@@ -47,9 +49,9 @@ GRFTownName *GetGRFTownName(uint32 grfid
 
void DelGRFTownName(uint32 grfid);
 
void CleanUpGRFTownNames();
 
char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last);
 
uint32 GetGRFTownNameId(int gen);
 
uint16 GetGRFTownNameType(int gen);
 
StringID GetGRFTownNameName(uint gen);
 
uint32 GetGRFTownNameId(uint16 gen);
 
uint16 GetGRFTownNameType(uint16 gen);
 
StringID GetGRFTownNameName(uint16 gen);
 

	
 
const std::vector<StringID>& GetGRFTownNameList();
 

	
0 comments (0 inline, 0 general)