Skip to content

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:

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:
    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 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:

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 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: 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 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 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 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

TypePurposeExample
featIntroduces a new feature or vanilla game mechanicfeat(entity): implement drowned swimming goal
fixResolves a bug, glitch, or protocol issuefix(protocol): resolve creative slot index offset
docsDocumentation additions or updatesdocs(developer): add porting versions guide
perfCode modifications that improve execution speed or memory usageperf(world): optimize chunk section block iteration
refactorCode changes that neither fix bugs nor add featuresrefactor(command): unify argument parsing helpers
testAdding missing tests or correcting existing teststest(inventory): add crafting table recipe tests
choreRoutine maintenance, dependency bumps, or toolchain updateschore(deps): bump tokio to 1.43
ciModifications to CI workflows, scripts, or Docker containersci(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.

MIT ライセンスの下でリリースされています。