Add Database::user_general_messages()

This commit is contained in:
Oliver Hamlet
2026-01-02 16:41:42 +00:00
parent 744586fe96
commit 1d123c8b21
9 changed files with 170 additions and 17 deletions
+13
View File
@@ -178,6 +178,19 @@ public:
virtual std::vector<Message> GetGeneralMessages(
bool evaluateConditions = false) const = 0;
/**
* @brief Get all general messages listed in the loaded userlist.
* @param evaluateConditions
* If true, any metadata conditions are evaluated before the metadata
* is returned, otherwise unevaluated metadata is returned. Evaluating
* general message conditions also clears the condition cache before
* evaluating conditions.
* @returns A vector of messages supplied in the userlist but not attached to
* any particular plugin.
*/
virtual std::vector<Message> GetUserGeneralMessages(
bool evaluateConditions = false) const = 0;
/**
* @brief Gets the groups that are defined in the loaded metadata lists.
* @param includeUserMetadata
+10
View File
@@ -95,6 +95,16 @@ std::vector<Message> Database::GetGeneralMessages(
}
}
std::vector<Message> Database::GetUserGeneralMessages(
bool evaluateConditions) const {
try {
return convert<Message>(
database_->user_general_messages(evaluateConditions));
} catch (const ::rust::Error& e) {
std::rethrow_exception(mapError(e));
}
}
std::vector<Group> Database::GetGroups(bool includeUserMetadata) const {
try {
return convert<Group>(database_->groups(includeUserMetadata));
+3
View File
@@ -38,6 +38,9 @@ public:
std::vector<Message> GetGeneralMessages(
bool evaluateConditions = false) const override;
std::vector<Message> GetUserGeneralMessages(
bool evaluateConditions = false) const override;
std::vector<Group> GetGroups(bool includeUserMetadata = true) const override;
std::vector<Group> GetUserGroups() const override;
void SetUserGroups(const std::vector<Group>& groups) override;
+14
View File
@@ -144,6 +144,20 @@ impl Database {
.map_err(Into::into)
}
pub fn user_general_messages(
&self,
evaluate_conditions: bool,
) -> Result<Vec<Message>, VerboseError> {
Ok(self
.0
.read()
.map_err(DatabaseLockPoisonError::from)?
.user_general_messages(to_eval_mode(evaluate_conditions))?
.into_iter()
.map(Into::into)
.collect())
}
pub fn groups(&self, include_user_metadata: bool) -> Result<Vec<Group>, VerboseError> {
Ok(self
.0
+2
View File
@@ -276,6 +276,8 @@ mod ffi {
pub fn general_messages(&self, evaluate_conditions: bool) -> Result<Vec<Message>>;
pub fn user_general_messages(&self, evaluate_conditions: bool) -> Result<Vec<Message>>;
pub fn groups(&self, include_user_metadata: bool) -> Result<Vec<Group>>;
pub fn user_groups(&self) -> Result<Vec<Group>>;
@@ -566,6 +566,21 @@ TEST_P(
EXPECT_TRUE(messages.empty());
}
TEST_P(DatabaseInterfaceTest,
getUserGeneralMessagesShouldGetGeneralMessagesFromTheUserlistOnly) {
ASSERT_NO_THROW(GenerateMasterlist());
ASSERT_NO_THROW(GenerateUserlist());
ASSERT_NO_THROW(handle_->GetDatabase().LoadMasterlist(masterlistPath));
ASSERT_NO_THROW(handle_->GetDatabase().LoadUserlist(userlistPath_));
auto messages = handle_->GetDatabase().GetUserGeneralMessages();
std::vector<Message> expectedMessages({
Message(MessageType::say, generalUserlistMessage),
});
EXPECT_EQ(expectedMessages, messages);
}
TEST_P(DatabaseInterfaceTest,
getPluginMetadataShouldReturnAnEmptyOptionalIfThePluginHasNoMetadata) {
EXPECT_FALSE(handle_->GetDatabase().GetPluginMetadata(blankEsm));
+13
View File
@@ -183,6 +183,19 @@ impl Database {
.map_err(Into::into)
}
#[napi]
pub fn user_general_messages(
&self,
evaluate_conditions: EvalMode,
) -> Result<Vec<Message>, VerboseError> {
self.0
.read()
.map_err(DatabaseLockPoisonError::from)?
.user_general_messages(evaluate_conditions.into())
.map(|v| v.into_iter().map(Into::into).collect())
.map_err(Into::into)
}
#[napi]
pub fn groups(&self, include_user_metadata: MergeMode) -> Result<Vec<Group>, VerboseError> {
Ok(self
+12
View File
@@ -148,6 +148,18 @@ impl Database {
.map_err(Into::into)
}
pub fn user_general_messages(
&self,
evaluate_conditions: bool,
) -> Result<Vec<Message>, VerboseError> {
self.0
.read()
.map_err(DatabaseLockPoisonError::from)?
.user_general_messages(to_eval_mode(evaluate_conditions))
.map(|v| v.into_iter().map(Into::into).collect())
.map_err(Into::into)
}
pub fn groups(&self, include_user_metadata: bool) -> Result<Vec<Group>, VerboseError> {
Ok(self
.0
+88 -17
View File
@@ -194,23 +194,26 @@ impl Database {
&self,
evaluate_conditions: EvalMode,
) -> Result<Vec<Message>, ConditionEvaluationError> {
let messages_iter = self
.masterlist
.messages()
.iter()
.chain(self.userlist.messages());
process_messages(
self.masterlist
.messages()
.iter()
.chain(self.userlist.messages()),
&self.condition_evaluator_state,
evaluate_conditions,
)
}
if evaluate_conditions == EvalMode::Evaluate {
let messages = messages_iter
.filter_map(|m| {
filter_map_on_condition(m, m.condition(), &self.condition_evaluator_state)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(messages)
} else {
Ok(messages_iter.cloned().collect())
}
/// Get all general messages listed in the loaded userlist.
pub fn user_general_messages(
&self,
evaluate_conditions: EvalMode,
) -> Result<Vec<Message>, ConditionEvaluationError> {
process_messages(
self.userlist.messages().iter(),
&self.condition_evaluator_state,
evaluate_conditions,
)
}
/// Gets the groups that are defined in the loaded metadata lists.
@@ -281,7 +284,7 @@ impl Database {
}
}
/// Get a plugin's metadata loaded from the given userlist.
/// Get a plugin's metadata loaded from the loaded userlist.
pub fn plugin_user_metadata(
&self,
plugin_name: &str,
@@ -379,6 +382,22 @@ fn merge_groups(lhs: &[Group], rhs: &[Group]) -> Vec<Group> {
groups
}
fn process_messages<'a, I: Iterator<Item = &'a Message>>(
messages_iter: I,
condition_evaluator_state: &loot_condition_interpreter::State,
evaluate_conditions: EvalMode,
) -> Result<Vec<Message>, ConditionEvaluationError> {
if evaluate_conditions == EvalMode::Evaluate {
let messages = messages_iter
.filter_map(|m| filter_map_on_condition(m, m.condition(), condition_evaluator_state))
.collect::<Result<Vec<_>, _>>()?;
Ok(messages)
} else {
Ok(messages_iter.cloned().collect())
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
@@ -1039,6 +1058,58 @@ plugins:
}
}
mod user_general_messages {
use super::*;
#[test]
fn user_general_messages_should_return_only_general_messages_in_the_userlist() {
let fixture = Fixture::new(GameType::Oblivion);
let mut database = fixture.database();
database.load_masterlist(&fixture.metadata_path).unwrap();
let userlist_path = fixture.inner.local_path.join("userlist.yaml");
std::fs::write(
&userlist_path,
"globals: [{type: say, content: 'A user message', condition: 'file(\"missing.esp\")'}]",
)
.unwrap();
database.load_userlist(&userlist_path).unwrap();
assert_eq!(
&[Message::new(MessageType::Say, "A user message".into())
.with_condition("file(\"missing.esp\")".into())],
database
.user_general_messages(EvalMode::DoNotEvaluate)
.unwrap()
.as_slice()
);
}
#[test]
fn should_filter_out_messages_with_false_conditions_when_evaluating_conditions() {
let fixture = Fixture::new(GameType::Oblivion);
let mut database = fixture.database();
let userlist_path = fixture.inner.local_path.join("userlist.yaml");
std::fs::write(
&userlist_path,
"globals: [{type: say, content: 'A user message', condition: 'file(\"missing.esp\")'}]",
)
.unwrap();
database.load_userlist(&userlist_path).unwrap();
assert!(
database
.user_general_messages(EvalMode::Evaluate)
.unwrap()
.is_empty()
);
}
}
mod groups {
use super::*;