1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Player and editor input types.

use std::array;

use bones_framework::input::PlayerControls;

use crate::{prelude::*, MAX_PLAYERS};

pub fn install(session: &mut Session) {
    session.world.init_resource::<MatchInputs>();
}

/// The inputs for each player in this simulation frame.
#[derive(Clone, Debug, HasSchema)]
pub struct MatchInputs {
    pub players: [PlayerInput; MAX_PLAYERS as usize],
}

impl Default for MatchInputs {
    fn default() -> Self {
        Self {
            players: array::from_fn(|_| default()),
        }
    }
}

impl PlayerControls<'_, PlayerControl> for MatchInputs {
    type ControlSource = ControlSource;
    type ControlMapping = PlayerControlMapping;
    type InputCollector = PlayerInputCollector;

    fn update_controls(&mut self, collector: &mut PlayerInputCollector) {
        (0..MAX_PLAYERS as usize).for_each(|i| {
            let player_input = &mut self.players[i];
            if let Some(source) = &player_input.control_source {
                player_input.control = *collector.get_control(i, *source);
            }
        });
    }

    fn get_control_source(&self, player_idx: usize) -> Option<ControlSource> {
        self.players.get(player_idx).unwrap().control_source
    }

    fn get_control(&self, player_idx: usize) -> &PlayerControl {
        &self.players.get(player_idx).unwrap().control
    }

    fn get_control_mut(&mut self, player_idx: usize) -> &mut PlayerControl {
        &mut self.players.get_mut(player_idx).unwrap().control
    }
}

/// Player input, not just controls, but also other status that comes from the player, such as the
/// selected player and whether the player is actually active.
#[derive(Default, Clone, Debug, HasSchema)]
pub struct PlayerInput {
    /// Whether or not the player is present.
    pub active: bool,
    /// The selected player skin.
    pub selected_player: Handle<PlayerMeta>,
    /// The selected player hat.
    pub selected_hat: Option<Handle<HatMeta>>,
    /// The player control input
    pub control: PlayerControl,
    /// The editor inputs the player is making, if any.
    pub editor_input: Option<EditorInput>,
    /// If this is [`None`] it means the player is an AI, or remote player in networked game.
    pub control_source: Option<ControlSource>,

    /// Whether or not this is an AI player.
    pub is_ai: bool,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocatedTileLayer {
    pub layer_index: u32,
    pub located_tiles: Vec<(UVec2, u32, TileCollisionKind)>,
}

#[derive(Clone, HasSchema, Default, Debug)]
pub struct ElementLayer {
    pub layer_index: u32,
    pub located_elements: Vec<(Vec2, Handle<ElementMeta>)>,
}

/// The editor inputs that a player may make.
#[derive(Clone, Debug)]
pub enum EditorInput {
    /// Spawn an element onto the map.
    SpawnElement {
        /// The handle to the element that is being spawned.
        handle: Handle<ElementMeta>,
        /// The translation to spawn the element with.
        translation: Vec2,
        /// The map layer index to spawn the element on.
        layer: u8,
    },
    MoveEntity {
        /// The entity to move.
        entity: Entity,
        /// The amount to move the entity.
        pos: Vec2,
    },
    DeleteEntity {
        /// The entity to delete.
        entity: Entity,
    },
    /// Create a new layer
    CreateLayer {
        /// The name of the layer.
        id: String,
    },
    /// Rename a map layer.
    RenameLayer {
        /// The index of the layer to rename.
        layer: u8,
        /// The new name of the layer.
        name: String,
    },
    DeleteLayer {
        layer: u8,
    },
    /// Move a layer up or down.
    MoveLayer {
        /// The layer to move
        layer: u8,
        /// Whether or not to move the layer down. If false, move the layer up.
        down: bool,
    },
    /// Update the tilemap of a layer.
    SetTilemap {
        /// The layer index of the layer to update.
        layer: u8,
        /// The handle to the tilemap to use or [`None`] to clear the tilemap.
        handle: Option<Handle<Atlas>>,
    },
    SetTile {
        /// The layer index of the layer to update
        layer: u8,
        /// The position of the tile to set
        pos: UVec2,
        /// The index in the tilemap to set the tile, or [`None`] to delete the tile.
        tilemap_tile_idx: Option<u32>,
        /// The tile collision kind
        collision: TileCollisionKind,
    },
    RenameMap {
        name: String,
    },
    RandomizeTiles {
        tile_layers: Vec<LocatedTileLayer>,
        element_layers: Vec<ElementLayer>,
        tile_size: Vec2,
    },
}