ChipiMod/CONTRIBUTING.md

4.8 KiB

Contributing Guide (Java Style)

This project follows a strict, C/C++-style Java formatting rule set. The goal is to preserve intent, control flow clarity, and fast mental parsing. Please follow these rules for any Java changes.

If a tool or formatter fights these rules, the tool is wrong.

Core Philosophy

  • Java is written as if it were C/C++.
  • Formatting must never change perceived control flow.
  • Readability means fast, correct parsing in your head.
  • Tools adapt to the codebase, not the other way around.

Indentation & Whitespace

  • Indentation: 4 spaces.
  • No tabs.
  • Avoid excessive vertical whitespace.
  • Blank lines only when they add logical separation.

Good:

int sum(int a, int b) {
    int r = a + b;
    return r;
}

Bad:

int sum(int a, int b)

{

    int r = a + b;

    return r;
}

Braces

  • Braces are always required.
  • Opening brace stays on the same line.
  • Never rely on implicit scopes.

Good:

if (value == null) {
    return;
}

Bad:

if (value == null)
{
    return;
}

Imports (Strict Rules)

Never use fully-qualified class names inline

Forbidden:

net.minecraft.util.math.BlockPos pos = new net.minecraft.util.math.BlockPos(0, 0, 0);

Required:

import net.minecraft.util.math.BlockPos;

BlockPos pos = new BlockPos(0, 0, 0);

Import grouping and ordering

  1. Imports from external/other packages first.
  2. Blank line.
  3. Imports from this project (net.Chipperfluff.*) next.

Inside each block, order by:

  1. Classes
  2. Functions (static method imports)
  3. Variables/constants (static field imports)
  4. Enums

If there are no project imports, do not add a blank line.

Method Signatures

  • Method signatures must stay on one line.
  • Do not break parameters across multiple lines.
  • Long lines are acceptable; ambiguity is not.

Good:

void processUser(User user, int flags, boolean force, long timeout) {
    ...
}

Bad:

void processUser(
    User user,
    int flags,
    boolean force,
    long timeout
) {
    ...
}

Function Calls & Argument Layout

Default rule

  • Single-line calls are preferred.
  • Flat calls stay flat.
  • Length alone is not a reason to wrap.

Good:

Color color = user.getProfile().getSettings().getTheme().getPrimaryColor();

Multiline calls are allowed only when:

  • The call is structural or declarative.
  • Each argument is conceptually distinct.
  • Nesting would otherwise hide meaning.

Good (structural/declarative):

BiomeModifications.addFeature(
    BiomeSelectors.foundInOverworld(),
    GenerationStep.Feature.UNDERGROUND_ORES,
    RegistryKey.of(
        RegistryKeys.PLACED_FEATURE,
        new Identifier("chipi", "chipper_ore")
    )
);

Bad (no semantic gain):

doThing(
    a,
    b,
    c
);

Chained Calls

  • Flat chains stay on one line.
  • Long or builder-style chains may be split vertically.
  • Each chained step gets its own line.

Good:

builder
    .withColor(theme.getPrimaryColor())
    .withSize(32)
    .enableShadow()
    .build();

Bad:

builder.withColor(
    theme.getPrimaryColor()
).withSize(
    32
).enableShadow().build();

Control Flow & Returns

  • Early returns are encouraged.
  • Avoid artificial nesting.
  • Single-exit functions are not required.

Good:

void handle(User user) {
    if (user == null) return;
    if (!user.isActive()) return;

    process(user);
}

Bad:

void handle(User user) {
    if (user != null) {
        if (user.isActive()) {
            process(user);
        }
    }
}

One-Liners

  • One-liners allowed for simple guard clauses.
  • No complex logic on one line.

Allowed:

if (value == null) return;

Not allowed:

if (a == b && c != d && flag && check()) doThing();

Null Handling

  • null is a valid, intentional state.
  • Do not over-engineer around it.
  • Prefer clarity over defensive clutter.

Good:

User user = findUser(id);
if (user == null) return;

Logging & Debug Output

  • Logging must be short and readable.
  • Prefer System.out.println for quick diagnostics.
  • Verbose logging only when justified.

Good:

System.out.println("Loaded structure: " + id);

Autoformatters & Linters

Autoformatters must not:

  • Break method signatures.
  • Move braces to new lines.
  • Introduce unwanted trailing newlines.
  • Rewrap stable code repeatedly.

If a formatter fights these rules: disable or reconfigure it.

Empty Methods

Empty methods or constructors must be written on one line:

public static void register() {}

Summary (Non-Negotiable)

  • Java written with C/C++ structure.
  • Compact signatures, explicit layout.
  • Imports always used (no fully-qualified inline types).
  • Multiline formatting only when it adds meaning.
  • Formatting reflects logic, not fashion.