#genie #age-of-empires #drs #genie-engine #scx #lang #empires

genie-lang

Read different types of language resource files from Age of Empires 1 and 2

3 unstable releases

0.2.1 May 18, 2020
0.2.0 Aug 4, 2019
0.1.0 Apr 9, 2019

#2245 in Rust patterns

Download history 8/week @ 2023-11-08 14/week @ 2023-11-15 13/week @ 2023-11-22 19/week @ 2023-11-29 12/week @ 2023-12-06 14/week @ 2023-12-13 16/week @ 2023-12-20 12/week @ 2023-12-27 9/week @ 2024-01-03 12/week @ 2024-01-10 12/week @ 2024-01-17 12/week @ 2024-01-24 14/week @ 2024-01-31 16/week @ 2024-02-07 36/week @ 2024-02-14 108/week @ 2024-02-21

178 downloads per month
Used in 2 crates

GPL-3.0 license

52KB
1K SLoC

genie-lang

docs.rs crates.io GitHub license MSRV

Read different types of language resource files from Age of Empires 1 and 2.

License

GPL-3.0


lib.rs:

genie-lang reads language files into a map of UTF-8 strings. All three major language file types used by Age of Empires versions are supported: DLLs, INI files, and HD Edition's key-value format.

DLLs are used by the original games. INI files are used for Voobly mods, and can be used with a standard AoC installation through the aoc-language-ini mod.

DLLs

use genie_lang::{LangFileType::Dll, StringKey};
use std::{convert::TryFrom, fs::File};
let f = File::open("./test/dlls/language_x1_p1.dll")?;
let lang_file = Dll.read_from(f)?;
assert_eq!(
    lang_file.get(&StringKey::try_from(30177).unwrap()),
    Some(&String::from("Turbo Random Map - Buildings create units faster, villagers gather faster, build faster, and carry more.")));
assert_eq!(
    lang_file.get(&StringKey::try_from(20156).unwrap()),
    Some(&String::from("<b>Byzantines<b> \n\
          Defensive civilization \n\
          · Buildings +10% HPs Dark, +20% Feudal, \n +30% Castle, +40% Imperial Age \n\
          · Camels, skirmishers, Pikemen, Halberdiers cost -25% \n\
          · Fire ships +20% attack \n\
          · Advance to Imperial Age costs -33% \n\
          · Town Watch free \n\n\
          <b>Unique Unit:<b> Cataphract (cavalry) \n\n\
          <b>Unique Tech:<b> Logistica (Cataphracts cause trample damage) \n\n\
          <b>Team Bonus:<b> Monks +50% heal speed")));

INI files

use genie_lang::{LangFileType::Ini, StringKey};
use std::{convert::TryFrom, io::Cursor};
let text = br#"
46523=The Uighurs will join if you kill Ornlu the wolf and return to tell the tale.
; a comment
46524=Uighurs: Yes, that is the pelt of the great wolf. We will join you, Genghis Khan. And to seal the agreement, we will give you the gift of flaming arrows!
"#;
let f = Cursor::new(&text[..]);
let lang_file = Ini.read_from(f)?;
assert_eq!(
    lang_file.get(&StringKey::try_from(46523).unwrap()),
    Some(&String::from("The Uighurs will join if you kill Ornlu the wolf and return to tell the tale.")));

HD key-value files

use genie_lang::{LangFileType::KeyValue, StringKey};
use std::{convert::TryFrom, io::Cursor};
let text = br#"
46523 "The Uighurs will join if you kill Ornlu the wolf and return to tell the tale."
46524 "Uighurs: Yes, that is the pelt of the great wolf. We will join you, Genghis Khan. And to seal the agreement, we will give you the gift of flaming arrows!"
46604 "Kill the traitor, Kushluk.\n\nPrevent the tent of Genghis Khan (Wonder) from being destroyed."
LOBBYBROWSER_DATMOD_TITLE_FORMAT "DatMod: \"%s\""
"#;
let f = Cursor::new(&text[..]);
let lang_file = KeyValue.read_from(f)?;
assert_eq!(
    lang_file.get(&StringKey::try_from(46523).unwrap()),
    Some(&String::from("The Uighurs will join if you kill Ornlu the wolf and return to tell the tale.")));
assert_eq!(
    lang_file.get(&StringKey::from("LOBBYBROWSER_DATMOD_TITLE_FORMAT")),
    Some(&String::from(r#"DatMod: "%s""#)));

Creating a file from scratch

use genie_lang::{LangFile, StringKey};
use std::{convert::TryFrom, str};
let mut lang_file = LangFile::new();
lang_file.insert(StringKey::try_from(46604).unwrap(), String::from("Kill the traitor, Kushluk.\n\n\
                      Prevent the tent of Genghis Khan (Wonder) from being destroyed."));
let mut out = vec![];
lang_file.write_to_ini(&mut out)?;
assert_eq!(
    str::from_utf8(&out)?,
    r"46604=Kill the traitor, Kushluk.\n\nPrevent the tent of Genghis Khan (Wonder) from being destroyed.
");
lang_file.insert(StringKey::from("LOBBYBROWSER_DATMOD_TITLE_FORMAT"), String::from(r#"DatMod: "%s""#));
let mut out = vec![];
lang_file.write_to_keyval(&mut out)?;
let result_string = str::from_utf8(&out)?;
println!("{}", result_string);
assert!(
    result_string == r#"46604 "Kill the traitor, Kushluk.\n\nPrevent the tent of Genghis Khan (Wonder) from being destroyed."
LOBBYBROWSER_DATMOD_TITLE_FORMAT "DatMod: \"%s\""
"#
    ||
    result_string == r#"LOBBYBROWSER_DATMOD_TITLE_FORMAT "DatMod: \"%s\""
46604 "Kill the traitor, Kushluk.\n\nPrevent the tent of Genghis Khan (Wonder) from being destroyed."
"#);

Dependencies

~5MB
~149K SLoC