Add gamepad support to the desktop build
Co-Authored-By: deepseek-v4.1-flash (opencode-go) via CodeCraft
This commit is contained in:
1 parent
8d51d6ec6a
commit
e44aab6f5c
7 files changed
+260
-31
No files matched your search
Generated
+116
@@ -93,6 +93,12 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg_aliases"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -194,6 +200,7 @@ name = "dungeoncraft"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cpal",
|
"cpal",
|
||||||
|
"gilrs",
|
||||||
"macroquad",
|
"macroquad",
|
||||||
"rfd",
|
"rfd",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -226,6 +233,12 @@ dependencies = [
|
|||||||
"zlib-rs",
|
"zlib-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foldhash"
|
name = "foldhash"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -266,6 +279,40 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gilrs"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "902fb00d3f6398e635be22e5c837b303c501835cca7ac11a47bba138f7aafdd8"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"gilrs-core",
|
||||||
|
"log",
|
||||||
|
"uuid",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gilrs-core"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc7f0ce6237abcc0523f2a5502b1e3fe5802daaae47ac14e166fe49551301ea9"
|
||||||
|
dependencies = [
|
||||||
|
"inotify",
|
||||||
|
"js-sys",
|
||||||
|
"libc",
|
||||||
|
"libudev-sys",
|
||||||
|
"log",
|
||||||
|
"nix",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
"objc2-io-kit",
|
||||||
|
"uuid",
|
||||||
|
"vec_map",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glam"
|
name = "glam"
|
||||||
version = "0.27.0"
|
version = "0.27.0"
|
||||||
@@ -312,6 +359,26 @@ dependencies = [
|
|||||||
"hashbrown 0.17.1",
|
"hashbrown 0.17.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify"
|
||||||
|
version = "0.11.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cc00ea907cab49550b7da656f80ebb97be1b997d931fbcd28d39734e17ce592"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"inotify-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify-sys"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@@ -399,6 +466,16 @@ version = "0.2.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libudev-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.35"
|
version = "0.4.35"
|
||||||
@@ -513,6 +590,18 @@ dependencies = [
|
|||||||
"jni-sys 0.3.1",
|
"jni-sys 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.31.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"cfg-if",
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -666,6 +755,17 @@ dependencies = [
|
|||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-io-kit"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"libc",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
@@ -983,6 +1083,22 @@ version = "1.0.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.29.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bed99139f7dac9b5cfe5f17be4d66dc7079a34dee1d74bcc77217119240e267c"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|||||||
+2
-1
@@ -26,7 +26,8 @@ inherits = "release"
|
|||||||
lto = "thin"
|
lto = "thin"
|
||||||
codegen-units = 16
|
codegen-units = 16
|
||||||
|
|
||||||
# desktop builds: system file dialog (xdg portal on Linux) and sound output
|
# desktop builds: system file dialog (xdg portal on Linux), sound output and gamepads
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
rfd = { version = "0.17", default-features = false, features = ["xdg-portal"] }
|
rfd = { version = "0.17", default-features = false, features = ["xdg-portal"] }
|
||||||
cpal = "0.18"
|
cpal = "0.18"
|
||||||
|
gilrs = "0.11"
|
||||||
+3
-2
@@ -46,8 +46,9 @@ cargo build --release
|
|||||||
./target/release/dungeoncraft
|
./target/release/dungeoncraft
|
||||||
```
|
```
|
||||||
|
|
||||||
On Linux the build needs the ALSA headers (`alsa-lib` / `libasound2-dev`); the sound goes through ALSA (PipeWire and
|
On Linux the build needs the ALSA headers (`alsa-lib` / `libasound2-dev`) and libudev for gamepads
|
||||||
PulseAudio take it). The settings, the autosave, the campaign progress and the profile are kept as files in the
|
(`libudev-dev`); the sound goes through ALSA (PipeWire and PulseAudio take it). Gamepads are read directly on the
|
||||||
|
desktop (gilrs, hot-plug included); the browser build uses the browser's Gamepad API. The settings, the autosave, the campaign progress and the profile are kept as files in the
|
||||||
data folder: `~/.local/share/dungeoncraft/` (Linux, or `$XDG_DATA_HOME/dungeoncraft`), `%APPDATA%\DungeonCraft`
|
data folder: `~/.local/share/dungeoncraft/` (Linux, or `$XDG_DATA_HOME/dungeoncraft`), `%APPDATA%\DungeonCraft`
|
||||||
(Windows), `~/Library/Application Support/DungeonCraft` (macOS); `DUNGEONCRAFT_DATA` chooses another one.
|
(Windows), `~/Library/Application Support/DungeonCraft` (macOS); `DUNGEONCRAFT_DATA` chooses another one.
|
||||||
*Save Game* and saved campaigns land in its `saves/` folder; *Load Game* opens the system file dialog there (on
|
*Save Game* and saved campaigns land in its `saves/` folder; *Load Game* opens the system file dialog there (on
|
||||||
|
|||||||
+134
-12
@@ -65,6 +65,32 @@ pub fn kind_for(setting: u8, detected: i32) -> Kind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Desktop: the pad's vendor id names the type (Microsoft, Sony, Nintendo)
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn kind_from_vendor(vendor: u16) -> i32 {
|
||||||
|
match vendor {
|
||||||
|
0x045e => 1,
|
||||||
|
0x054c => 2,
|
||||||
|
0x057e => 3,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desktop: a pad without a known vendor, its name usually says what it is
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn kind_from_name(name: &str) -> i32 {
|
||||||
|
let n = name.to_lowercase();
|
||||||
|
if n.contains("xbox") || n.contains("xinput") || n.contains("microsoft") {
|
||||||
|
1
|
||||||
|
} else if n.contains("nintendo") || n.contains("switch") || n.contains("joy-con") || n.contains("joycon") || n.contains("pro controller") {
|
||||||
|
3
|
||||||
|
} else if n.contains("playstation") || n.contains("dualshock") || n.contains("dualsense") || n.contains("sony") || n.contains("wireless controller") {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static KIND: Cell<Kind> = const { Cell::new(Kind::Xbox) };
|
static KIND: Cell<Kind> = const { Cell::new(Kind::Xbox) };
|
||||||
}
|
}
|
||||||
@@ -84,28 +110,113 @@ pub struct Pad {
|
|||||||
axes: [f32; 4],
|
axes: [f32; 4],
|
||||||
pointer: (f32, f32), // device pixels of the interface
|
pointer: (f32, f32), // device pixels of the interface
|
||||||
pointer_ready: bool,
|
pointer_ready: bool,
|
||||||
|
// desktop builds read the pads themselves (miniquad does not poll them); gilrs opens the
|
||||||
|
// system's input devices, None when that is impossible or there are none
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
gilrs: Option<gilrs::Gilrs>,
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
tried: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pad {
|
impl Pad {
|
||||||
pub fn new() -> Pad {
|
pub fn new() -> Pad {
|
||||||
Pad { connected: false, buttons: 0, prev: 0, axes: [0.0; 4], pointer: (0.0, 0.0), pointer_ready: false }
|
Pad {
|
||||||
|
connected: false,
|
||||||
|
buttons: 0,
|
||||||
|
prev: 0,
|
||||||
|
axes: [0.0; 4],
|
||||||
|
pointer: (0.0, 0.0),
|
||||||
|
pointer_ready: false,
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
gilrs: None,
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
tried: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the pad for this frame; kind_setting = Settings::gamepad.
|
// Read the pad for this frame; kind_setting = Settings::gamepad.
|
||||||
pub fn poll(&mut self, kind_setting: u8) {
|
pub fn poll(&mut self, kind_setting: u8) {
|
||||||
self.prev = if self.connected { self.buttons } else { 0 };
|
self.prev = if self.connected { self.buttons } else { 0 };
|
||||||
let slot = crate::platform::gamepad_slot();
|
#[cfg(target_arch = "wasm32")]
|
||||||
self.connected = slot >= 0;
|
{
|
||||||
let detected = if self.connected { crate::platform::gamepad_kind(slot) } else { 0 };
|
let slot = crate::platform::gamepad_slot();
|
||||||
KIND.with(|c| c.set(kind_for(kind_setting, detected)));
|
self.connected = slot >= 0;
|
||||||
if !self.connected {
|
let detected = if self.connected { crate::platform::gamepad_kind(slot) } else { 0 };
|
||||||
self.buttons = 0;
|
KIND.with(|c| c.set(kind_for(kind_setting, detected)));
|
||||||
self.axes = [0.0; 4];
|
if !self.connected {
|
||||||
return;
|
self.buttons = 0;
|
||||||
|
self.axes = [0.0; 4];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.buttons = crate::platform::gamepad_buttons(slot);
|
||||||
|
for (i, a) in self.axes.iter_mut().enumerate() {
|
||||||
|
*a = crate::platform::gamepad_axis(slot, i as i32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.buttons = crate::platform::gamepad_buttons(slot);
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
for (i, a) in self.axes.iter_mut().enumerate() {
|
self.poll_desktop(kind_setting);
|
||||||
*a = crate::platform::gamepad_axis(slot, i as i32);
|
}
|
||||||
|
|
||||||
|
// Desktop: gilrs reports the pad's buttons and sticks. Its Y axes point up when positive,
|
||||||
|
// the browser's Gamepad API points down, so they are flipped to the same meaning here.
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn poll_desktop(&mut self, kind_setting: u8) {
|
||||||
|
use gilrs::{Axis, Button as GBtn};
|
||||||
|
if self.gilrs.is_none() && !self.tried {
|
||||||
|
self.tried = true;
|
||||||
|
match gilrs::Gilrs::new() {
|
||||||
|
Ok(g) => self.gilrs = Some(g),
|
||||||
|
Err(e) => eprintln!("DungeonCraft: no gamepad support: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let state = match self.gilrs.as_mut() {
|
||||||
|
None => None,
|
||||||
|
Some(g) => {
|
||||||
|
// drain the queue, so hot-plugged pads show up and the state stays current
|
||||||
|
while g.next_event().is_some() {}
|
||||||
|
g.gamepads().next().map(|(_, p)| {
|
||||||
|
let mut m = 0u32;
|
||||||
|
for (gb, b) in [
|
||||||
|
(GBtn::South, Btn::South),
|
||||||
|
(GBtn::East, Btn::East),
|
||||||
|
(GBtn::West, Btn::West),
|
||||||
|
(GBtn::North, Btn::North),
|
||||||
|
(GBtn::LeftTrigger, Btn::Lb),
|
||||||
|
(GBtn::RightTrigger, Btn::Rb),
|
||||||
|
(GBtn::LeftTrigger2, Btn::Lt),
|
||||||
|
(GBtn::RightTrigger2, Btn::Rt),
|
||||||
|
(GBtn::Select, Btn::Select),
|
||||||
|
(GBtn::Start, Btn::Start),
|
||||||
|
(GBtn::LeftThumb, Btn::LStick),
|
||||||
|
(GBtn::RightThumb, Btn::RStick),
|
||||||
|
(GBtn::DPadUp, Btn::Up),
|
||||||
|
(GBtn::DPadDown, Btn::Down),
|
||||||
|
(GBtn::DPadLeft, Btn::Left),
|
||||||
|
(GBtn::DPadRight, Btn::Right),
|
||||||
|
] {
|
||||||
|
if p.is_pressed(gb) {
|
||||||
|
m |= b.bit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let axes = [p.value(Axis::LeftStickX), -p.value(Axis::LeftStickY), p.value(Axis::RightStickX), -p.value(Axis::RightStickY)];
|
||||||
|
let detected = p.vendor_id().map(kind_from_vendor).unwrap_or_else(|| kind_from_name(&p.name()));
|
||||||
|
(detected, m, axes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match state {
|
||||||
|
Some((detected, buttons, axes)) => {
|
||||||
|
self.connected = true;
|
||||||
|
self.buttons = buttons;
|
||||||
|
self.axes = axes;
|
||||||
|
KIND.with(|c| c.set(kind_for(kind_setting, detected)));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.connected = false;
|
||||||
|
self.buttons = 0;
|
||||||
|
self.axes = [0.0; 4];
|
||||||
|
KIND.with(|c| c.set(kind_for(kind_setting, 0)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +323,17 @@ mod tests {
|
|||||||
assert!(!p.pressed(Btn::South));
|
assert!(!p.pressed(Btn::South));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the desktop path opens the system's input devices; without a pad (or without access to
|
||||||
|
// them) it simply reports none, and it must never panic
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
#[test]
|
||||||
|
fn polling_the_desktop_pad_is_safe() {
|
||||||
|
let mut p = Pad::new();
|
||||||
|
p.poll(0);
|
||||||
|
p.poll(2);
|
||||||
|
assert_eq!(p.connected(), p.gilrs.as_ref().map_or(false, |g| g.gamepads().next().is_some()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn the_pointer_follows_the_mouse_and_the_stick() {
|
fn the_pointer_follows_the_mouse_and_the_stick() {
|
||||||
let mut p = Pad::new();
|
let mut p = Pad::new();
|
||||||
|
|||||||
+2
-14
@@ -388,20 +388,8 @@ mod imp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Gamepad API only exists in browsers. The desktop build has no gamepad input yet
|
// Gamepads are polled by pad.rs with gilrs; the browser's Gamepad API lives in the
|
||||||
// (miniquad does not poll gamepads; that would need a crate like gilrs).
|
// dc_gamepad_* imports of the JS plugin (see the wasm imp above).
|
||||||
pub fn gamepad_slot() -> i32 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
pub fn gamepad_buttons(_slot: i32) -> u32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
pub fn gamepad_axis(_slot: i32, _axis: i32) -> f32 {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
pub fn gamepad_kind(_slot: i32) -> i32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use imp::*;
|
pub use imp::*;
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
- linux: dist/DungeonCraft-<version>-x86_64.AppImage
|
- linux: dist/DungeonCraft-<version>-x86_64.AppImage
|
||||||
built with cargo-zigbuild against glibc 2.28, so it runs on distributions from about 2019 on;
|
built with cargo-zigbuild against glibc 2.28, so it runs on distributions from about 2019 on;
|
||||||
needs on the build machine: zig, cargo-zigbuild, the ALSA headers (alsa-lib / libasound2-dev);
|
needs on the build machine: zig, cargo-zigbuild, the ALSA headers (alsa-lib / libasound2-dev)
|
||||||
|
and libudev (libudev-dev, for gamepads);
|
||||||
appimagetool is downloaded once into ~/.cache/dungeoncraft/
|
appimagetool is downloaded once into ~/.cache/dungeoncraft/
|
||||||
- windows: dist/DungeonCraft-<version>-windows-x64.exe (one file, Windows 10 and newer)
|
- windows: dist/DungeonCraft-<version>-windows-x64.exe (one file, Windows 10 and newer)
|
||||||
cross-compiled with cargo-zigbuild for x86_64-pc-windows-gnu
|
cross-compiled with cargo-zigbuild for x86_64-pc-windows-gnu
|
||||||
|
|||||||
Reference in new issue
Block a user