Initial Horizon OS bringup
This commit is contained in:
parent
2860938b9a
commit
5d92cafe67
18
Cargo.toml
18
Cargo.toml
|
@ -32,7 +32,7 @@ category = "Game"
|
||||||
osx_minimum_system_version = "10.12"
|
osx_minimum_system_version = "10.12"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["default-base", "backend-sdl", "render-opengl", "exe"]
|
default = ["default-base", "backend-sdl", "render-opengl", "exe", "webbrowser"]
|
||||||
default-base = ["ogg-playback"]
|
default-base = ["ogg-playback"]
|
||||||
ogg-playback = ["lewton"]
|
ogg-playback = ["lewton"]
|
||||||
backend-sdl = ["sdl2", "sdl2-sys"]
|
backend-sdl = ["sdl2", "sdl2-sys"]
|
||||||
|
@ -48,11 +48,11 @@ android = []
|
||||||
#glutin = { path = "./3rdparty/glutin/glutin", optional = true }
|
#glutin = { path = "./3rdparty/glutin/glutin", optional = true }
|
||||||
#lua-ffi = { path = "./3rdparty/luajit-rs", optional = true }
|
#lua-ffi = { path = "./3rdparty/luajit-rs", optional = true }
|
||||||
#winit = { path = "./3rdparty/winit", optional = true, default_features = false, features = ["x11"] }
|
#winit = { path = "./3rdparty/winit", optional = true, default_features = false, features = ["x11"] }
|
||||||
#sdl2 = { path = "./3rdparty/rust-sdl2", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
|
sdl2 = { path = "./3rdparty/rust-sdl2", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
|
||||||
#sdl2-sys = { path = "./3rdparty/rust-sdl2/sdl2-sys", optional = true, features = ["bundled", "static-link"] }
|
sdl2-sys = { path = "./3rdparty/rust-sdl2/sdl2-sys", optional = true, features = ["bundled", "static-link"] }
|
||||||
byteorder = "1.4"
|
byteorder = "1.4"
|
||||||
case_insensitive_hashmap = "1.0.0"
|
case_insensitive_hashmap = "1.0.0"
|
||||||
chrono = "0.4"
|
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
|
||||||
cpal = "0.14"
|
cpal = "0.14"
|
||||||
directories = "3"
|
directories = "3"
|
||||||
downcast = "0.11"
|
downcast = "0.11"
|
||||||
|
@ -68,9 +68,9 @@ lua-ffi = { git = "https://github.com/doukutsu-rs/lua-ffi.git", rev = "e0b2ff596
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
pelite = ">=0.9.2"
|
pelite = { version = ">=0.9.2", default-features = false, features = ["std"] }
|
||||||
sdl2 = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "95bcf63768abf422527f86da41da910649b9fcc9", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
|
#sdl2 = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "95bcf63768abf422527f86da41da910649b9fcc9", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
|
||||||
sdl2-sys = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "95bcf63768abf422527f86da41da910649b9fcc9", optional = true, features = ["bundled", "static-link"] }
|
#sdl2-sys = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "95bcf63768abf422527f86da41da910649b9fcc9", optional = true, features = ["bundled", "static-link"] }
|
||||||
rc-box = "1.2.0"
|
rc-box = "1.2.0"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
|
@ -81,7 +81,7 @@ strum = "0.24"
|
||||||
strum_macros = "0.24"
|
strum_macros = "0.24"
|
||||||
# remove and replace when drain_filter is in stable
|
# remove and replace when drain_filter is in stable
|
||||||
vec_mut_scan = "0.4"
|
vec_mut_scan = "0.4"
|
||||||
webbrowser = "0.8"
|
webbrowser = { version = "0.8", optional = true }
|
||||||
#winit = { git = "https://github.com/alula/winit.git", rev = "6acf76ff192dd8270aaa119b9f35716c03685f9f", optional = true, default_features = false, features = ["x11"] }
|
#winit = { git = "https://github.com/alula/winit.git", rev = "6acf76ff192dd8270aaa119b9f35716c03685f9f", optional = true, default_features = false, features = ["x11"] }
|
||||||
winit = { version = "0.27", optional = true, default_features = false, features = ["x11"] }
|
winit = { version = "0.27", optional = true, default_features = false, features = ["x11"] }
|
||||||
xmltree = "0.10"
|
xmltree = "0.10"
|
||||||
|
@ -100,3 +100,5 @@ ndk = "0.7"
|
||||||
ndk-glue = "0.7"
|
ndk-glue = "0.7"
|
||||||
ndk-sys = "0.4"
|
ndk-sys = "0.4"
|
||||||
jni = "0.20"
|
jni = "0.20"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "horizon")'.dependencies]
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
[package]
|
[package]
|
||||||
name = "drsandroid"
|
name = "drsandroid"
|
||||||
|
description = "doukutsu-rs targeted for Android"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Alula"]
|
edition = "2021"
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ndk = "0.3"
|
ndk = "0.7"
|
||||||
ndk-glue = "0.3"
|
ndk-glue = "0.7"
|
||||||
ndk-sys = "0.2"
|
ndk-sys = "0.4"
|
||||||
doukutsu-rs = { path = "../", default-features = false, features = ["default-base", "backend-glutin"] }
|
doukutsu-rs = { path = "../", default-features = false, features = ["default-base", "backend-glutin", "webbrowser"] }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[cfg_attr(target_os = "android", ndk_glue::main())]
|
#[cfg_attr(target_os = "android", ndk_glue::main())]
|
||||||
pub fn android_main() {
|
pub fn android_main() {
|
||||||
let options = doukutsu_rs::LaunchOptions { server_mode: false, editor: false };
|
let options = doukutsu_rs::game::LaunchOptions { server_mode: false, editor: false };
|
||||||
|
|
||||||
doukutsu_rs::init(options).unwrap();
|
doukutsu_rs::init(options).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
[build]
|
||||||
|
target = ["aarch64-nintendo-switch"]
|
||||||
|
|
||||||
|
[target.aarch64-nintendo-switch]
|
||||||
|
cc = {path = "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc"}
|
||||||
|
cxx = {path = "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-g++"}
|
||||||
|
ar = "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-ar"
|
||||||
|
ranlib = {path = "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-ranlib"}
|
||||||
|
linker = "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc"
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "drshorizon"
|
||||||
|
description = "doukutsu-rs targeted for Nintendo Switch"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
doukutsu-rs = { path = "../", default-features = false, features = ["default-base"] }
|
|
@ -0,0 +1,3 @@
|
||||||
|
Experimental. Nothing to see there yet.
|
||||||
|
|
||||||
|
ld script and .specs taken from devkitPro
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"arch": "aarch64",
|
||||||
|
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||||
|
"dynamic-linking": true,
|
||||||
|
"disable-redzone": true,
|
||||||
|
"env": "newlib",
|
||||||
|
"executables": true,
|
||||||
|
"exe-suffix": ".elf",
|
||||||
|
"features": "+a57,+strict-align,+crc,+crypto",
|
||||||
|
"has-rpath": false,
|
||||||
|
"linker": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc",
|
||||||
|
"linker-flavor": "gcc",
|
||||||
|
"llvm-target": "aarch64-unknown-none",
|
||||||
|
"max-atomic-width": 128,
|
||||||
|
"no-default-libraries": false,
|
||||||
|
"os": "horizon",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"position-independent-executables": true,
|
||||||
|
"pre-link-args": {
|
||||||
|
"gcc": [
|
||||||
|
"-fPIC",
|
||||||
|
"-specs",
|
||||||
|
"aarch64_nintendo_switch.specs",
|
||||||
|
"-T",
|
||||||
|
"aarch64_nintendo_switch.ld",
|
||||||
|
"-L",
|
||||||
|
"/opt/devkitpro/portlibs/switch/lib",
|
||||||
|
"-L",
|
||||||
|
"/opt/devkitpro/libnx/lib"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"relocation-model": "pic",
|
||||||
|
"requires-uwtable": true,
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-family": ["unix"],
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"trap-unreachable": true,
|
||||||
|
"vendor": "nintendo"
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
OUTPUT_ARCH(aarch64)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
code PT_LOAD FLAGS(5) /* Read | Execute */;
|
||||||
|
rodata PT_LOAD FLAGS(4) /* Read */;
|
||||||
|
data PT_LOAD FLAGS(6) /* Read | Write */;
|
||||||
|
dyn PT_DYNAMIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* =========== CODE section =========== */
|
||||||
|
PROVIDE(__start__ = 0x0);
|
||||||
|
. = __start__;
|
||||||
|
__code_start = . ;
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
HIDDEN(__text_start = .);
|
||||||
|
KEEP (*(.crt0))
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} :code
|
||||||
|
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP( *(.init) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} :code
|
||||||
|
|
||||||
|
.plt :
|
||||||
|
{
|
||||||
|
*(.plt)
|
||||||
|
*(.iplt)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} :code
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP( *(.fini) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} :code
|
||||||
|
|
||||||
|
/* =========== RODATA section =========== */
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
__rodata_start = . ;
|
||||||
|
|
||||||
|
.nx-module-name : { KEEP (*(.nx-module-name)) } :rodata
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } :rodata
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } :rodata
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } :rodata
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } : rodata
|
||||||
|
|
||||||
|
HIDDEN(__dynamic_start = .);
|
||||||
|
.dynamic : { *(.dynamic) } :rodata :dyn
|
||||||
|
.dynsym : { *(.dynsym) } :rodata
|
||||||
|
.dynstr : { *(.dynstr) } :rodata
|
||||||
|
.rela.dyn : { *(.rela.*) } :rodata
|
||||||
|
.interp : { *(.interp) } :rodata
|
||||||
|
.hash : { *(.hash) } :rodata
|
||||||
|
.gnu.hash : { *(.gnu.hash) } :rodata
|
||||||
|
.gnu.version : { *(.gnu.version) } :rodata
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) } :rodata
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) } :rodata
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) } :rodata
|
||||||
|
|
||||||
|
/* =========== DATA section =========== */
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
__data_start = . ;
|
||||||
|
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } :data
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } :data
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } : data
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } :data
|
||||||
|
|
||||||
|
.tdata ALIGN(8) :
|
||||||
|
{
|
||||||
|
__tdata_lma = .;
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
__tdata_lma_end = .;
|
||||||
|
} :data
|
||||||
|
|
||||||
|
.tbss ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} :data
|
||||||
|
|
||||||
|
.preinit_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} :data
|
||||||
|
|
||||||
|
.init_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP( *(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)) )
|
||||||
|
KEEP( *(.init_array .ctors) )
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} :data
|
||||||
|
|
||||||
|
.fini_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP( *(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)) )
|
||||||
|
KEEP( *(.fini_array .dtors) )
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} :data
|
||||||
|
|
||||||
|
__got_start__ = .;
|
||||||
|
|
||||||
|
.got : { *(.got) *(.igot) } :data
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) } :data
|
||||||
|
|
||||||
|
__got_end__ = .;
|
||||||
|
|
||||||
|
.data ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
} :data
|
||||||
|
|
||||||
|
__bss_start__ = .;
|
||||||
|
.bss ALIGN(8) :
|
||||||
|
{
|
||||||
|
HIDDEN(__bss_start = .);
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(8);
|
||||||
|
|
||||||
|
/* Reserve space for the TLS segment of the main thread */
|
||||||
|
__tls_start = .;
|
||||||
|
. += + SIZEOF(.tdata) + SIZEOF(.tbss);
|
||||||
|
__tls_end = .;
|
||||||
|
HIDDEN(__bss_end = .);
|
||||||
|
} :data
|
||||||
|
__bss_end__ = .;
|
||||||
|
|
||||||
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
__argdata__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== Metadata ====
|
||||||
|
================== */
|
||||||
|
|
||||||
|
/* Discard sections that difficult post-processing */
|
||||||
|
/DISCARD/ : { *(.group .comment .note) }
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -pie --no-dynamic-linker --spare-dynamic-tags=0 -z text -z nodynamic-undefined-weak --build-id=sha1 --nx-module-name
|
||||||
|
|
||||||
|
*startfile:
|
||||||
|
crti%O%s crtbegin%O%s --require-defined=main
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-lib=dylib=nx");
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd "$(dirname "$0")" || exit
|
||||||
|
set -e
|
||||||
|
|
||||||
|
rustup run rust-switch cargo build -Z build-std=core,alloc,std,panic_abort --target aarch64-nintendo-switch.json
|
||||||
|
|
||||||
|
rm -f target/aarch64-nintendo-switch/debug/drshorizon.nro
|
||||||
|
rm -f target/aarch64-nintendo-switch/debug/drshorizon.nacp
|
||||||
|
|
||||||
|
echo "Creating NACP..."
|
||||||
|
nacptool --create 'doukutsu-rs' 'doukutsu-rs contributors' '0.100.0' target/aarch64-nintendo-switch/debug/drshorizon.nacp
|
||||||
|
|
||||||
|
echo "Running elf2nro..."
|
||||||
|
elf2nro target/aarch64-nintendo-switch/debug/drshorizon.elf target/aarch64-nintendo-switch/debug/drshorizon.nro \
|
||||||
|
--icon=../res/nx_icon.jpg \
|
||||||
|
--nacp=target/aarch64-nintendo-switch/debug/drshorizon.nacp
|
||||||
|
|
||||||
|
echo "done."
|
|
@ -0,0 +1,27 @@
|
||||||
|
//#![feature(restricted_std)]
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PrintConsole {}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn consoleInit(unk: *mut PrintConsole) -> *mut PrintConsole;
|
||||||
|
|
||||||
|
pub fn consoleUpdate(unk: *mut PrintConsole);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
consoleInit(std::ptr::null_mut());
|
||||||
|
|
||||||
|
let options = doukutsu_rs::game::LaunchOptions { server_mode: false, editor: false };
|
||||||
|
let result = doukutsu_rs::game::init(options);
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
println!("Initialization error: {}", e);
|
||||||
|
loop {
|
||||||
|
consoleUpdate(std::ptr::null_mut());
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
|
@ -27,10 +27,23 @@ impl Backend for NullBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "horizon")]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PrintConsole {}
|
||||||
|
|
||||||
|
#[cfg(target_os = "horizon")]
|
||||||
|
extern "C" { fn consoleUpdate(unk: *mut PrintConsole); }
|
||||||
|
|
||||||
pub struct NullEventLoop;
|
pub struct NullEventLoop;
|
||||||
|
|
||||||
impl BackendEventLoop for NullEventLoop {
|
impl BackendEventLoop for NullEventLoop {
|
||||||
fn run(&mut self, game: &mut Game, ctx: &mut Context) {
|
fn run(&mut self, game: &mut Game, ctx: &mut Context) {
|
||||||
|
println!("BackendEventLoop::run");
|
||||||
|
#[cfg(target_os = "horizon")]
|
||||||
|
unsafe {
|
||||||
|
consoleUpdate(std::ptr::null_mut());
|
||||||
|
}
|
||||||
|
|
||||||
let state_ref = unsafe { &mut *game.state.get() };
|
let state_ref = unsafe { &mut *game.state.get() };
|
||||||
|
|
||||||
ctx.screen_size = (640.0, 480.0);
|
ctx.screen_size = (640.0, 480.0);
|
||||||
|
@ -54,6 +67,11 @@ impl BackendEventLoop for NullEventLoop {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
|
||||||
game.draw(ctx).unwrap();
|
game.draw(ctx).unwrap();
|
||||||
|
|
||||||
|
#[cfg(target_os = "horizon")]
|
||||||
|
unsafe {
|
||||||
|
consoleUpdate(std::ptr::null_mut());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
108
src/game/mod.rs
108
src/game/mod.rs
|
@ -221,8 +221,8 @@ pub fn init(options: LaunchOptions) -> GameResult {
|
||||||
.with_level(log::Level::Info.to_level_filter())
|
.with_level(log::Level::Info.to_level_filter())
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
let resource_dir = if let Ok(data_dir) = std::env::var("CAVESTORY_DATA_DIR") {
|
let resource_dir = if let Ok(data_dir) = std::env::var("CAVESTORY_DATA_DIR") {
|
||||||
PathBuf::from(data_dir)
|
PathBuf::from(data_dir)
|
||||||
} else {
|
} else {
|
||||||
let mut resource_dir = std::env::current_exe()?;
|
let mut resource_dir = std::env::current_exe()?;
|
||||||
|
@ -231,46 +231,46 @@ pub fn init(options: LaunchOptions) -> GameResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
let mut bundle_dir = resource_dir.clone();
|
let mut bundle_dir = resource_dir.clone();
|
||||||
let _ = bundle_dir.pop();
|
let _ = bundle_dir.pop();
|
||||||
let mut bundle_exec_dir = bundle_dir.clone();
|
let mut bundle_exec_dir = bundle_dir.clone();
|
||||||
let mut csplus_data_dir = bundle_dir.clone();
|
let mut csplus_data_dir = bundle_dir.clone();
|
||||||
let _ = csplus_data_dir.pop();
|
let _ = csplus_data_dir.pop();
|
||||||
let _ = csplus_data_dir.pop();
|
let _ = csplus_data_dir.pop();
|
||||||
let mut csplus_data_base_dir = csplus_data_dir.clone();
|
let mut csplus_data_base_dir = csplus_data_dir.clone();
|
||||||
csplus_data_base_dir.push("data");
|
csplus_data_base_dir.push("data");
|
||||||
csplus_data_base_dir.push("base");
|
csplus_data_base_dir.push("base");
|
||||||
|
|
||||||
bundle_exec_dir.push("MacOS");
|
bundle_exec_dir.push("MacOS");
|
||||||
bundle_dir.push("Resources");
|
bundle_dir.push("Resources");
|
||||||
|
|
||||||
if bundle_exec_dir.is_dir() && bundle_dir.is_dir() {
|
if bundle_exec_dir.is_dir() && bundle_dir.is_dir() {
|
||||||
log::info!("Running in macOS bundle mode");
|
log::info!("Running in macOS bundle mode");
|
||||||
|
|
||||||
if csplus_data_base_dir.is_dir() {
|
if csplus_data_base_dir.is_dir() {
|
||||||
log::info!("Cave Story+ Steam detected");
|
log::info!("Cave Story+ Steam detected");
|
||||||
resource_dir = csplus_data_dir;
|
resource_dir = csplus_data_dir;
|
||||||
} else {
|
} else {
|
||||||
resource_dir = bundle_dir;
|
resource_dir = bundle_dir;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resource_dir.push("data");
|
resource_dir.push("data");
|
||||||
resource_dir
|
resource_dir
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
log::info!("Resource directory: {:?}", resource_dir);
|
log::info!("Resource directory: {:?}", resource_dir);
|
||||||
log::info!("Initializing engine...");
|
log::info!("Initializing engine...");
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
mount_vfs(&mut context, Box::new(PhysicalFS::new(&resource_dir, true)));
|
mount_vfs(&mut context, Box::new(PhysicalFS::new(&resource_dir, true)));
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
let project_dirs = match directories::ProjectDirs::from("", "", "doukutsu-rs") {
|
let project_dirs = match directories::ProjectDirs::from("", "", "doukutsu-rs") {
|
||||||
Some(dirs) => dirs,
|
Some(dirs) => dirs,
|
||||||
None => {
|
None => {
|
||||||
use crate::framework::error::GameError;
|
use crate::framework::error::GameError;
|
||||||
|
@ -278,35 +278,35 @@ pub fn init(options: LaunchOptions) -> GameResult {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
let mut data_path =
|
let mut data_path =
|
||||||
PathBuf::from(ndk_glue::native_activity().internal_data_path().to_string_lossy().to_string());
|
PathBuf::from(ndk_glue::native_activity().internal_data_path().to_string_lossy().to_string());
|
||||||
let mut user_path = data_path.clone();
|
let mut user_path = data_path.clone();
|
||||||
|
|
||||||
data_path.push("data");
|
data_path.push("data");
|
||||||
user_path.push("saves");
|
user_path.push("saves");
|
||||||
|
|
||||||
let _ = std::fs::create_dir_all(&data_path);
|
let _ = std::fs::create_dir_all(&data_path);
|
||||||
let _ = std::fs::create_dir_all(&user_path);
|
let _ = std::fs::create_dir_all(&user_path);
|
||||||
|
|
||||||
log::info!("Android data directories: data_path={:?} user_path={:?}", &data_path, &user_path);
|
log::info!("Android data directories: data_path={:?} user_path={:?}", &data_path, &user_path);
|
||||||
|
|
||||||
mount_vfs(&mut context, Box::new(PhysicalFS::new(&data_path, true)));
|
mount_vfs(&mut context, Box::new(PhysicalFS::new(&data_path, true)));
|
||||||
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(&user_path, false)));
|
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(&user_path, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
{
|
{
|
||||||
if crate::framework::filesystem::open(&context, "/.drs_localstorage").is_ok() {
|
if crate::framework::filesystem::open(&context, "/.drs_localstorage").is_ok() {
|
||||||
let mut user_dir = resource_dir.clone();
|
let mut user_dir = resource_dir.clone();
|
||||||
user_dir.push("_drs_profile");
|
user_dir.push("_drs_profile");
|
||||||
|
|
||||||
let _ = std::fs::create_dir_all(&user_dir);
|
let _ = std::fs::create_dir_all(&user_dir);
|
||||||
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(&user_dir, false)));
|
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(&user_dir, false)));
|
||||||
} else {
|
} else {
|
||||||
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(project_dirs.data_local_dir(), false)));
|
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(project_dirs.data_local_dir(), false)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mount_vfs(&mut context, Box::new(BuiltinFS::new()));
|
mount_vfs(&mut context, Box::new(BuiltinFS::new()));
|
||||||
|
|
||||||
|
@ -318,9 +318,9 @@ pub fn init(options: LaunchOptions) -> GameResult {
|
||||||
let game = UnsafeCell::new(Game::new(&mut context)?);
|
let game = UnsafeCell::new(Game::new(&mut context)?);
|
||||||
let state_ref = unsafe { &mut *((&mut *game.get()).state.get()) };
|
let state_ref = unsafe { &mut *((&mut *game.get()).state.get()) };
|
||||||
#[cfg(feature = "scripting-lua")]
|
#[cfg(feature = "scripting-lua")]
|
||||||
{
|
{
|
||||||
state_ref.lua.update_refs(unsafe { (&*game.get()).state.get() }, &mut context as *mut Context);
|
state_ref.lua.update_refs(unsafe { (&*game.get()).state.get() }, &mut context as *mut Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
state_ref.next_scene = Some(Box::new(LoadingScene::new()));
|
state_ref.next_scene = Some(Box::new(LoadingScene::new()));
|
||||||
context.run(unsafe { &mut *game.get() })?;
|
context.run(unsafe { &mut *game.get() })?;
|
||||||
|
|
|
@ -327,12 +327,13 @@ impl SharedGameState {
|
||||||
None => "data",
|
None => "data",
|
||||||
};
|
};
|
||||||
|
|
||||||
let vanilla_extractor =
|
#[cfg(not(target_os = "horizon"))]
|
||||||
VanillaExtractor::from(ctx, vanilla_ext_exe.to_string(), vanilla_ext_outdir.to_string());
|
if let Some(vanilla_extractor) =
|
||||||
if vanilla_extractor.is_some() {
|
VanillaExtractor::from(ctx, vanilla_ext_exe.to_string(), vanilla_ext_outdir.to_string())
|
||||||
let result = vanilla_extractor.unwrap().extract_data();
|
{
|
||||||
if result.is_err() {
|
let result = vanilla_extractor.extract_data();
|
||||||
log::error!("Failed to extract vanilla data: {}", result.unwrap_err());
|
if let Err(e) = result {
|
||||||
|
log::error!("Failed to extract vanilla data: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//#![cfg_attr(target_os = "horizon", feature(restricted_std))]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate strum;
|
extern crate strum;
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::menu::MenuEntry;
|
||||||
use crate::menu::{Menu, MenuSelectionResult};
|
use crate::menu::{Menu, MenuSelectionResult};
|
||||||
use crate::scene::title_scene::TitleScene;
|
use crate::scene::title_scene::TitleScene;
|
||||||
use crate::sound::InterpolationMode;
|
use crate::sound::InterpolationMode;
|
||||||
|
use crate::util::browser;
|
||||||
|
|
||||||
use super::controls_menu::ControlsMenu;
|
use super::controls_menu::ControlsMenu;
|
||||||
|
|
||||||
|
@ -295,13 +296,18 @@ impl SettingsMenu {
|
||||||
|
|
||||||
self.graphics.push_entry(GraphicsMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
self.graphics.push_entry(GraphicsMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
||||||
|
|
||||||
|
self.main.push_entry(
|
||||||
|
MainMenuEntry::Graphics,
|
||||||
|
MenuEntry::Active(state.loc.t("menus.options_menu.graphics").to_owned()),
|
||||||
|
);
|
||||||
self.main
|
self.main
|
||||||
.push_entry(MainMenuEntry::Graphics, MenuEntry::Active(state.loc.t("menus.options_menu.graphics").to_owned()));
|
.push_entry(MainMenuEntry::Sound, MenuEntry::Active(state.loc.t("menus.options_menu.sound").to_owned()));
|
||||||
self.main.push_entry(MainMenuEntry::Sound, MenuEntry::Active(state.loc.t("menus.options_menu.sound").to_owned()));
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
self.main
|
self.main.push_entry(
|
||||||
.push_entry(MainMenuEntry::Controls, MenuEntry::Active(state.loc.t("menus.options_menu.controls").to_owned()));
|
MainMenuEntry::Controls,
|
||||||
|
MenuEntry::Active(state.loc.t("menus.options_menu.controls").to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
self.language.push_entry(
|
self.language.push_entry(
|
||||||
LanguageMenuEntry::Title,
|
LanguageMenuEntry::Title,
|
||||||
|
@ -322,10 +328,13 @@ impl SettingsMenu {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.main
|
self.main.push_entry(
|
||||||
.push_entry(MainMenuEntry::Behavior, MenuEntry::Active(state.loc.t("menus.options_menu.behavior").to_owned()));
|
MainMenuEntry::Behavior,
|
||||||
|
MenuEntry::Active(state.loc.t("menus.options_menu.behavior").to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
self.main.push_entry(MainMenuEntry::Links, MenuEntry::Active(state.loc.t("menus.options_menu.links").to_owned()));
|
self.main
|
||||||
|
.push_entry(MainMenuEntry::Links, MenuEntry::Active(state.loc.t("menus.options_menu.links").to_owned()));
|
||||||
|
|
||||||
self.links
|
self.links
|
||||||
.push_entry(LinksMenuEntry::Title, MenuEntry::Disabled(state.loc.t("menus.options_menu.links").to_owned()));
|
.push_entry(LinksMenuEntry::Title, MenuEntry::Disabled(state.loc.t("menus.options_menu.links").to_owned()));
|
||||||
|
@ -345,11 +354,17 @@ impl SettingsMenu {
|
||||||
|
|
||||||
self.sound.push_entry(
|
self.sound.push_entry(
|
||||||
SoundMenuEntry::MusicVolume,
|
SoundMenuEntry::MusicVolume,
|
||||||
MenuEntry::OptionsBar(state.loc.t("menus.options_menu.sound_menu.music_volume").to_owned(), state.settings.bgm_volume),
|
MenuEntry::OptionsBar(
|
||||||
|
state.loc.t("menus.options_menu.sound_menu.music_volume").to_owned(),
|
||||||
|
state.settings.bgm_volume,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
self.sound.push_entry(
|
self.sound.push_entry(
|
||||||
SoundMenuEntry::EffectsVolume,
|
SoundMenuEntry::EffectsVolume,
|
||||||
MenuEntry::OptionsBar(state.loc.t("menus.options_menu.sound_menu.effects_volume").to_owned(), state.settings.sfx_volume),
|
MenuEntry::OptionsBar(
|
||||||
|
state.loc.t("menus.options_menu.sound_menu.effects_volume").to_owned(),
|
||||||
|
state.settings.sfx_volume,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.sound.push_entry(
|
self.sound.push_entry(
|
||||||
|
@ -845,7 +860,7 @@ impl SettingsMenu {
|
||||||
},
|
},
|
||||||
CurrentMenu::LinksMenu => match self.links.tick(controller, state) {
|
CurrentMenu::LinksMenu => match self.links.tick(controller, state) {
|
||||||
MenuSelectionResult::Selected(LinksMenuEntry::Link(url), _) => {
|
MenuSelectionResult::Selected(LinksMenuEntry::Link(url), _) => {
|
||||||
if let Err(e) = webbrowser::open(&url) {
|
if let Err(e) = browser::open(&url) {
|
||||||
log::warn!("Error opening web browser: {}", e);
|
log::warn!("Error opening web browser: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ impl Scene for NoDataScene {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
use crate::common::Rect;
|
use crate::common::Rect;
|
||||||
|
use crate::util::browser;
|
||||||
|
|
||||||
if !self.flag {
|
if !self.flag {
|
||||||
self.flag = true;
|
self.flag = true;
|
||||||
|
@ -39,7 +40,7 @@ impl Scene for NoDataScene {
|
||||||
|
|
||||||
let screen = Rect::new(0, 0, state.canvas_size.0 as isize, state.canvas_size.1 as isize);
|
let screen = Rect::new(0, 0, state.canvas_size.0 as isize, state.canvas_size.1 as isize);
|
||||||
if state.touch_controls.consume_click_in(screen) {
|
if state.touch_controls.consume_click_in(screen) {
|
||||||
if let Err(err) = webbrowser::open(REL_URL) {
|
if let Err(err) = browser::open(REL_URL) {
|
||||||
self.err = err.to_string();
|
self.err = err.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#[cfg(feature = "webbrowser")]
|
||||||
|
pub use webbrowser::open;
|
||||||
|
|
||||||
|
// stub for platforms webbrowser doesn't support, such as Horizon OS
|
||||||
|
#[cfg(not(feature = "webbrowser"))]
|
||||||
|
pub fn open(_url: &str) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod bitvec;
|
pub mod bitvec;
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
|
pub mod browser;
|
||||||
|
|
Loading…
Reference in New Issue