Skip to content

Commit

Permalink
fix(fgdpp): add support for modifiers in entity keyvalues, implement …
Browse files Browse the repository at this point in the history
…strata fgd extension
  • Loading branch information
craftablescience committed Jul 10, 2024
1 parent e57759c commit fff4bb9
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
8 changes: 8 additions & 0 deletions include/fgdpp/fgdpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class FGD {
struct Field {
std::string_view name;
std::string_view valueType;
bool readonly;
bool reportable;
std::string_view displayName;
std::string_view valueDefault;
std::string_view description;
Expand All @@ -36,6 +38,8 @@ class FGD {
};

std::string_view name;
bool readonly;
bool reportable;
std::string_view displayName;
std::string_view valueDefault;
std::string_view description;
Expand All @@ -51,6 +55,10 @@ class FGD {
};

std::string_view name;
bool readonly;
bool reportable;
std::string_view displayName;
std::string_view description;
std::vector<Flag> flags;
};

Expand Down
56 changes: 51 additions & 5 deletions src/fgdpp/fgdpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,33 @@ void readEntityIO(BufferStreamReadOnly& stream, BufferStream& backing, FGD::Enti
parser::text::eatWhitespaceAndSingleLineComments(stream);
}

void readEntityFieldModifiers(BufferStreamReadOnly& stream, BufferStream& backing, bool& readonly, bool& reportable) {
readonly = false;
reportable = false;

parser::text::eatWhitespace(stream);
if (stream.peek<char>() == 'r') {
if (auto modifier = parser::text::readUnquotedStringToBuffer(stream, backing); modifier == "readonly") {
readonly = true;
} else if (modifier == "report") {
reportable = true;
return;
} else {
stream.seek(-static_cast<int64_t>(modifier.length()), std::ios::cur);
return;
}
}
parser::text::eatWhitespace(stream);
if (stream.peek<char>() == 'r') {
if (auto modifier = parser::text::readUnquotedStringToBuffer(stream, backing); modifier == "report") {
reportable = true;
} else {
stream.seek(-static_cast<int64_t>(modifier.length()), std::ios::cur);
return;
}
}
}

void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD::Entity& entity) {
// Key and value type (looks like "key(valueType)", or "input key(valueType)" for i/o)
auto name = parser::text::readUnquotedStringToBuffer(stream, backing, "(", parser::text::NO_ESCAPE_SEQUENCES);
Expand All @@ -205,6 +232,7 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD
if (string::iequals(valueType, "choices")) {
auto& field = entity.fieldsWithChoices.emplace_back();
field.name = name;
::readEntityFieldModifiers(stream, backing, field.readonly, field.reportable);

if (::tryToEatSeparator(stream, ':')) {
field.displayName = ::readFGDString(stream, backing);
Expand Down Expand Up @@ -238,6 +266,17 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD
} else if (string::iequals(valueType, "flags")) {
auto& field = entity.fieldsWithFlags.emplace_back();
field.name = name;
::readEntityFieldModifiers(stream, backing, field.readonly, field.reportable);

if (::tryToEatSeparator(stream, ':')) {
field.displayName = ::readFGDString(stream, backing);
parser::text::eatWhitespaceAndSingleLineComments(stream);
}

if (::tryToEatSeparator(stream, ':')) {
field.description = ::readFGDString(stream, backing);
parser::text::eatWhitespaceAndSingleLineComments(stream);
}

if (!::tryToEatSeparator(stream, '=') || !::tryToEatSeparator(stream, '[')) {
throw parser::text::syntax_error{INVALID_SYNTAX_MSG};
Expand All @@ -246,7 +285,7 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD

while (stream.peek<char>() != ']') {
auto& flag = field.flags.emplace_back();
flag.value = parser::text::readUnquotedStringToBuffer(stream, backing, parser::text::NO_ESCAPE_SEQUENCES);
flag.value = ::readFGDString(stream, backing);

if (!::tryToEatSeparator(stream, ':')) {
continue;
Expand All @@ -256,7 +295,7 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD
if (!::tryToEatSeparator(stream, ':')) {
continue;
}
flag.enabledByDefault = parser::text::readUnquotedStringToBuffer(stream, backing, parser::text::NO_ESCAPE_SEQUENCES);
flag.enabledByDefault = ::readFGDString(stream, backing);

if (!::tryToEatSeparator(stream, ':')) {
continue;
Expand All @@ -268,6 +307,7 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD
auto& field = entity.fields.emplace_back();
field.name = name;
field.valueType = valueType;
::readEntityFieldModifiers(stream, backing, field.readonly, field.reportable);
field.displayName = "";
field.valueDefault = "";
field.description = "";
Expand Down Expand Up @@ -299,8 +339,10 @@ void overwriteEntity(FGD::Entity& oldEntity, FGD::Entity& newEntity) {
for (const auto& field : newEntity.fields) {
if (auto it = std::find_if(oldEntity.fields.begin(), oldEntity.fields.end(), [&field](const auto& oldField) {
return oldField.name == field.name;
}); it != oldEntity.fields.end()) {
}); it != oldEntity.fields.end()) {
it->valueType = field.valueType;
it->readonly = field.readonly;
it->reportable = field.reportable;
if (!field.displayName.empty()) {
it->displayName = field.displayName;
}
Expand All @@ -317,7 +359,9 @@ void overwriteEntity(FGD::Entity& oldEntity, FGD::Entity& newEntity) {
for (const auto& field : newEntity.fieldsWithChoices) {
if (auto it = std::find_if(oldEntity.fieldsWithChoices.begin(), oldEntity.fieldsWithChoices.end(), [&field](const auto& oldField) {
return oldField.name == field.name;
}); it != oldEntity.fieldsWithChoices.end()) {
}); it != oldEntity.fieldsWithChoices.end()) {
it->readonly = field.readonly;
it->reportable = field.reportable;
if (!field.displayName.empty()) {
it->displayName = field.displayName;
}
Expand All @@ -335,7 +379,9 @@ void overwriteEntity(FGD::Entity& oldEntity, FGD::Entity& newEntity) {
for (const auto& field : newEntity.fieldsWithFlags) {
if (auto it = std::find_if(oldEntity.fieldsWithFlags.begin(), oldEntity.fieldsWithFlags.end(), [&field](const auto& oldField) {
return oldField.name == field.name;
}); it != oldEntity.fieldsWithFlags.end()) {
}); it != oldEntity.fieldsWithFlags.end()) {
it->readonly = field.readonly;
it->reportable = field.reportable;
it->flags = field.flags;
} else {
oldEntity.fieldsWithFlags.push_back(field);
Expand Down
16 changes: 12 additions & 4 deletions test/res/fgdpp/ideal.fgd
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
"An entity that can be linked to another door and create a passage between them dynamically.\n" +
"This is a separate line!"
[
portal1(int)
portal1(int) readonly
portal2(int) : "Portal 2"
portal3(int) : "Portal 3" : "0"
portal4(int) : "Portal 4" : "0" : "This is the wonderful world of Portal " +
"4"
portal4(int) report : "Portal 4" : "0" : "This is the wonderful world of Portal " +
"4"

input portalInput1(string)
input portalInput2(string) : "Portal Input 2"
Expand All @@ -31,7 +31,7 @@
8 : "nothing" : 1
]

model(choices) : "Model used" : "models/something02.mdl" =
model(choices) readonly report : "Model used" : "models/something02.mdl" =
[
"models/something01.mdl" : "something"
"models/something02.mdl" : "something else (default)"
Expand All @@ -51,6 +51,14 @@
]

output portalOutput3(string) : "Portal Output 3"

effects(flags) : "Effects" : "These sure are effects" =
[
0: "None" : 0
1: "Always, very expensive!" : 0
2: "Bright, dynamic light at entity origin" : 0
4: "Dim, dynamic light at entity origin" : 0
]
]

@MaterialExclusion
Expand Down

0 comments on commit fff4bb9

Please sign in to comment.