mirror of
https://github.com/Xevion/Pac-Man.git
synced 2026-01-30 20:25:00 -06:00
fix(lint): resolve clippy warnings and add cross-platform lint recipe
- Add `just lint` recipe for desktop + wasm clippy checks - Fix clippy warnings: redundant field names, formatting, dead code - Gate Emscripten-specific audio methods behind target_os cfg
This commit is contained in:
@@ -40,6 +40,14 @@ web *args:
|
||||
bun run --cwd web build
|
||||
caddy file-server --root web/dist/client --listen :8547
|
||||
|
||||
# Run strict multi-platform lints (desktop + wasm)
|
||||
lint:
|
||||
@echo "Running clippy for desktop target..."
|
||||
@cargo clippy --all-targets --all-features --quiet -- -D warnings
|
||||
@echo "Running clippy for wasm target..."
|
||||
@cargo clippy -p pacman --target wasm32-unknown-emscripten --all-features --quiet -- -D warnings
|
||||
@echo "All lints passed!"
|
||||
|
||||
# Fix linting errors & formatting
|
||||
fix:
|
||||
cargo fix --workspace --lib --allow-dirty
|
||||
|
||||
@@ -75,7 +75,7 @@ impl AppState {
|
||||
sessions: Arc::new(DashMap::new()),
|
||||
jwt_encoding_key: Arc::new(EncodingKey::from_secret(jwt_secret.as_bytes())),
|
||||
jwt_decoding_key: Arc::new(DecodingKey::from_secret(jwt_secret.as_bytes())),
|
||||
db: db,
|
||||
db,
|
||||
health: Arc::new(RwLock::new(Health::default())),
|
||||
image_storage,
|
||||
healthchecker_task: Arc::new(RwLock::new(None)),
|
||||
|
||||
+15
-3
@@ -56,11 +56,18 @@ pub struct Audio {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum AudioState {
|
||||
Enabled { volume: u8 },
|
||||
Muted { previous_volume: u8 },
|
||||
Enabled {
|
||||
volume: u8,
|
||||
},
|
||||
Muted {
|
||||
previous_volume: u8,
|
||||
},
|
||||
/// Audio is suspended until user interaction unlocks it (browser autoplay policy).
|
||||
/// On Emscripten, audio starts in this state and transitions to Enabled when unlock() is called.
|
||||
Suspended { volume: u8 },
|
||||
#[cfg(target_os = "emscripten")]
|
||||
Suspended {
|
||||
volume: u8,
|
||||
},
|
||||
Disabled,
|
||||
}
|
||||
|
||||
@@ -264,6 +271,7 @@ impl Audio {
|
||||
///
|
||||
/// Transitions from Suspended to Enabled state, allowing audio to play.
|
||||
/// Called when the user clicks or presses a key to satisfy browser autoplay policy.
|
||||
#[cfg(target_os = "emscripten")]
|
||||
pub fn unlock(&mut self) {
|
||||
if let AudioState::Suspended { volume } = self.state {
|
||||
tracing::info!("Audio unlocked after user interaction");
|
||||
@@ -275,11 +283,15 @@ impl Audio {
|
||||
///
|
||||
/// Returns `true` if audio is in the Enabled state, `false` if suspended,
|
||||
/// muted, or disabled.
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[allow(dead_code)]
|
||||
pub fn is_ready(&self) -> bool {
|
||||
matches!(self.state, AudioState::Enabled { .. })
|
||||
}
|
||||
|
||||
/// Returns whether audio is suspended waiting for user interaction.
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[allow(dead_code)]
|
||||
pub fn is_suspended(&self) -> bool {
|
||||
matches!(self.state, AudioState::Suspended { .. })
|
||||
}
|
||||
|
||||
+5
-2
@@ -22,9 +22,12 @@ use crate::systems::{
|
||||
EntityType, Frozen, FruitSprites, GameStage, Ghost, GhostAnimation, GhostAnimations, GhostBundle, GhostCollider, GhostState,
|
||||
GlobalState, ItemBundle, ItemCollider, LastAnimationState, LinearAnimation, MapTextureResource, MovementModifiers, NodeId,
|
||||
PacmanCollider, PlayerAnimation, PlayerBundle, PlayerControlled, PlayerDeathAnimation, PlayerLives, Position, RenderDirty,
|
||||
Renderable, ScoreResource, StartupSequence, SystemId, SystemTimings, Timing, TouchState, Velocity, Visibility,
|
||||
Renderable, ScoreResource, SystemId, SystemTimings, Timing, TouchState, Velocity, Visibility,
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
use crate::systems::StartupSequence;
|
||||
|
||||
use crate::texture::animated::{DirectionalTiles, TileSequence};
|
||||
use crate::texture::sprite::AtlasTile;
|
||||
use crate::texture::sprites::{FrightenedColor, GameSprite, GhostSprite, MazeSprite, PacmanSprite};
|
||||
@@ -787,7 +790,7 @@ impl Game {
|
||||
// Use dt to determine expected frame time, with 80% as threshold to account for normal variance
|
||||
// Desktop uses LOOP_TIME (~16.67ms), WebAssembly adapts to requestAnimationFrame timing
|
||||
let frame_budget_ms = (dt * 1000.0 * 1.2) as u128;
|
||||
|
||||
|
||||
// Log performance warnings for slow frames
|
||||
if total_duration.as_millis() > frame_budget_ms {
|
||||
let slowest_systems = timings.get_slowest_systems();
|
||||
|
||||
@@ -23,12 +23,7 @@ extern "C" {
|
||||
/// - `arg`: user data pointer passed to callback
|
||||
/// - `fps`: target FPS (0 = use requestAnimationFrame)
|
||||
/// - `simulate_infinite_loop`: if 1, never returns (standard for games)
|
||||
pub fn emscripten_set_main_loop_arg(
|
||||
func: EmMainLoopCallback,
|
||||
arg: *mut c_void,
|
||||
fps: c_int,
|
||||
simulate_infinite_loop: c_int,
|
||||
);
|
||||
pub fn emscripten_set_main_loop_arg(func: EmMainLoopCallback, arg: *mut c_void, fps: c_int, simulate_infinite_loop: c_int);
|
||||
|
||||
/// Execute JavaScript code from Rust
|
||||
fn emscripten_run_script(script: *const i8);
|
||||
|
||||
@@ -89,7 +89,7 @@ pub fn hud_render_system(
|
||||
if pause_state.active() {
|
||||
// Enable blending for transparency
|
||||
canvas.set_blend_mode(sdl2::render::BlendMode::Blend);
|
||||
|
||||
|
||||
// Draw semi-transparent black overlay
|
||||
canvas.set_draw_color(Color::RGBA(0, 0, 0, 160));
|
||||
let _ = canvas.fill_rect(Rect::new(0, 0, constants::CANVAS_SIZE.x, constants::CANVAS_SIZE.y));
|
||||
@@ -101,7 +101,7 @@ pub fn hud_render_system(
|
||||
let paused_height = paused_renderer.text_height();
|
||||
let paused_position = glam::UVec2::new(
|
||||
(constants::CANVAS_SIZE.x - paused_width) / 2,
|
||||
(constants::CANVAS_SIZE.y - paused_height) / 2
|
||||
(constants::CANVAS_SIZE.y - paused_height) / 2,
|
||||
);
|
||||
if let Err(e) = paused_renderer.render_with_color(canvas, &mut atlas, paused_text, paused_position, Color::YELLOW) {
|
||||
errors.write(TextureError::RenderFailed(format!("Failed to render PAUSED text: {}", e)).into());
|
||||
|
||||
@@ -43,6 +43,7 @@ pub struct IntroPlayed(pub bool);
|
||||
pub enum GameStage {
|
||||
/// Waiting for user interaction before starting (Emscripten only).
|
||||
/// Game is rendered but audio/gameplay are paused until the user clicks or presses a key.
|
||||
#[cfg(target_os = "emscripten")]
|
||||
WaitingForInteraction,
|
||||
Starting(StartupSequence),
|
||||
/// The main gameplay loop is active.
|
||||
@@ -186,7 +187,15 @@ impl TooSimilar for GameStage {
|
||||
fn too_similar(&self, other: &Self) -> bool {
|
||||
discriminant(self) == discriminant(other) && {
|
||||
// These states are very simple, so they're 'too similar' automatically
|
||||
if matches!(self, GameStage::Playing | GameStage::GameOver | GameStage::WaitingForInteraction) {
|
||||
#[cfg(target_os = "emscripten")]
|
||||
if matches!(
|
||||
self,
|
||||
GameStage::Playing | GameStage::GameOver | GameStage::WaitingForInteraction
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
if matches!(self, GameStage::Playing | GameStage::GameOver) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -210,7 +219,10 @@ impl TooSimilar for GameStage {
|
||||
},
|
||||
) => ghost_entity == other_ghost_entity && ghost_type == other_ghost_type && node == other_node,
|
||||
// Already handled, but kept to properly exhaust the match
|
||||
#[cfg(target_os = "emscripten")]
|
||||
(GameStage::Playing, _) | (GameStage::GameOver, _) | (GameStage::WaitingForInteraction, _) => unreachable!(),
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
(GameStage::Playing, _) | (GameStage::GameOver, _) => unreachable!(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -315,6 +327,7 @@ pub fn stage_system(
|
||||
}
|
||||
|
||||
let new_state: GameStage = new_state_opt.unwrap_or_else(|| match *game_state {
|
||||
#[cfg(target_os = "emscripten")]
|
||||
GameStage::WaitingForInteraction => {
|
||||
// Stay in this state until JS calls start_game()
|
||||
*game_state
|
||||
|
||||
Reference in New Issue
Block a user