File size: 17,878 Bytes
119e586 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | //! FORGE Generation Engine β Autonomous Environmental Evolution
//!
//! FORGE does not generate terrain. FORGE generates:
//! infrastructure logic, settlement patterns, ecosystem balance,
//! social topology, conflict vectors, economic pressure, architectural identity.
//!
//! When a player says "build a trading post that charges 2% tax" β
//! FORGE constructs the shard, authors the object DNA, writes the behavior rules,
//! patches the economy, and seals the entire act to the WORM chain.
//! No developer wrote this map. FORGE built it. It is now permanent history.
use serde::{Deserialize, Serialize};
use sha2::{Sha256, Digest};
use super::object_dna::{ObjectDna, ObjectKind, BehaviorRule};
use super::world_shard::{WorldShard, ShardKind};
/// A FORGE generation request β what the world needs built
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ForgeRequest {
pub id: String,
pub intent: String, // raw player/agent intent
pub parsed_kind: GenerationKind,
pub district: String,
pub constraints: Vec<String>, // economic, physical, social constraints
pub requester: String, // player ID or agent name
pub seal: String,
pub ts: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum GenerationKind {
Structure, // buildings, walls, roads
Economy, // markets, vaults, banks, tax systems
Ecosystem, // forests, rivers, fauna populations
Social, // community spaces, governance halls
Infrastructure, // roads, bridges, portals between shards
Conflict, // arenas, faction territories, contested zones
Event, // temporary world events β festivals, disasters
}
/// A FORGE generation result β what was built
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ForgeOutput {
pub request_id: String,
pub shard: WorldShard,
pub objects: Vec<ObjectDna>,
pub behavior_script: String, // Lua script for runtime behavior
pub economic_rules: Vec<EconomicRule>,
pub seal: String,
pub worm_id: String,
pub build_ms: u64,
pub ts: u64,
}
/// An economic rule authored by FORGE for a shard
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EconomicRule {
pub id: String,
pub kind: EconomicRuleKind,
pub rate: f64, // tax rate, interest rate, exchange rate
pub condition: String, // when this rule applies
pub beneficiary: String, // who receives the value
pub seal: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum EconomicRuleKind {
Tax,
Tariff,
Subsidy,
InterestRate,
ExchangeRate,
ResourceCap,
}
/// Settlement emergence pattern β how FORGE decides what to build next
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SettlementPressure {
pub population_density: f64, // drives housing and social infra
pub trade_volume: f64, // drives markets and roads
pub conflict_index: f64, // drives arenas and fortifications
pub resource_scarcity: f64, // drives resource extraction structures
pub cultural_momentum: f64, // drives galleries, schools, temples
}
impl SettlementPressure {
/// Determine what FORGE should build next based on systemic pressure
pub fn highest_priority(&self) -> GenerationKind {
let pressures = [
(self.population_density, GenerationKind::Social),
(self.trade_volume, GenerationKind::Economy),
(self.conflict_index, GenerationKind::Conflict),
(self.resource_scarcity, GenerationKind::Infrastructure),
(self.cultural_momentum, GenerationKind::Structure),
];
pressures.iter()
.max_by(|a, b| a.0.partial_cmp(&b.0).unwrap())
.map(|(_, k)| k.clone())
.unwrap_or(GenerationKind::Structure)
}
}
impl ForgeRequest {
pub fn new(
intent: impl Into<String>,
parsed_kind: GenerationKind,
district: impl Into<String>,
requester: impl Into<String>,
) -> Self {
let ts = Self::now();
let intent = intent.into();
let district = district.into();
let requester = requester.into();
let mut h = Sha256::new();
h.update(format!("FORGE-REQ:{:?}:{}:{}:{}", parsed_kind, district, requester, ts).as_bytes());
let seal = hex::encode(h.finalize());
let id = format!("FREQ-{}", &seal[..12].to_uppercase());
Self { id, intent, parsed_kind, district, constraints: vec![], requester, seal, ts }
}
fn now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
}
/// The FORGE engine β parses intent, constructs shards and objects
pub struct ForgeEngine {
pub generations: Vec<ForgeOutput>,
}
impl ForgeEngine {
pub fn new() -> Self { Self { generations: vec![] } }
/// Parse raw player/agent intent into a structured request
pub fn parse_intent(
&self,
raw_intent: &str,
district: &str,
requester: &str,
) -> ForgeRequest {
let kind = Self::classify_intent(raw_intent);
ForgeRequest::new(raw_intent, kind, district, requester)
}
/// Execute a FORGE request β build the shard, objects, and rules
pub fn execute(&mut self, req: ForgeRequest) -> ForgeOutput {
let t0 = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64;
let (shard, objects, econ_rules, script) = match req.parsed_kind {
GenerationKind::Economy => self.build_economy(&req),
GenerationKind::Structure => self.build_structure(&req),
GenerationKind::Social => self.build_social(&req),
GenerationKind::Conflict => self.build_conflict(&req),
GenerationKind::Ecosystem => self.build_ecosystem(&req),
GenerationKind::Infrastructure => self.build_infrastructure(&req),
GenerationKind::Event => self.build_event(&req),
};
let ts = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64;
let build_ms = ts - t0;
let mut h = Sha256::new();
h.update(format!("FORGE-OUT:{}:{}:{}", req.id, shard.id, ts).as_bytes());
let seal = hex::encode(h.finalize());
let worm_id = format!("WORM-FORGE-{}", &seal[..16].to_uppercase());
let output = ForgeOutput {
request_id: req.id, shard, objects, behavior_script: script,
economic_rules: econ_rules, seal, worm_id, build_ms, ts,
};
self.generations.push(output.clone());
output
}
// ββ Generation Routines ββββββββββββββββββββββββββββββββββββββββββββββ
fn build_economy(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
// Parse tax rate from intent if present
let tax_rate = Self::extract_rate(&req.intent, "tax").unwrap_or(0.02);
let mut shard = WorldShard::spawn(
ShardKind::TradingPost,
Self::name_from_intent(&req.intent, "Exchange"),
&req.district, 200,
format!("FORGE built by: {}", req.requester),
);
// Object: market structure
let mut market = ObjectDna::new(ObjectKind::Economic, "Market Hall");
market.attributes.insert("trade_volume".into(), 0.0);
market.attributes.insert("tax_rate".into(), tax_rate);
market.forge_rewrite(
"on_trade",
&format!("price > 0"),
&format!("apply_tax({tax_rate}); seal_ledger(); emit_to_vault()"),
);
// Object: vault
let mut vault = ObjectDna::new(ObjectKind::Economic, "Tax Vault");
vault.attributes.insert("balance".into(), 0.0);
// Economic rule
let mut h = Sha256::new();
h.update(format!("TAX:{}:{}", tax_rate, req.ts).as_bytes());
let rule_seal = hex::encode(h.finalize());
let econ_rule = EconomicRule {
id: format!("ERULE-{}", &rule_seal[..10].to_uppercase()),
kind: EconomicRuleKind::Tax,
rate: tax_rate,
condition: "every_trade".into(),
beneficiary: req.requester.clone(),
seal: rule_seal,
};
shard.forge_patch(format!(
"-- FORGE generated economy script\nTAX_RATE = {tax_rate}\n\
function on_trade(item, price)\n tax = price * TAX_RATE\n\
ledger:seal(item, price, tax)\n vault:deposit(tax)\nend"
));
let script = format!(
"-- Sovereign trading post: {}\n-- Tax: {}%\n-- WORM-sealed every trade",
req.intent, tax_rate * 100.0
);
(shard, vec![market, vault], vec![econ_rule], script)
}
fn build_structure(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
let mut shard = WorldShard::spawn(
ShardKind::BuildZone,
Self::name_from_intent(&req.intent, "Structure"),
&req.district, 50,
format!("FORGE built by: {}", req.requester),
);
let building = ObjectDna::new(ObjectKind::Structure, &req.intent);
let script = format!("-- Structure: {}\n-- All state sealed to WORM", req.intent);
shard.forge_patch(&script);
(shard, vec![building], vec![], script)
}
fn build_social(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
let mut shard = WorldShard::spawn(ShardKind::SocialHub,
Self::name_from_intent(&req.intent, "Hub"), &req.district, 150,
format!("FORGE: {}", req.intent));
let hall = ObjectDna::new(ObjectKind::Structure, "Community Hall");
let script = "-- Social hub: NPC memory events sealed here\n-- Governance voting enabled".into();
shard.forge_patch(script);
(shard, vec![hall], vec![], "-- community hub script".into())
}
fn build_conflict(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
let mut shard = WorldShard::spawn(ShardKind::CombatArena,
Self::name_from_intent(&req.intent, "Arena"), &req.district, 40,
format!("FORGE: {}", req.intent));
let arena = ObjectDna::new(ObjectKind::Structure, "Combat Arena");
let script = "-- Combat arena: every kill sealed to weapon DNA + player ledger".into();
shard.forge_patch(script);
(shard, vec![arena], vec![], "-- combat script".into())
}
fn build_ecosystem(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
let mut shard = WorldShard::spawn(ShardKind::Wilderness,
Self::name_from_intent(&req.intent, "Wilderness"), &req.district, 500,
format!("FORGE: {}", req.intent));
let terrain = ObjectDna::new(ObjectKind::NaturalFeature, "Procedural Terrain");
let script = "-- Ecosystem: resource nodes, fauna population, weather sealed per tick".into();
shard.forge_patch(script);
(shard, vec![terrain], vec![], "-- ecosystem script".into())
}
fn build_infrastructure(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
let mut shard = WorldShard::spawn(ShardKind::Portal,
Self::name_from_intent(&req.intent, "Portal"), &req.district, 1000,
format!("FORGE: {}", req.intent));
let portal = ObjectDna::new(ObjectKind::Portal, "Shard Gate");
let script = "-- Portal: cross-shard travel point, toll optional, usage sealed to ledger".into();
shard.forge_patch(script);
(shard, vec![portal], vec![], "-- infrastructure script".into())
}
fn build_event(&self, req: &ForgeRequest) -> (WorldShard, Vec<ObjectDna>, Vec<EconomicRule>, String) {
let mut shard = WorldShard::spawn(ShardKind::EventSpace,
Self::name_from_intent(&req.intent, "Event"), &req.district, 300,
format!("FORGE event: {}", req.intent));
let stage = ObjectDna::new(ObjectKind::Structure, "Event Stage");
let script = "-- Temporary event shard: auto-tears down when players leave".into();
shard.forge_patch(script);
(shard, vec![stage], vec![], "-- event script".into())
}
// ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
fn classify_intent(intent: &str) -> GenerationKind {
let i = intent.to_lowercase();
if i.contains("tax") || i.contains("market") || i.contains("trade") || i.contains("economy") || i.contains("bank") {
GenerationKind::Economy
} else if i.contains("arena") || i.contains("combat") || i.contains("fight") || i.contains("war") {
GenerationKind::Conflict
} else if i.contains("forest") || i.contains("river") || i.contains("nature") || i.contains("farm") {
GenerationKind::Ecosystem
} else if i.contains("road") || i.contains("bridge") || i.contains("portal") || i.contains("gate") {
GenerationKind::Infrastructure
} else if i.contains("festival") || i.contains("event") || i.contains("celebration") {
GenerationKind::Event
} else if i.contains("hall") || i.contains("community") || i.contains("gather") || i.contains("social") {
GenerationKind::Social
} else {
GenerationKind::Structure
}
}
fn extract_rate(intent: &str, keyword: &str) -> Option<f64> {
let pattern = format!("{}%", keyword);
if let Some(pos) = intent.to_lowercase().find(&pattern) {
let before = &intent[..pos];
let num_start = before.rfind(|c: char| !c.is_ascii_digit() && c != '.').map(|i| i + 1).unwrap_or(0);
if let Ok(rate) = before[num_start..].parse::<f64>() {
return Some(rate / 100.0);
}
}
// Also check "N% tax" pattern
if intent.to_lowercase().contains(keyword) {
// scan for any number near the keyword
for token in intent.split_whitespace() {
let t = token.trim_end_matches('%');
if let Ok(v) = t.parse::<f64>() {
if v > 0.0 && v <= 100.0 {
return Some(v / 100.0);
}
}
}
}
None
}
fn name_from_intent(intent: &str, fallback: &str) -> String {
// Use first 3-4 significant words of intent as the name
let words: Vec<&str> = intent.split_whitespace()
.filter(|w| w.len() > 3)
.take(3)
.collect();
if words.is_empty() { fallback.to_string() } else { words.join(" ") }
}
}
impl Default for ForgeEngine {
fn default() -> Self { Self::new() }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_economy_intent() {
let engine = ForgeEngine::new();
let req = engine.parse_intent(
"Build a trading post that charges 2% tax",
"Downtown", "PLAYER-001",
);
assert_eq!(req.parsed_kind, GenerationKind::Economy);
}
#[test]
fn test_forge_builds_economy_shard() {
let mut engine = ForgeEngine::new();
let req = engine.parse_intent("Build a trading post that charges 2% tax", "Downtown", "PLAYER");
let output = engine.execute(req);
assert!(!output.shard.id.is_empty());
assert!(!output.objects.is_empty());
assert!(!output.economic_rules.is_empty());
assert_eq!(output.economic_rules[0].kind, EconomicRuleKind::Tax);
assert!((output.economic_rules[0].rate - 0.02).abs() < 0.001);
assert!(!output.worm_id.is_empty());
assert!(output.worm_id.starts_with("WORM-FORGE-"));
}
#[test]
fn test_forge_conflict_arena() {
let mut engine = ForgeEngine::new();
let req = engine.parse_intent("create a combat arena for player tournaments", "Underground", "NEXUS");
let output = engine.execute(req);
assert_eq!(output.shard.kind, ShardKind::CombatArena);
}
#[test]
fn test_settlement_pressure_priorities() {
let high_trade = SettlementPressure {
population_density: 0.3,
trade_volume: 0.9,
conflict_index: 0.2,
resource_scarcity: 0.1,
cultural_momentum: 0.4,
};
assert_eq!(high_trade.highest_priority(), GenerationKind::Economy);
let high_conflict = SettlementPressure {
population_density: 0.2, trade_volume: 0.3,
conflict_index: 0.95, resource_scarcity: 0.1, cultural_momentum: 0.2,
};
assert_eq!(high_conflict.highest_priority(), GenerationKind::Conflict);
}
}
|