Skip to content

drey7925/perovskite

Repository files navigation

&🧊 Perovskite

Perovskite is a 3D voxel game engine inspired by Minetest.

It is written in Rust, with two goals:

  • Give me an opportunity to learn Rust
  • Create a decently playable game

At this time, it is not a playable game.

As this is a learning project, I may spend time on silly things that may not be useful to players or improved gameplay, if I think I can learn something from doing so. Likewise, I may use design patterns inconsistently (or make other inconsistencies) to increase the breadth of my learning. If there is enough interest or need, I can refactor and clean up code later.

Why the name?

Naming Rust projects after oxide minerals is fun. Unfortunately, all the cool oxide minerals are already used for really cool rust projects, or could otherwise cause confusion.

Perovskite is a cool mineral that inspired artificial structures with a bunch of cool aspirational applications.

What's the current state?

It is possible to define blocks and dig them. Inventory support is mostly present. There's a furnace and a crafting mechanism. Game content (i.e. all the blocks you'd expect) is not yet present.

Entities are under active development, but are not yet stable. The entity system is currently focused on autonomous movement, and low-latency player control will be added in the future.

I intend to wrap the engine-specific behaviors in a lightweight API that makes it easier to define game logic. That API is still not stable, but I intend to make that API more stable than the low-level engine API.

At the moment, the network API is not yet stable - the client and server must be built from the same code. The intent is to stabilize the API to a reasonable extent later on, but having an unstable API allows for faster feature iteration.

How is it different from similar voxel games?

The limitations:

  • The implementation is a bit more incoherent since it's a learning project
  • The game lacks a lot of content
  • A lot of basic features, like a player model, are still missing
  • No scripting language yet - all game logic is written in Rust
    • And no dynamic content loading yet. It might be possible once crABI stabilizes.
  • TLS support is a WIP. At this time, you need to bring your own certificate.
    • Let's Encrypt (certbot) works for this. One day, I'd like to implement automatic certificate provisioning using ACME + ALPN challenges. This ran into some problems on my first attempt.
    • TLS-secured servers should use address format https://domain:port
    • Unsecured servers should use the existing format grpc://domain:port

The benefits:

  • The engine is optimized for scalability and performance where possible
    • Note that not all of the components have been optimized yet
  • The minecarts can move at an unusually high speed, comparable to real-world HSR
  • All game logic is written in Rust
  • Authentication uses a secure remote password protocol that avoids sending the password over the network
  • Communication is secured with TLS

How do I play it?

Server

First, build and run the server:

$ cargo build  --features= --bin perovskite_game_api --release
$ target/release/perovskite_game_api --data-dir /path/to/data-directory

The default server port is 28273.

The following --features can be used to do performance debugging of the server:

  • deadlock_detection - Prints stacktraces when certain deadlocks occur
  • tracy - Exports trace spans and metrics to tracy.
    • Depending on your system configuration, thread stacks and thread scheduling events may be visible. e.g. on Windows, this requires running the game server as an admin.
  • dhat-heap - Tracks heap allocations with dhat. Slow, and suspected to cause a rare deadlock.
  • tokio-console - Exports tokio stats to Tokio console. Requires $RUSTFLAGS to contain --cfg tokio_unstable.

--release is recommended.

At the moment, the render distance is hardcoded at the server, using constants in src/network_server/client_context.rs.

Use Ctrl+C to exit, and Ctrl+C a second time to force quit. At the moment, there are some deadlocks that cause graceful shutdown to hang.

Client

Then, build and run the client:

$ cargo build --features= --bin perovskite_client --release
$ target/release/perovskite_client

The only supported feature is --features=tracy, with similar behavior to the same feature on the server.

To reach a client on the local machine, use grpc://localhost:28273 as the server address.

Default keybinds

  • move with WASD
  • space to go up
  • left-click to dig
  • right-click to place
  • F to interact with a block (e.g. furnace/chest).
  • I for inventory
  • P to toggle between normal physics, flying, and noclip. This is useful if you spawn underground.
    • left-control to descend
  • Left-shift to sprint (if you have server permission to do so)
  • Escape for menu

These can be adjusted in the settings file, whose filename is printed in the log when the client starts up.

What are the requirements?

It runs on Windows and Linux. Mac is an open question due to issues involving Vulkan libraries.

Aspirationally, I'd like the game to be somewhat playable in single-player with only one or two CPU cores and a very basic GPU.

I'm not quite there yet, and it's possible that I'll drift further away from this goal as I add features. I tend to test with a fairly powerful laptop and a high-end GPU. I aim for the following performance goals:

  • 165 FPS (matching my monitor refresh rate) and no noticeable interaction latency when using my gaming machine - to ensure there are not bottlenecks at the high end of scaling
  • 30-50 FPS on Intel integrated graphics when the client and server are limited to a few E-cores.
    • This will require both optimizations and better control over load (e.g. settings, dynamic render distance, etc)

What's on the near-term roadmap?

Tons of stuff, in no particular order, and not yet prioritized. Everything in this list is a maybe, depending on my available time and mood.

  • Rendering and display:
    • TBD
  • Game map
    • Support for falling blocks (e.g. sand)
    • Further optimized APIs
      • Block visitors? (e.g. for_each_connected and similar taking closures and running them efficiently)
    • Out-of-line chunk loading (e.g. offloaded onto a dedicated executor)
    • Map bypass (i.e. stream chunks directly to the client for display)
  • Entities
    • Entity appearance/model
    • Optimized (shader-assisted?) entity renderer
    • Simpler (tokio-driven) entity API (i.e. use a tokio task rather than the custom coroutine)
    • Entity interaction
  • Net code
    • Testing and optimization for slow WANs
    • Player action validation
    • Adaptive and adjustable chunk load distance
  • Content
    • Torch (doable w/ custom geometry + custom handlers)
    • Mapgen
      • Trees - keep refining
      • Sand and other surface material variety
      • Ores (+ resulting items)
      • Slightly more interesting elevation profile
    • Helpers for stairs and slabs
    • Simple tools
    • Locked chests
    • Cobblestone, bricks, etc
    • Minecarts
      • Interlockings/signals
      • Route selection
      • Map all switch/curve types
      • Starting/stopping and entering/exiting carts
      • Track placement tool
      • Ensure stability at high speeds under server load
    • Pneumatic tubes
      • Tubes to send items between chests and furnaces, as a basis for some kind of machines later on
  • Audio
  • Bugfixes for known issues
    • Trees intersect each other
    • Only binds to IPv6 on Windows

What are the stability guarantees?

None at the moment. I test with either the latest or almost-latest stable Rust version, on Windows x64.

perovskite_server's API can change in breaking ways. perovskite_game_api (as well as anything it re-exports by default) should be reasonably stable once it's written. I intend to re-export some unstable APIs behind a feature flag.

Code style

  • Formatted following cargo fmt
  • No unsafe
  • No nightly-only features; should build on stable Rust.

Who is behind this?

I work on low-level infrastructure at a major hyperscaler and produce this game in my free time. You can find me on discord as drey7925.

Note that this project is not endorsed, sponsored, or supported by my employer or any affiliates.