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.
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: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:
# Clone with submodules
git clone --recursive https://github.com/Pumpkin-MC/Pumpkin.git
cd PumpkinIf you have already cloned without --recursive, initialize the submodules manually:
git submodule update --init --recursive3. Building and Running
You can compile and launch the server in debug mode:
cargo runTo build an optimized release binary (with LTO and single codegen units):
cargo build --releaseCoding 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()orexpect(): 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!(), orunimplemented!(): Do not leave unhandled stubs or panic statements in committed code. - No
println!()oreprintln!(): Always use the structured logging frameworktracing:rustuse 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 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:
- Tokio Runtime (Asynchronous I/O): Handles TCP/UDP network connections, incoming/outgoing packet streams, authentication HTTP requests, and timers.
- 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:
// 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:
# 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
typosBenchmarking Performance
If you are modifying performance-sensitive hot paths (such as packet serialization, chunk loading, or entity ticking), run benchmarks with Criterion:
cargo benchConsider 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 with the Vineflower decompiler:
git clone https://github.com/FabricMC/yarn.git
cd yarn
./gradlew decompileVineflowerAfter decompilation completes, the mapped source code will be available in:
build/namedSrcUseful Protocol & Data Resources
- Minecraft Wiki Protocol Reference: Complete reference of packet structures, fields, and IDs across game states.
- Mojang Data Reports: Raw JSON dumps of registries, blocks, items, commands, and packet IDs.
tools/pumpkin-codegen: Our internal tool for parsing Minecraft game data and generatingpumpkin-datacode.
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:
- Fork the Repository: Fork Pumpkin-MC/Pumpkin on GitHub.
- Create a Feature Branch:bash
git checkout -b feature/my-new-feature - Commit Your Changes: Follow the Conventional Commits specification (detailed below).
- 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.
- 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 specification. This convention ensures consistent commit history and automated release changelog generation.
Commit & PR Title Structure
<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, notaddedoradds;fix, notfixedorfixes). - 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 includeBREAKING 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.