O5P6HCPWGMGJBFJEMC3SYQJ5OEW2AQV4KEJCMRVTTS3K6M45Z3BAC
RSKZITUCAFUWNT5UT7752VOM7BK6E2O7YHSUCKBXMYMT6PUNCP6QC
FPNW5ZHTGO2UDPGVOKZYX2BYZRMKAB3NEAFVSIXRVYNSWCUPBWFQC
RWAEE6C6YZEFU226ACROCZQYSPVW4QQLKDBY4S5BGTDGHQD5LJSAC
TKNFBCKZDYYH4FXMUCMLMY5HZIVVWSH2LXGHPG5WVTYO4AJJ6REQC
34CROJEM52NB7TGBCGGMIYAQ2AZUI44FWO25MGYYUSCMHLCLJNAQC
DKGUNP6LG3DJ35VMHU42K3VJO5JJ5UVYI4PLM72HO5ZNAQ4P366AC
GROTV3H2V6BHU5CA7WSLVYDCWAR7GHUP5JV2QOGPLJ6N3553T4MAC
PAOLWMH7TLJLNAWBJBWP7KB7YGDFUPASMTFU33KZ3QW5JXJMPXCAC
Y4JIGMJIDT3RS23FHKHYW2YMSW5OSVXCRHFXRQ33RHQFQIRJAKHQC
KID2E3YKLHUFPHWYYGRQZTX73THWMAXQWPT5XZEJJO46BCQD27HQC
L6RIUKGLJZLAOKFGUDTZKBPP4HUBPEZAKHJEQHO34WFF62AB2ZIQC
GHIHJCWBCGFZI4AG66L7WG4WKJ467DXFBRBNLT4ZULSN7ZVBJI6AC
X5EMQBC4BFNJOOHS2QMF4UB4QH6JKSALK6RXLK6B7SP6MNYSAP6QC
WQIQA2TNWNSNGKQC22XPTECAZEWG6PG5QWQECUVXDUQRSCV6RUZQC
KMU4E426CB2NDRJEK7B4GSL22P62CJPPZRK45X3JV5WP5NIBIGRQC
7CBRRVV3GLVLBHNPQNRHSA2ZCLHIMCHFEMWMZNOICY2OZLB7DGPAC
Q6Z5IQJ3SUI7BUJCKT377EPIRO7UVZFI7UB74ZEEGTCTUKC7WGKQC
4RVKY4GPSLJ354NLVZDZFB7UFRMOTIC22NQIHYPEU6FKYLKBN75QC
SHETNOQ72CK37ZFZBK7I4DEFNJDCNBKBR4ROF6T6MCN3IFOXHBHAC
HTDZ53HWD4X3DSFZX7MMC7DPFJNHQPGBVLJD2S325SQRRVIQ3CLAC
DOR7S6M2PZ5FQ7TFGWIK7FUFUZENXKU4G42I5HQITODPBBEJB4YQC
MMCK5BQQST5NDI5R3VLY7ICBGNARTYG2FKKRPRIXQHXXGH2QO3PQC
ER6ZNH7MRH3CT66LQR72NYUXOTC2NDKHHDV72VBUHSJGE2VNUXCAC
NS7EOR3SRISITX6SBHBOJIYTINDN2ZBL2QY64H6FNJJ3I2I3PYGQC
6YVIIRYC6FQP7ET7AMJHG4XCIDI4KIJMOKUDAUMVBLYFEULRDQEAC
mod game;
mod ldtk;
mod screen;
mod text;
use std::time::{Duration, Instant};
use game::Game;
use winit::{
dpi,
event::*,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
const WINDOW_WIDTH: u32 = 900;
const WINDOW_HEIGHT: u32 = 600;
const LOGIC_DURATION: Duration = Duration::from_millis(16);
let event_loop = EventLoop::new()?;
let window = WindowBuilder::new()
.with_inner_size(dpi::LogicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT))
.build(&event_loop)?;
event_loop.set_control_flow(ControlFlow::Poll);
let main_window_id = window.id();
let mut game = match Game::new(window) {
Ok(game) => game,
Err(e) => {
log::error!("{}", e);
return Err(e);
}
};
let mut avg_fps = 0.0;
let mut tick = Instant::now();
let mut accum = Duration::ZERO;
event_loop.run(move |event, elwt| match event {
Event::WindowEvent {
window_id,
ref event,
} if window_id == main_window_id => {
if !game.input(event) {
match event {
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::RedrawRequested => {
// The profiler should get a new frame
puffin::GlobalProfiler::lock().new_frame();
// Redraw the application.
//
// It's preferable for applications that do not render continuously to render in
// this event rather than in AboutToWait, since rendering in here allows
// the program to gracefully handle redraws requested by the OS.
game.set_window_title(format!("Cat Waiter | FPS {avg_fps:03.2}"));
match game.render() {
Ok(()) => {}
// Reconfigure surface if lost
Err(screen::RenderError::Wgpu(wgpu::SurfaceError::Lost)) => {
game.screen().reconfigure()
}
// System OOM, quit
Err(screen::RenderError::Wgpu(wgpu::SurfaceError::OutOfMemory)) => {
elwt.exit()
}
// All other errors should resolve themselves next render
Err(e) => log::info!("Encountered render error: {e:?}"),
}
}
WindowEvent::Resized(phys_size) => {
game.screen_mut().resize(*phys_size);
}
_ => {}
}
}
}
Event::AboutToWait => {
// App update code
let elapsed = tick.elapsed();
tick = Instant::now();
accum += elapsed;
let mut frames = 0.0;
while accum >= LOGIC_DURATION {
accum -= LOGIC_DURATION;
game.update(LOGIC_DURATION);
frames += 1.0;
}
if frames > 0.0 {
avg_fps = (avg_fps + (frames / LOGIC_DURATION.as_secs_f64())) / 2.0;
}
// Sync the physics system with the real world *now* (using the remainder of the accumuator as a delta)
game.physics_sync(accum.as_secs_f32() / LOGIC_DURATION.as_secs_f32());
// Queue a RedrawRequested event.
//
// You only need to call this if you've determined that you need to redraw in
// applications which do not always need to. Applications that redraw continuously
// can render here instead.
game.screen().window().request_redraw();
}
_ => {}
})?;
Ok(())
pollster::block_on(meowframe::run())
mod game;
mod ldtk;
mod screen;
mod text;
use std::time::Duration;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
use game::Game;
use winit::{
dpi,
event::*,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
const WINDOW_WIDTH: u32 = 900;
const WINDOW_HEIGHT: u32 = 600;
const LOGIC_DURATION: Duration = Duration::from_millis(16);
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
#[cfg(feature = "web")]
pub async fn main_web() {
// TODO move to tracing eventually?
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Warn).expect("Couldn't initialize logger");
run().await.unwrap()
}
pub async fn run() -> color_eyre::Result<()> {
#[cfg(not(any(feature = "web", feature = "desktop")))]
compile_error!("Must compile with platform feature");
let event_loop = EventLoop::new()?;
let mut builder =
WindowBuilder::new().with_inner_size(dpi::LogicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT));
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowBuilderExtWebSys;
builder = builder.with_append(true);
}
let window = builder.build(&event_loop)?;
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;
if web_sys::window()
.and_then(|win| win.document())
.and_then(|doc| {
if let Some(canvas) = window.canvas() {
let dst = doc.get_element_by_id("game")?;
dst.append_child(&canvas).ok()?;
}
Some(())
})
.is_none()
{
log::warn!("Failed to find an element with 'game' id, leaving window appended");
}
}
event_loop.set_control_flow(ControlFlow::Poll);
let main_window_id = window.id();
// Pick the assets source
#[cfg(not(target_arch = "wasm32"))]
let source = assets_manager::source::FileSystem::new("assets")?;
#[cfg(target_arch = "wasm32")]
let source = assets_manager::source::Embedded::from(assets_manager::source::embed!("assets"));
let mut game = match Game::new(window, source).await {
Ok(game) => game,
Err(e) => {
log::error!("{}", e);
return Err(e);
}
};
let mut avg_fps = 0.0;
let mut tick = instant::Instant::now();
let mut accum = Duration::ZERO;
event_loop.run(move |event, elwt| match event {
Event::WindowEvent {
window_id,
ref event,
} if window_id == main_window_id => {
if !game.input(event) {
match event {
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::RedrawRequested => {
// The profiler should get a new frame
puffin::GlobalProfiler::lock().new_frame();
// Redraw the application.
//
// It's preferable for applications that do not render continuously to render in
// this event rather than in AboutToWait, since rendering in here allows
// the program to gracefully handle redraws requested by the OS.
game.set_window_title(format!("Cat Waiter | FPS {avg_fps:03.2}"));
match game.render() {
Ok(()) => {}
// Reconfigure surface if lost
Err(screen::RenderError::Wgpu(wgpu::SurfaceError::Lost)) => {
game.screen().reconfigure()
}
// System OOM, quit
Err(screen::RenderError::Wgpu(wgpu::SurfaceError::OutOfMemory)) => {
elwt.exit()
}
// All other errors should resolve themselves next render
Err(e) => log::info!("Encountered render error: {e:?}"),
}
}
WindowEvent::Resized(phys_size) => {
game.screen_mut().resize(*phys_size);
}
_ => {}
}
}
}
Event::AboutToWait => {
// App update code
let elapsed = tick.elapsed();
tick = instant::Instant::now();
accum += elapsed;
let mut frames = 0.0;
while accum >= LOGIC_DURATION {
accum -= LOGIC_DURATION;
game.update(LOGIC_DURATION);
frames += 1.0;
}
if frames > 0.0 {
avg_fps = (avg_fps + (frames / LOGIC_DURATION.as_secs_f64())) / 2.0;
}
// Sync the physics system with the real world *now* (using the remainder of the accumuator as a delta)
game.physics_sync(accum.as_secs_f32() / LOGIC_DURATION.as_secs_f32());
// Queue a RedrawRequested event.
//
// You only need to call this if you've determined that you need to redraw in
// applications which do not always need to. Applications that redraw continuously
// can render here instead.
game.screen().window().request_redraw();
}
_ => {}
})?;
Ok(())
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link data-trunk rel="rust" data-cargo-features="web" data-target-name="meowframe" />
<title>Cat Waiter</title>
</head>
<body>
<div id="game"></div>
</body>
</html>
[jobs.run]
command = [
"cargo", "run",
"--color", "always",
# put launch parameters for your program behind a `--` separator
]
need_stdout = true
allow_warnings = true
background = true
# [jobs.run]
# command = [
# "cargo", "run",
# "--color", "always",
# # put launch parameters for your program behind a `--` separator
# ]
# need_stdout = true
# allow_warnings = true
# background = true
a = "job:check"
alt-a = "job:check-web"
alt-c = "job:clippy-web"
wgpu = { version = "0.19", default-features = false }
instant = "0.1.12"
[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.6"
console_log = "1.0"
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4.30"
# lock this version of web-sys cuz that's what wgpu compiles with
web-sys = { version = "=0.3.67", features = [
"Document",
"Window",
"Element",
]}
web = ["poll-promise/web", "dep:getrandom", "getrandom?/js",
"tracing-subscriber/time", "wgpu/webgpu", "instant/wasm-bindgen"]
desktop = ["egui-winit/clipboard", "egui-winit/links", "egui-winit/wayland",
"egui-winit/x11", "wgpu/dx12", "wgpu/metal", "wgpu/webgpu", "wgpu/wgsl",
"tracing-subscriber/env-filter"]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if",
"wasm-bindgen",
]
[[package]]
name = "console_log"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f"
dependencies = [
"log",
"web-sys",
]
[[package]]
]
[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a62d0338e4056db6a73221c2fb2e30619452f6ea9651bac4110f51b0f7a7581"
source = "git+https://github.com/Jengamon/glyphon.git#af20ebc69ba7b1415d32c47199064a8f937539c1"
name = "leptos_reactive"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30c5bc7f3496d6ba399578171cf133c50d2172f9791fe292db4da2fd0d8cec4"
dependencies = [
"base64",
"cfg-if",
"futures",
"indexmap",
"js-sys",
"paste",
"pin-project",
"rustc-hash",
"self_cell",
"serde",
"serde-wasm-bindgen",
"serde_json",
"slotmap",
"thiserror",
"tracing",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "pin-project"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]]
]
[[package]]
name = "poll-promise"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6a58fecbf9da8965bcdb20ce4fd29788d1acee68ddbb64f0ba1b81bccdb7df"
dependencies = [
"document-features",
"static_assertions",
"wasm-bindgen",
"wasm-bindgen-futures",
"regex-automata",
"regex-syntax",
"regex-automata 0.4.5",
"regex-syntax 0.8.2",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
]
[[package]]
name = "time"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
[[package]]
name = "tokio"
version = "1.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
dependencies = [
"backtrace",
"pin-project-lite",
"tokio-macros",
]
[[package]]
name = "tokio-macros"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
]
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-logfmt"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84bab42e40ace4e4ff19c92023ee1dbc1510db60976828fbbdc6994852c7d065"
dist
[language-server.rust-analyzer.config]
cargo = { features = ["desktop"] }
dist
[build]
rustflags = ["--cfg=web_sys_unstable_apis"]
rustdocflags = ["--cfg=web_sys_unstable_apis"]