mirror of
https://github.com/Corfirean/coa-server-manager.git
synced 2026-11-11 20:01:01 +00:00
Phase 8: stopped realms keep the progression their core last reported; smoke tool project command
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9009550510
commit
c36aaeca74
3 files changed
+40
-2
No files matched your search
@@ -56,7 +56,14 @@ fn with_profile(db: &Db, store: &mut Store, base: &ImportOptions, data_dir: &str
|
||||
}
|
||||
let registry = coa_core::portable::extension::ExtensionRegistry::new();
|
||||
let mut ra = ra_port.and_then(|port| std::env::var("COA_RA_PASSWORD").ok().and_then(|pw| coa_core::ra::Ra::connect_to(port, ra_user, &pw).ok()));
|
||||
let caps = realm::profile::probe_capabilities(db, Some(std::path::Path::new(data_dir)), ra.as_mut(), ®istry).map_err(|e| e.to_string())?;
|
||||
let mut caps = realm::profile::probe_capabilities(db, Some(std::path::Path::new(data_dir)), ra.as_mut(), ®istry).map_err(|e| e.to_string())?;
|
||||
if ra.is_none() {
|
||||
let remembered = store.realm_profile(server).map_err(|e| e.to_string())?;
|
||||
caps = realm::profile::with_remembered_progression(caps, remembered.as_ref()).map_err(|e| e.to_string())?;
|
||||
if caps.progression.is_none() {
|
||||
eprintln!("realm {server}: its progression (level cap) has never been read from a running core: start it once and run `capabilities` with --ra-port");
|
||||
}
|
||||
}
|
||||
let change = store.set_realm_profile(server, &caps, if ra.is_some() { "live" } else { "offline" }).map_err(|e| e.to_string())?;
|
||||
eprintln!("realm {server}: content profile {}{}", &caps.content_profile_hash[..16], if change.changed() { " (new or changed)" } else { "" });
|
||||
Ok(ImportOptions { capabilities: Some(std::sync::Arc::new(caps)), extensions: Some(std::sync::Arc::new(registry)), ..base.clone() })
|
||||
@@ -268,7 +275,7 @@ fn run() -> Result<(), String> {
|
||||
_ if store.server_mappings(model.character_id).map_err(|e| e.to_string())?.iter().any(|m| &m.server_id == server) => coa_core::portable::compat::Operation::Update,
|
||||
_ => coa_core::portable::compat::Operation::OfflineImport,
|
||||
};
|
||||
let report = coa_core::portable::compat::evaluate(&coa_core::portable::compat::Inputs { operation, model: &model, capabilities: &caps, knowledge: opts.knowledge.as_deref(), collections: &[], extensions: opts.extensions.as_deref(), projection_decider: opts.projection.is_some() || matches!(operation, coa_core::portable::compat::Operation::OnlineImport) });
|
||||
let report = coa_core::portable::compat::evaluate(&coa_core::portable::compat::Inputs { operation, model: &model, capabilities: &caps, knowledge: opts.knowledge.as_deref(), collections: &[], extensions: opts.extensions.as_deref(), projection_decider: opts.projection.is_some() || matches!(operation, coa_core::portable::compat::Operation::OnlineImport | coa_core::portable::compat::Operation::RuntimeSession) && ra_port.is_some() });
|
||||
println!("{} on {server} (content profile {}): {:?}", report.operation, &caps.content_profile_hash[..16], report.verdict());
|
||||
for o in &report.outcomes {
|
||||
println!(" {o}");
|
||||
|
||||
@@ -96,6 +96,21 @@ pub fn probe_capabilities(db: &Db, data_dir: Option<&Path>, ra: Option<&mut Ra>,
|
||||
assemble(db, &schema, data_dir, report.as_ref(), registry)
|
||||
}
|
||||
|
||||
/// A profile assembled without the realm's core (a stopped realm) knows nothing of its progression. The progression the realm's core last
|
||||
/// reported live (remembered in the store) is the best there is: the profile gets it, and the core still refuses a character prepared for
|
||||
/// another progression at login, so a realm whose rules changed since is caught, not trusted.
|
||||
pub fn with_remembered_progression(offline: RealmCapabilities, remembered: Option<&RealmCapabilities>) -> Result<RealmCapabilities> {
|
||||
let Some(progression) = remembered.and_then(|r| r.progression.clone()) else { return Ok(offline) };
|
||||
if offline.progression.is_some() {
|
||||
return Ok(offline);
|
||||
}
|
||||
let mut content = offline.content.clone();
|
||||
if remembered.is_some_and(|r| r.content.supports(Feature::LevelProjection)) {
|
||||
content.features.insert(Feature::LevelProjection);
|
||||
}
|
||||
RealmCapabilities::build(offline.core.clone(), content, Some(progression))
|
||||
}
|
||||
|
||||
/// The table-level view an adapter needs to say whether its module is present, before any character is involved.
|
||||
struct NoRealm<'a> {
|
||||
probe: &'a SchemaProbe,
|
||||
|
||||
@@ -234,6 +234,22 @@ mod tests {
|
||||
assert!(matches!(plan_with(&c, 3, Some(&unknown), None), Err(PortableError::ProgressionChanged(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_stopped_realm_keeps_the_progression_its_core_last_reported() {
|
||||
use super::super::profile::with_remembered_progression;
|
||||
let live = caps(60, SIG);
|
||||
let mut offline = live.clone();
|
||||
offline.progression = None;
|
||||
offline.content.features.remove(&Feature::LevelProjection);
|
||||
let offline = RealmCapabilities::build(None, offline.content, None).unwrap();
|
||||
assert!(offline.needs_reprobe());
|
||||
let merged = with_remembered_progression(offline.clone(), Some(&live)).unwrap();
|
||||
assert_eq!(merged.progression, live.progression);
|
||||
assert!(merged.content.supports(Feature::LevelProjection));
|
||||
assert!(with_remembered_progression(offline.clone(), None).unwrap().needs_reprobe(), "nothing remembered, nothing invented");
|
||||
assert_eq!(with_remembered_progression(live.clone(), Some(&caps(70, &"ab".repeat(32)))).unwrap(), live, "a live profile keeps its own");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_query_job_names_its_character_and_its_hash() {
|
||||
let c = geared_level_eighty();
|
||||
|
||||
Reference in new issue
Block a user