@bloomengine/engine 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1393,6 +1393,39 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
1393
1393
  }
1394
1394
  #[no_mangle]
1395
1395
  pub extern "C" fn bloom_get_platform() -> f64 { 5.0 }
1396
+
1397
+ /// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag), read
1398
+ /// from the device locale system property via the NDK (no JNI). Tries the
1399
+ /// user-set locale first, then the factory defaults. Falls back to "en".
1400
+ #[no_mangle]
1401
+ pub extern "C" fn bloom_get_language() -> f64 {
1402
+ fn parse(buf: &[u8], n: i32) -> Option<f64> {
1403
+ if n < 2 { return None; }
1404
+ let lc = |b: u8| if b.is_ascii_uppercase() { b + 32 } else { b };
1405
+ let (c0, c1) = (lc(buf[0]), lc(buf[1]));
1406
+ if c0.is_ascii_alphabetic() && c1.is_ascii_alphabetic() {
1407
+ Some((c0 as f64) * 256.0 + (c1 as f64))
1408
+ } else {
1409
+ None
1410
+ }
1411
+ }
1412
+ let props: [&[u8]; 3] = [
1413
+ b"persist.sys.locale\0",
1414
+ b"ro.product.locale\0",
1415
+ b"ro.product.locale.language\0",
1416
+ ];
1417
+ for prop in props {
1418
+ let mut buf = [0u8; 92]; // PROP_VALUE_MAX
1419
+ let n = unsafe {
1420
+ libc::__system_property_get(
1421
+ prop.as_ptr() as *const libc::c_char,
1422
+ buf.as_mut_ptr() as *mut libc::c_char,
1423
+ )
1424
+ };
1425
+ if let Some(v) = parse(&buf, n) { return v; }
1426
+ }
1427
+ 25966.0
1428
+ }
1396
1429
  #[no_mangle]
1397
1430
  pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
1398
1431
  if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
@@ -23,6 +23,6 @@ panic = "abort"
23
23
  image = { version = "0.25", default-features = false, features = ["hdr"] }
24
24
  bloom-shared = { path = "../shared", default-features = false, features = ["mp3"] }
25
25
  objc2 = "0.6"
26
- objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject"] }
26
+ objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject", "NSLocale", "NSArray"] }
27
27
  raw-window-handle = "0.6"
28
28
  wgpu = "29"
@@ -2078,6 +2078,14 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
2078
2078
  }
2079
2079
  #[no_mangle]
2080
2080
  pub extern "C" fn bloom_get_platform() -> f64 { 2.0 }
2081
+
2082
+ /// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag). See macos lib for format.
2083
+ #[no_mangle]
2084
+ pub extern "C" fn bloom_get_language() -> f64 {
2085
+ fn pack(code: &str) -> f64 { let l = code.to_ascii_lowercase(); let b = l.as_bytes(); if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 } }
2086
+ let langs = objc2_foundation::NSLocale::preferredLanguages();
2087
+ match langs.firstObject() { Some(s) => pack(&s.to_string()), None => 25966.0 }
2088
+ }
2081
2089
  #[no_mangle]
2082
2090
  pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
2083
2091
  if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
@@ -1846,6 +1846,14 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
1846
1846
  }
1847
1847
  #[no_mangle]
1848
1848
  pub extern "C" fn bloom_get_platform() -> f64 { 4.0 }
1849
+
1850
+ /// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag), from $LANG/$LC_*.
1851
+ #[no_mangle]
1852
+ pub extern "C" fn bloom_get_language() -> f64 {
1853
+ fn pack(code: &str) -> f64 { let l = code.to_ascii_lowercase(); let b = l.as_bytes(); if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 } }
1854
+ let v = std::env::var("LANG").or_else(|_| std::env::var("LC_ALL")).or_else(|_| std::env::var("LC_MESSAGES")).unwrap_or_default();
1855
+ if v.len() >= 2 && !v.starts_with('C') && !v.starts_with("POSIX") { pack(&v) } else { 25966.0 }
1856
+ }
1849
1857
  #[no_mangle]
1850
1858
  pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
1851
1859
  if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
@@ -27,7 +27,7 @@ panic = "abort"
27
27
  bloom-shared = { path = "../shared", default-features = false, features = ["mp3"] }
28
28
  image = { version = "0.25", default-features = false, features = ["hdr"] }
29
29
  objc2 = "0.6"
30
- objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread"] }
30
+ objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSLocale", "NSArray"] }
31
31
  objc2-app-kit = { version = "0.3", features = ["NSWindow", "NSView", "NSEvent", "NSApplication", "NSScreen", "NSGraphicsContext", "NSRunningApplication", "NSResponder"] }
32
32
  objc2-quartz-core = { version = "0.3", features = ["CAMetalLayer"] }
33
33
  raw-window-handle = "0.6"
@@ -2415,6 +2415,25 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
2415
2415
  }
2416
2416
  #[no_mangle]
2417
2417
  pub extern "C" fn bloom_get_platform() -> f64 { 1.0 }
2418
+
2419
+ /// Return the user's preferred OS language as a packed 2-letter code:
2420
+ /// `c0 * 256 + c1`, where c0/c1 are the ASCII bytes of the lowercased
2421
+ /// ISO-639 primary subtag (e.g. "en-US" -> "en" -> 101*256+110). The script
2422
+ /// subtag is dropped (zh-Hans/zh-Hant both pack as "zh"); callers map that to
2423
+ /// their supported variant. Falls back to "en" when no preference is set.
2424
+ #[no_mangle]
2425
+ pub extern "C" fn bloom_get_language() -> f64 {
2426
+ fn pack(code: &str) -> f64 {
2427
+ let lower = code.to_ascii_lowercase();
2428
+ let b = lower.as_bytes();
2429
+ if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 101.0 * 256.0 + 110.0 }
2430
+ }
2431
+ let langs = objc2_foundation::NSLocale::preferredLanguages();
2432
+ match langs.firstObject() {
2433
+ Some(s) => pack(&s.to_string()),
2434
+ None => pack("en"),
2435
+ }
2436
+ }
2418
2437
  #[no_mangle]
2419
2438
  pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
2420
2439
  if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
@@ -22,7 +22,7 @@ panic = "abort"
22
22
  [dependencies]
23
23
  bloom-shared = { path = "../shared", default-features = false, features = ["mp3"] }
24
24
  objc2 = "0.6"
25
- objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject"] }
25
+ objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject", "NSLocale", "NSArray"] }
26
26
  raw-window-handle = "0.6"
27
27
  wgpu = "29"
28
28
  # Needed by bloom_set_env_clear_from_hdr (HDR env-map decode); mirrors macOS.
@@ -3046,6 +3046,14 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
3046
3046
  }
3047
3047
  #[no_mangle]
3048
3048
  pub extern "C" fn bloom_get_platform() -> f64 { 6.0 }
3049
+
3050
+ /// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag). See macos lib for format.
3051
+ #[no_mangle]
3052
+ pub extern "C" fn bloom_get_language() -> f64 {
3053
+ fn pack(code: &str) -> f64 { let l = code.to_ascii_lowercase(); let b = l.as_bytes(); if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 } }
3054
+ let langs = objc2_foundation::NSLocale::preferredLanguages();
3055
+ match langs.firstObject() { Some(s) => pack(&s.to_string()), None => 25966.0 }
3056
+ }
3049
3057
  #[no_mangle]
3050
3058
  pub extern "C" fn bloom_get_crown_rotation() -> f64 {
3051
3059
  engine().input.consume_crown_rotation()
@@ -206,6 +206,10 @@ pub extern "C" fn perry_scene_will_connect(_scene: *const c_void) {}
206
206
  #[no_mangle]
207
207
  pub extern "C" fn bloom_get_platform() -> f64 { 8.0 }
208
208
 
209
+ /// Preferred OS language packed as `c0*256+c1`. TODO: real per-OS detection; returns "en" for now.
210
+ #[no_mangle]
211
+ pub extern "C" fn bloom_get_language() -> f64 { 25966.0 }
212
+
209
213
  #[no_mangle]
210
214
  pub extern "C" fn bloom_get_crown_rotation() -> f64 { consume_crown() }
211
215
 
@@ -1937,6 +1937,14 @@ pub fn bloom_get_platform() -> f64 {
1937
1937
  7.0 // Web platform ID
1938
1938
  }
1939
1939
 
1940
+ #[wasm_bindgen]
1941
+ pub fn bloom_get_language() -> f64 {
1942
+ // navigator.language (e.g. "en-US" / "zh-Hans") -> packed 2-letter code.
1943
+ let lang = web_sys::window().and_then(|w| w.navigator().language()).unwrap_or_default();
1944
+ let b = lang.to_ascii_lowercase().into_bytes();
1945
+ if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 }
1946
+ }
1947
+
1940
1948
  #[wasm_bindgen]
1941
1949
  pub fn bloom_is_any_input_pressed() -> f64 {
1942
1950
  if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
@@ -28,6 +28,7 @@ wgpu = "29"
28
28
  [target.'cfg(windows)'.dependencies]
29
29
  windows = { version = "0.58", features = [
30
30
  "Win32_Foundation",
31
+ "Win32_Globalization",
31
32
  "Win32_UI_WindowsAndMessaging",
32
33
  "Win32_UI_HiDpi",
33
34
  "Win32_UI_Input_KeyboardAndMouse",
@@ -1635,6 +1635,23 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
1635
1635
  }
1636
1636
  #[no_mangle]
1637
1637
  pub extern "C" fn bloom_get_platform() -> f64 { 3.0 }
1638
+
1639
+ /// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag), from
1640
+ /// `GetUserDefaultLocaleName` (e.g. "en-US" -> "en"). Falls back to "en".
1641
+ #[no_mangle]
1642
+ pub extern "C" fn bloom_get_language() -> f64 {
1643
+ use windows::Win32::Globalization::GetUserDefaultLocaleName;
1644
+ let mut buf = [0u16; 85]; // LOCALE_NAME_MAX_LENGTH
1645
+ let n = unsafe { GetUserDefaultLocaleName(&mut buf) };
1646
+ if n >= 2 {
1647
+ let lc = |c: u16| -> u8 { let b = c as u8; if b.is_ascii_uppercase() { b + 32 } else { b } };
1648
+ let (c0, c1) = (lc(buf[0]), lc(buf[1]));
1649
+ if c0.is_ascii_alphabetic() && c1.is_ascii_alphabetic() {
1650
+ return (c0 as f64) * 256.0 + (c1 as f64);
1651
+ }
1652
+ }
1653
+ 25966.0
1654
+ }
1638
1655
  #[no_mangle]
1639
1656
  pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
1640
1657
  if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloomengine/engine",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "Bloom Engine: native TypeScript game engine compiled by Perry",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -251,6 +251,7 @@
251
251
  { "name": "bloom_inject_gamepad_button_down","params": ["f64"], "returns": "void" },
252
252
  { "name": "bloom_inject_gamepad_button_up","params": ["f64"], "returns": "void" },
253
253
  { "name": "bloom_get_platform", "params": [], "returns": "f64" },
254
+ { "name": "bloom_get_language", "params": [], "returns": "f64" },
254
255
  { "name": "bloom_is_any_input_pressed", "params": [], "returns": "f64" },
255
256
  { "name": "bloom_get_crown_rotation", "params": [], "returns": "f64" },
256
257
 
package/src/core/index.ts CHANGED
@@ -97,6 +97,7 @@ declare function bloom_inject_gamepad_axis(axis: number, value: number): void;
97
97
  declare function bloom_inject_gamepad_button_down(button: number): void;
98
98
  declare function bloom_inject_gamepad_button_up(button: number): void;
99
99
  declare function bloom_get_platform(): number;
100
+ declare function bloom_get_language(): number;
100
101
  declare function bloom_is_any_input_pressed(): number;
101
102
  declare function bloom_get_crown_rotation(): number;
102
103
 
@@ -822,6 +823,11 @@ export const Platform = { UNKNOWN: 0, MACOS: 1, IOS: 2, WINDOWS: 3, LINUX: 4, AN
822
823
 
823
824
  export function getPlatform(): number { return bloom_get_platform(); }
824
825
 
826
+ /// User's preferred OS language as a packed 2-letter code (`c0 * 256 + c1`,
827
+ /// ASCII of the lowercased ISO-639 primary subtag, e.g. "en" = 101*256+110).
828
+ /// Script subtags are dropped (zh-Hans -> "zh"); callers map to their variant.
829
+ export function getLanguage(): number { return bloom_get_language(); }
830
+
825
831
  export function isMobile(): boolean {
826
832
  const p = bloom_get_platform();
827
833
  return p === 2 || p === 5;