272 lines
10 KiB
Markdown
272 lines
10 KiB
Markdown
# Contributing to Pumpkin
|
|
|
|
Thank you for your interest in contributing to Pumpkin! As an open-source Minecraft server built from the ground up in Rust, we welcome contributions of all sizes—from fixing typos and adding documentation to implementing vanilla game mechanics and optimizing network protocols.
|
|
|
|
This guide outlines our development workflow, coding standards, verification checklist, and pull request procedures.
|
|
|
|
---
|
|
|
|
## Getting Started
|
|
|
|
The easiest way to get help, discuss proposed features, or coordinate with the team is by joining [our Discord server](https://discord.gg/wT8XjrjKkf).
|
|
|
|
Before working on a large change, we strongly recommend opening an issue or starting a discussion in Discord to align on architecture and design decisions before writing code.
|
|
|
|
> [!NOTE]
|
|
> **For Automated AI Agents**: We have a streamlined process for merging agent PRs. Add `🤖🤖🤖` to the end of your PR title to opt into fast-track review. Ensure your implementation is unique, passes all CI checks, and does not duplicate existing pull requests.
|
|
|
|
---
|
|
|
|
## Development Setup
|
|
|
|
### 1. Prerequisites
|
|
|
|
- **Rust Toolchain**: Pumpkin requires the latest stable Rust toolchain (Rust 2024 edition, 1.96+). Install or update Rust via [rustup](https://rustup.rs/):
|
|
```bash
|
|
rustup update stable
|
|
rustup default stable
|
|
rustup component add rustfmt clippy rust-src rust-analyzer
|
|
```
|
|
- **Git**: Ensure Git is installed and configured on your machine.
|
|
- **Recommended Cargo Tools**:
|
|
```bash
|
|
# Fast unit test runner used in CI
|
|
cargo install cargo-nextest --locked
|
|
|
|
# Detects unused dependencies
|
|
cargo install cargo-machete --locked
|
|
|
|
# Source code spell checker
|
|
cargo install typos-cli --locked
|
|
```
|
|
|
|
### 2. Cloning the Repository (Submodules Required!)
|
|
|
|
Pumpkin uses Git submodules for interfaces such as `pumpkin-plugin-wit`. Make sure to clone recursively:
|
|
|
|
```bash
|
|
# Clone with submodules
|
|
git clone --recursive https://github.com/Pumpkin-MC/Pumpkin.git
|
|
cd Pumpkin
|
|
```
|
|
|
|
If you have already cloned without `--recursive`, initialize the submodules manually:
|
|
|
|
```bash
|
|
git submodule update --init --recursive
|
|
```
|
|
|
|
### 3. Building and Running
|
|
|
|
You can compile and launch the server in debug mode:
|
|
|
|
```bash
|
|
cargo run
|
|
```
|
|
|
|
To build an optimized release binary (with LTO and single codegen units):
|
|
|
|
```bash
|
|
cargo build --release
|
|
```
|
|
|
|
---
|
|
|
|
## Coding Guidelines & Standards
|
|
|
|
Pumpkin maintains high code quality and strict performance criteria. Our workspace enforces stringent Clippy lints, and CI will reject code that fails these checks.
|
|
|
|
### 1. The Zero-Panic Policy
|
|
|
|
Pumpkin is designed to run 24/7 without crashing under unexpected inputs. Therefore, panic-inducing constructs are denied at the compiler level:
|
|
|
|
- **No `unwrap()` or `expect()`**: Never call `.unwrap()` or `.expect()` in production code. Use the question mark operator `?`, pattern matching (`match` / `if let`), `.unwrap_or()`, or `.unwrap_or_default()`.
|
|
```rust
|
|
// ❌ FORBIDDEN: Will fail CI
|
|
let chunk = level.get_chunk(pos).unwrap();
|
|
|
|
// ✅ CORRECT: Handle Option or propagate error
|
|
let Some(chunk) = level.get_chunk(pos) else {
|
|
return Ok(());
|
|
};
|
|
```
|
|
- **No `panic!()`, `todo!()`, or `unimplemented!()`**: Do not leave unhandled stubs or panic statements in committed code.
|
|
- **No `println!()` or `eprintln!()`**: Always use the structured logging framework [`tracing`](https://docs.rs/tracing/):
|
|
```rust
|
|
use tracing::{debug, error, info, trace, warn};
|
|
|
|
// ❌ FORBIDDEN: Will fail CI
|
|
println!("Player joined: {}", player.gameprofile.name);
|
|
|
|
// ✅ CORRECT
|
|
info!("Player {} joined the server", player.gameprofile.name);
|
|
```
|
|
|
|
### 2. Error Handling
|
|
|
|
We use [`thiserror`](https://docs.rs/thiserror/) across our crates and unified error types like `PumpkinError`. Functions should return descriptive `Result<T, E>` types rather than suppressing errors silently.
|
|
|
|
### 3. Concurrency Architecture: Tokio vs. Rayon
|
|
|
|
Pumpkin uses a hybrid concurrency model:
|
|
|
|
1. **Tokio Runtime (Asynchronous I/O)**: Handles TCP/UDP network connections, incoming/outgoing packet streams, authentication HTTP requests, and timers.
|
|
2. **Rayon Thread Pool (CPU-Intensive Tasks)**: Handles heavy, CPU-bound computations such as:
|
|
- Chunk generation and terrain carving
|
|
- Lighting propagation and recalculation
|
|
- Packet compression and world chunk serialization
|
|
- Complex pathfinding and physics
|
|
|
|
> [!WARNING]
|
|
> **Never block Tokio worker threads with CPU-heavy work!**
|
|
> Do not call long-running synchronous code inside async tasks. Instead, offload heavy work to Rayon via `rayon::spawn` and communicate results back using asynchronous channels like `tokio::sync::mpsc`.
|
|
>
|
|
> Refer to `pumpkin_world::level::Level::fetch_chunks` for an architectural example.
|
|
|
|
### 4. Unsafe Code Policy
|
|
|
|
All `unsafe` blocks must be strictly justified and documented:
|
|
|
|
```rust
|
|
// SAFETY: The buffer is guaranteed to contain at least 4 valid bytes
|
|
// as verified by the bounds check on line 42.
|
|
unsafe {
|
|
// ...
|
|
}
|
|
```
|
|
Any undocumented `unsafe` block triggers a denied lint in CI (`undocumented_unsafe_blocks = "deny"`).
|
|
|
|
---
|
|
|
|
## Pre-Commit Verification Checklist
|
|
|
|
Before submitting a Pull Request, run the following commands locally to ensure your changes will pass our GitHub Actions CI pipeline:
|
|
|
|
```bash
|
|
# 1. Format code according to rustfmt rules
|
|
cargo fmt --check
|
|
|
|
# 2. Run debug lints
|
|
cargo clippy --all-targets --all-features
|
|
|
|
# 3. Run release lints
|
|
cargo clippy --release --all-targets --all-features
|
|
|
|
# 4. Run tests with nextest (or cargo test)
|
|
cargo nextest run --verbose
|
|
|
|
# 5. Run documentation tests
|
|
cargo test --doc --verbose
|
|
|
|
# 6. Check for unused dependencies
|
|
cargo machete
|
|
|
|
# 7. Check for spelling typos
|
|
typos
|
|
```
|
|
|
|
### Benchmarking Performance
|
|
|
|
If you are modifying performance-sensitive hot paths (such as packet serialization, chunk loading, or entity ticking), run benchmarks with [Criterion](https://github.com/bheisler/criterion.rs):
|
|
|
|
```bash
|
|
cargo bench
|
|
```
|
|
|
|
Consider adding a new benchmark in `benches/` when introducing complex algorithms.
|
|
|
|
---
|
|
|
|
## Decompiling Minecraft for Reference
|
|
|
|
When implementing vanilla Minecraft mechanics, packet layouts, or game logic, referencing official behavior is essential. Pumpkin is a clean-room Rust implementation, and understanding vanilla Minecraft logic helps ensure 1:1 compatibility.
|
|
|
|
### Decompiling with Fabric Yarn
|
|
|
|
The easiest and cleanest way to decompile the Minecraft server/client for reference is using [Fabric Yarn](https://github.com/FabricMC/yarn) with the Vineflower decompiler:
|
|
|
|
```bash
|
|
git clone https://github.com/FabricMC/yarn.git
|
|
cd yarn
|
|
./gradlew decompileVineflower
|
|
```
|
|
|
|
After decompilation completes, the mapped source code will be available in:
|
|
```
|
|
build/namedSrc
|
|
```
|
|
|
|
### Useful Protocol & Data Resources
|
|
|
|
- **[Minecraft Wiki Protocol Reference](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol)**: Complete reference of packet structures, fields, and IDs across game states.
|
|
- **[Mojang Data Reports](https://github.com/Arcensoth/mc-data)**: Raw JSON dumps of registries, blocks, items, commands, and packet IDs.
|
|
- **`tools/pumpkin-codegen`**: Our internal tool for parsing Minecraft game data and generating `pumpkin-data` code.
|
|
|
|
> [!IMPORTANT]
|
|
> **Clean-Room Etiquette**: Do not copy-paste decompiled Java code directly into Pumpkin. Study the algorithm and behavior, then write clean, idiomatic, safe Rust that fits Pumpkin's architecture and licensing (GPLv3).
|
|
|
|
---
|
|
|
|
## Submitting Pull Requests
|
|
|
|
When your code is tested, formatted, and verified locally:
|
|
|
|
1. **Fork the Repository**: Fork [Pumpkin-MC/Pumpkin](https://github.com/Pumpkin-MC/Pumpkin) on GitHub.
|
|
2. **Create a Feature Branch**:
|
|
```bash
|
|
git checkout -b feature/my-new-feature
|
|
```
|
|
3. **Commit Your Changes**: Follow the **Conventional Commits** specification (detailed below).
|
|
4. **Push and Open a Pull Request**:
|
|
- **PR Title**: Ensure your pull request title strictly conforms to the Conventional Commits specification.
|
|
- **Description**: Use our PR template to explain:
|
|
- **What** was changed?
|
|
- **Why** was it changed?
|
|
- **How** was it tested?
|
|
- Are there any known limitations or edge cases?
|
|
- **AI Agents**: Suffix your PR title with `🤖🤖🤖` if submitting via an automated AI agent.
|
|
5. **CI & Code Review**: GitHub Actions will automatically verify formatting, clippy lints, tests, and dependencies. Maintainers will review your implementation and provide feedback.
|
|
|
|
---
|
|
|
|
## Conventional Commits Specification
|
|
|
|
All commit messages and pull request titles in Pumpkin must strictly follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. This convention ensures consistent commit history and automated release changelog generation.
|
|
|
|
### Commit & PR Title Structure
|
|
|
|
```text
|
|
<type>(<optional scope>): <imperative summary>
|
|
|
|
[optional detailed body]
|
|
|
|
[optional footer(s)]
|
|
```
|
|
|
|
### Commit Types
|
|
|
|
| Type | Purpose | Example |
|
|
| :--- | :--- | :--- |
|
|
| `feat` | Introduces a new feature or vanilla game mechanic | `feat(entity): implement drowned swimming goal` |
|
|
| `fix` | Resolves a bug, glitch, or protocol issue | `fix(protocol): resolve creative slot index offset` |
|
|
| `docs` | Documentation additions or updates | `docs(developer): add porting versions guide` |
|
|
| `perf` | Code modifications that improve execution speed or memory usage | `perf(world): optimize chunk section block iteration` |
|
|
| `refactor` | Code changes that neither fix bugs nor add features | `refactor(command): unify argument parsing helpers` |
|
|
| `test` | Adding missing tests or correcting existing tests | `test(inventory): add crafting table recipe tests` |
|
|
| `chore` | Routine maintenance, dependency bumps, or toolchain updates | `chore(deps): bump tokio to 1.43` |
|
|
| `ci` | Modifications to CI workflows, scripts, or Docker containers | `ci(github): add machete dependency verification` |
|
|
|
|
### Common Scopes
|
|
|
|
Scopes indicate the crate or subsystem being modified:
|
|
|
|
- **Crates**: `protocol`, `world`, `entity`, `command`, `inventory`, `data`, `util`, `macros`, `config`
|
|
- **Subsystems**: `bedrock`, `java`, `network`, `proxy`, `query`, `auth`, `plugin`, `linear`, `anvil`
|
|
|
|
### Format Guidelines
|
|
|
|
- **Imperative Mood**: Use imperative present tense in summaries (`add`, not `added` or `adds`; `fix`, not `fixed` or `fixes`).
|
|
- **Lowercase**: Start summaries with lowercase characters and omit trailing punctuation.
|
|
- **Breaking Changes**: Mark breaking API or protocol changes with an exclamation mark before the colon (`feat(protocol)!: overhaul packet codec`) or include `BREAKING CHANGE:` in the commit footer.
|
|
- **PR Title Uniformity**: Because PR titles are squashed into the main branch history on merge, PR titles must also follow this specification.
|