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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
//! A prototype API for `quill`, Feather's plugin API.
//!
//! # Concepts
//! * Feather is based on [the ECS architecture], an alternative
//! to classic object-oriented game architecture which is generally
//! more flexible and slightly more performant.
//! * Feather plugins compile to WebAssembly and are run in a sandboxed
//! environment.
//!
//! # Getting started
//! Install `cargo-quill`, a command line tool to help build
//! and test Feather plugins:
//! ```bash
//! cargo install cargo-quill
//! ```
//!
//! To start on a new plugin, run `cargo quill init myplugin`.
//! `cargo-quill` creates a new directory called `myplugin` and
//! fills it with a starter template.
//!
//! Let's take a look at the directory structure:
//! ```
//! myplugin
//! ├── Cargo.toml
//! └── src
//!    └── main.rs
//! ```

use std::{marker::PhantomData, ops::Deref, ops::DerefMut};
use uuid::Uuid;

/// (Would be reexported from `feather-blocks` in the final product)
pub struct BlockId;

/// Result type returned by most functions.
pub type SysResult<T = ()> = anyhow::Result<T>;

/// A type that can be associated with an entity as a component.
///
/// Components are a critical part of the ECS architecture;
/// refer to [this guide] for mroe information.
///
/// This trait is automatically implemented for most types.
///
/// # Persistence
/// Custom components are removed from entities when your
/// plugin is unloaded. We will offer a component persistence
/// API in the future.
pub trait Component: Send + Sync + 'static {}
impl<T> Component for T where T: Send + Sync + 'static {}

/// Error returned when attempting to get a component from an entity.
#[derive(Debug, thiserror::Error)]
pub enum ComponentError {
    /// The entity no longer exists, e.g. because it was despawned
    /// or killed.
    #[error("entity has been despawned")]
    EntityDead,
    /// The entity does not have the component requested.
    #[error("entity does not have a component of type '{0}0")]
    MissingComponent(&'static str),
}

/// An RAII guard to a component reference.
pub struct ComponentRef<T> {
    _todo: PhantomData<T>,
    _not_send_sync: PhantomData<*mut ()>,
}

impl<T> Deref for ComponentRef<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        todo!()
    }
}

/// An RAII guard to a mutable reference to a component.
pub struct ComponentRefMut<T> {
    _todo: PhantomData<T>,
    _not_send_sync: PhantomData<*mut ()>,
}

impl<T> Deref for ComponentRefMut<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        todo!()
    }
}

impl<T> DerefMut for ComponentRefMut<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        todo!()
    }
}

/// A handle to an entity. Provides access to components.
///
/// This handle cannot be sent to another thread, as it requires
/// access to the main server state. To persist entity handles across
/// thread boundaries, you may use [`EntityId`] instead.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EntityRef {
    _not_send_sync: PhantomData<*mut ()>,
}

impl EntityRef {
    /// Gets a component of this entity.
    ///
    /// Returns an error if the entity does not have this component
    /// or if the entity no longer exists.
    pub fn get<T: Component>(self) -> Result<ComponentRef<T>, ComponentError> {
        todo!()
    }

    /// Gets a mutable reference to a component of this entity.
    ///
    /// Returns an error if the entity does not have this component
    /// or if the entity no longer exists.
    pub fn get_mut<T: Component>(self) -> Result<ComponentRefMut<T>, ComponentError> {
        todo!()
    }

    /// Adds a component to this entity.
    ///
    /// If the entity already has a component of type `T`,
    /// then the component is overwritten.
    pub fn add<T: Component>(self, _component: T) -> Result<(), EntityDead> {
        todo!()
    }

    /// Sends a message to this entity.
    ///
    /// Returns an error if this entity cannot receive a message.
    /// (Usually, only players and the console are capable of receiving messages.)
    pub fn send_message(self, _message: &str) -> Result<(), ComponentError> {
        todo!()
    }

    /// Returns the ID of this entity. This ID can be stored
    /// for later use, usually through [`State::entity`].
    pub fn id(self) -> EntityId {
        todo!()
    }

    /// Returns this entity's `Position` component.
    pub fn position(self) -> Result<Position, ComponentError> {
        todo!()
    }

    /// Returns this entity's `Name` component.
    pub fn name(self) -> Result<Name, ComponentError> {
        todo!()
    }

    /// Returns this entity's `Uuid` component.
    pub fn uuid(self) -> Result<Uuid, ComponentError> {
        todo!()
    }
}

/// An opaque, unique ID of an entity. Can be used with [`State::entity`] to get
/// an [`EntityRef`] which allows access to an entity's components.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EntityId(u32);

/// A position in world space.
#[derive(Copy, Clone, Debug)]
pub struct Position {
    pub x: f64,
    pub y: f64,
    pub z: f64,
    pub pitch: f32,
    pub yaw: f32,
    pub on_ground: bool,
}

/// Position of a block in world space.
///
/// Like [`Position`], but coordinates are always integers.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct BlockPosition {
    pub x: i32,
    pub y: i32,
    pub z: i32,
}

/// The name of an entity.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Name(pub String); // TODO: evaluate heap allocation

/// Error returned when an entity no longer exists.
#[derive(Debug, thiserror::Error)]
#[error("entity has been despawned")]
pub struct EntityDead;

/// Error returned when a block cannot be accessed because
/// its chunk is not loaded.
#[derive(Debug, thiserror::Error)]
#[error("block chunk is unloaded")]
pub struct ChunkNotLoaded;

/// Error returned when a resource of some type does not exist.
#[derive(Debug, thiserror::Error)]
#[error("missing resource of type '{0}'")]
pub struct MissingResource(&'static str);

/// A type that can be stored in [`State`] as a "resource."
///
/// Resources are useful for plugin state that is not directly
/// related to a specific entity. For example, you might store
/// your plugin's configuration in a `Resource`.
///
/// Use [`State::resource`] and [`State::resource_mut`] to access resources.
/// Similarly, use [`Setup::resource`] to create a resource when your plugin
/// is loaded.
///
/// This trait is automatically implemented for most types.
pub trait Resource: Send + Sync + 'static {}
impl<T> Resource for T where T: Send + Sync + 'static {}

/// The main server state.
///
/// This struct is passed to systems and event handlers. It
/// provides access to entities, components, blocks, resources,
/// etc.
#[derive(Debug)]
pub struct State;

impl State {
    /// Gets an [`EntityRef`] from an [`EntityId`].
    ///
    /// Returns an error if the entity no longer exists.
    pub fn entity(&self, _id: EntityId) -> Result<EntityRef, EntityDead> {
        todo!()
    }

    /// Gets the block at the given position.
    ///
    /// Returns an error if the block's chunk is not loaded.
    pub fn block(&self, _pos: BlockPosition) -> Result<BlockId, ChunkNotLoaded> {
        todo!()
    }

    /// Sets the block at the given position.
    ///
    /// Returns an error if the block's chunk is not loaded.
    pub fn set_block(&self, _pos: BlockPosition, _block: BlockId) -> Result<(), ChunkNotLoaded> {
        todo!()
    }

    /// Gets a reference to a resource.
    ///
    /// Returns an error if the resource does not exist.
    pub fn resource<T: Resource>(&self) -> Result<&T, MissingResource> {
        todo!()
    }

    /// Gets a mutable reference to a resource.
    ///
    /// Returns an error if the resource does not exist.
    pub fn resource_mut<T: Resource>(&self) -> Result<&mut T, MissingResource> {
        todo!()
    }
}

impl State {
    /// Gets an online player by their username.
    pub fn player_by_name(&self, _name: &str) -> Option<EntityRef> {
        todo!()
    }

    /// Gets an online entity by their UUID.
    ///
    /// This function works for all entities, not just players.
    pub fn entity_by_uuid(&self, _uuid: Uuid) -> Option<EntityRef> {
        todo!()
    }
}

/// A function that can be used as a command executor.
///
/// This is a temporary Bukkit-like command API. We'll figure
/// out a more structured approach to commands (like Brigadier)
/// in the future.
pub type CommandExecutor = fn(state: &mut State, sender: EntityRef, args: &[&str]) -> SysResult;

/// A builder for a command.
///
/// # Example
/// A basic `/msg` command:
/// ```no_run
/// # fn main() -> anyhow::Result<()> {
/// use quill_prototype::{CommandBuilder, State, EntityRef, SysResult};
///
/// # let mut setup = quill_prototype::Setup;
///
/// CommandBuilder::new("msg")
///     .alias("m")
///     .build(on_msg, &mut setup);
///
/// fn on_msg(state: &mut State, sender: EntityRef, args: &[&str]) -> SysResult {
///     if args.len() < 1 {
///         sender.send_message("Usage: /msg <player> [message...]")?;
///         // Note that a command executor should only return an `Err`
///         // when an internal error occurs, not when user input is incorrect.
///         // Returning an error will
///         // send the player a "an internal error occurred while trying to execute
///         // this command" message and print the error to the console.
///         // Returning an `Err` is like throwing
///         // an exception in Bukkit.
///         return Ok(());
///     }
///     let target = match state.player_by_name(args[0]) {
///         Some(player) => player,
///         None => {
///             sender.send_message(&format!("Player {} not found.", args[0]));
///             return Ok(());
///         }
///     };
///     
///     // Build the message by accumulating `args`.
///     let mut message = String::new();
///     for arg in &args[1..] {
///         message += arg;
///         message.push(' ');
///     }
///     target.send_message(&message)?;
///     Ok(())
/// }
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct CommandBuilder;

impl CommandBuilder {
    /// Creates a new `CommandBuilder` for a command with
    /// the given name.
    ///
    /// # Example
    /// Create a `CommandBuilder` for the `/msg` command:
    /// ```no_run
    /// use quill_prototype::CommandBuilder;
    /// CommandBuilder::new("msg");
    /// ```
    /// (Note the absence of a preceding slash.)
    pub fn new(_name: &str) -> Self {
        todo!()
    }

    /// Adds an alias for this command.
    pub fn alias(&mut self, _alias: &str) -> &mut Self {
        todo!()
    }

    /// Builds this `CommandBuilder`.
    ///
    /// This function takes:
    /// * The function called when the command is executed
    /// * The [`Setup`] passed to your plugin's `setup` function
    /// and registers the command with the server.
    pub fn build(&mut self, _executor: CommandExecutor, _setup: &mut Setup) {
        todo!()
    }
}

/// A system, the `S` part of the ECS.
///
/// System functions are invoked each tick.
///
// # Errors
/// A system returns a [`SysResult`], which is a `Result<(), anyhow::Error>`.
/// (See [`anyhow`](https://docs.rs/anyhow).)
///
/// Returning an error should be preferred to panicking, as it allows
/// for more graceful recovery. If your plugin panics, then the server
/// will have to reload it as its internal state can no longer be considered
/// intact. On the other hand, returning an error from a system will result
/// in a console message, but it typically won't cause anything to break.
pub type System = fn(&mut State) -> SysResult;

/// Struct passed to your plugin's `setup` function which
/// is called when it's loaded.
///
/// Use this struct to register systems, resources, components,
/// commands, event handlers, etc.
#[derive(Debug)]
pub struct Setup;

impl Setup {
    /// Registers a resource. The resource can later
    /// be accessed via [`State::resource`].
    pub fn resource(&mut self, _resource: impl Resource) -> &mut Self {
        todo!()
    }

    /// Registers a system.
    /// The `system` function will be invoked each tick.
    pub fn system(&mut self, _system: System) -> &mut Self {
        todo!()
    }
}