Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

ProjectRed is a NeoForge Minecraft mod (MC 1.21.1, NeoForge 21.1.72, Java 21) focused on Redstone circuitry. It uses a multi-module Gradle build.

## Build Commands

```bash
./gradlew build # Build all modules
./gradlew :core:build # Build a specific module
./gradlew genIntellijRuns # Generate IntelliJ run configs
./gradlew test # Run all unit tests
./gradlew :core:test # Run unit tests for a specific module
./gradlew :transmission:runGameTestServer # Run in-game tests for transmission module
```

Built JARs are placed in `<module>/build/libs/`.

## Module Architecture

The project is split into 8 modules with a strict dependency hierarchy:

```
api (no mod deps — public API for other mods)
core → api, CodeChickenLib, CBMultipart, JEI, CCTweaked
├── expansion (pistons, frames, block movement)
├── exploration (world generation content)
├── illumination (lighting blocks)
├── integration (logic gates and basic circuits)
└── transmission (wire networks and signal routing)
└── fabrication → core + integration + transmission (factory automation, largest module)
runtime (empty module; aggregates all modules for IDE run configs)
```

Each module's main class is annotated with `@Mod("projectred_<module>")`.

### Key Internal Packages (core module)

- `mrtjp.projectred.core` — Mod entry point (`ProjectRedCore.java`)
- `mrtjp.projectred.core.init` — Deferred registers (blocks, items, menus, parts, creative tabs)
- `mrtjp.projectred.core.tile` — Block entities
- `mrtjp.projectred.core.part` — CBMultipart multipart definitions
- `mrtjp.projectred.core.power` — Power/energy system interfaces
- `mrtjp.projectred.lib` — Shared utilities (VecLib, ModelLib, etc.)
- `mrtjp.projectred.redui` — Custom UI framework used across all modules

### CBMultipart Integration

Blocks that can coexist in the same world position (e.g., wires) are implemented as "parts" rather than standard blocks. These extend CBMultipart's `MultiPart` class and register via `CBMultipartPlugin`. Parts live in `*.part` packages.

### Public API

`mrtjp.projectred.api.ProjectRedAPI` is the entry point for other mods. Module API fields (e.g., `transmissionAPI`, `expansionAPI`) are nullable — they're only set when the module is loaded. Other mods should use soft dependencies.

## Data Generation

Generated assets (models, recipes, tags, lang files) are output to `<module>/src/main/generated/`. Do not manually edit files in `generated/` — they are regenerated by datagen runs (`./gradlew :<module>:runData`).

Translation files go in `<module>/src/main/resources/assets/projectred_<module>/lang/`. Run the verification script after editing translations:

```bash
python3 .github/verify_lang_files.py --language <lang_code> --verbose
python3 .github/verify_lang_files.py --language <lang_code> --fix # auto-fix ordering/missing keys
```

## Testing

- **Unit tests** (JUnit 5): `<module>/src/test/java` — currently in `core` (VecLib, ModelLib, voxel shapes)
- **Game tests** (NeoForge GameTest framework): `transmission` module has active game test infrastructure; test namespace is `projectred_transmission`

## CI

Pull requests run: commitlint, lang file verification, `./gradlew build`, and transmission game tests. Commit messages must follow conventional commits (see `.github/commitlint.config.js`).
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ subprojects { p ->
maven { url = "https://maven.covers1624.net/" }
maven { url = "https://maven.squiddev.cc" }
maven { url = "https://maven.blamejared.com/" }
maven { url = "https://api.modrinth.com/maven" }
}

// Replace version tokens in mods.toml
Expand All @@ -58,7 +59,8 @@ subprojects { p ->
'lang_version': forge_version.split('\\.')[0],
'ccl_version': ccl_version,
'cbm_version': cbm_version,
'cct_version': cct_version
'cct_version': cct_version,
'embeddium_version': embeddium_version,
]

inputs.properties(expandMap)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package mrtjp.projectred.core.client;

import codechicken.lib.model.PerspectiveModel;
import codechicken.lib.model.PerspectiveModelState;
import codechicken.lib.render.CCModel;
import codechicken.lib.render.CCRenderState;
import codechicken.lib.render.buffer.BakedQuadVertexBuilder;
import codechicken.lib.util.TransformUtils;
import codechicken.lib.vec.Cuboid6;
import codechicken.lib.vec.Rotation;
import codechicken.lib.vec.Vector3;
import codechicken.lib.vec.uv.MultiIconTransformation;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.client.ChunkRenderTypeSet;
import net.neoforged.neoforge.client.model.IDynamicBakedModel;
import net.neoforged.neoforge.client.model.data.ModelData;
import net.neoforged.neoforge.client.model.generators.ConfiguredModel;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
* Needs to exist because Vanilla's default {@link ConfiguredModel} only supports a single x rotation and y rotation,
* making it very difficult to render blocks that can not only be oriented to all 6 sides, but also rotated about those
* sides. With only x/y rotations, we would have to use UV-mapping to rotate the textures themselves rather than the model.
*/
public abstract class FullyOrientableBlockModel implements IDynamicBakedModel, PerspectiveModel {
// State -> Side -> Quads list
private final HashMap<BlockState, HashMap<Integer, List<BakedQuad>>> modelMap = new HashMap<>();

//region Implementation abstracts
protected abstract RenderType getBlockRenderLayer(@Nullable BlockState state);

protected abstract RenderData getBlockRenderData(@Nullable BlockState state);

protected abstract BlockState getItemRenderState();
//endregion

@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, ModelData date, @Nullable RenderType renderType) {
// Render type must match
if (renderType != null && renderType != getBlockRenderLayer(state)) {
return List.of();
}
// Full block, so no uncullable sides
if (side == null) {
return List.of();
}

if (state == null) {
state = getItemRenderState();
}

return getOrGenerateQuads(state, side);
}

private List<BakedQuad> getOrGenerateQuads(BlockState state, Direction side) {
HashMap<Integer, List<BakedQuad>> sideMap = modelMap.get(state);
if (sideMap != null) return sideMap.get(side.ordinal());

synchronized (modelMap) {
// Re-check after waiting for sync
sideMap = modelMap.get(state);
if (sideMap == null) {
sideMap = generateSideMap(state);
modelMap.put(state, sideMap);
}
}

return sideMap.get(side.ordinal());
}

private HashMap<Integer, List<BakedQuad>> generateSideMap(BlockState state) {
// Prep render
CCRenderState ccrs = CCRenderState.instance();
ccrs.reset();
ccrs.computeLighting = false;
ccrs.brightness = 0;
BakedQuadVertexBuilder builder = new BakedQuadVertexBuilder();
ccrs.bind(builder, DefaultVertexFormat.BLOCK);

// Render full block model with orient transform
RenderData data = getBlockRenderData(state);
CCModel m = CCModel.quadModel(24)
.generateBlock(0, Cuboid6.full, 0)
.apply(Rotation.sideOrientation(data.side, data.rotation).at(Vector3.CENTER))
.computeNormals()
.shrinkUVs(0.0005);

m.render(ccrs, data.iconT);

// Bake and separate sides
HashMap<Integer, List<BakedQuad>> sideMap = new HashMap<>();
List<BakedQuad> blockQuads = builder.bake();
for (int s = 0; s < 6; s++) {
LinkedList<BakedQuad> sideQuads = new LinkedList<>();
for (BakedQuad quad : blockQuads) {
if (quad.getDirection().ordinal() == s) {
sideQuads.add(quad);
}
}
sideMap.put(s, sideQuads);
}

return sideMap;
}

@Override
public ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, ModelData data) {
return ChunkRenderTypeSet.of(RenderType.solid());
}

public record RenderData(int side, int rotation, MultiIconTransformation iconT) {
}

//region BakedModel
//@formatter:off
@Override public boolean useAmbientOcclusion() { return true; }
@Override public boolean isGui3d() { return true; }
@Override public boolean usesBlockLight() { return true; }
@Override public boolean isCustomRenderer() { return false; }
@Override public ItemOverrides getOverrides() { return ItemOverrides.EMPTY; }
@Override public @Nullable PerspectiveModelState getModelState() { return TransformUtils.DEFAULT_BLOCK; }
//@formatter:on
//endregion
}

This file was deleted.

3 changes: 3 additions & 0 deletions expansion/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ dependencies {
compileOnly project(":api")
implementation project(":core")

compileOnly "maven.modrinth:embeddium:${embeddium_version}"
compileOnly "maven.modrinth:sodium:${sodium_version}"

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
testImplementation 'org.mockito:mockito-core:5.14.2'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// 1.21.1 2025-08-10T20:38:13.26732 Block States: projectred_expansion
// 1.21.1 2026-04-12T17:22:00.453012 Block States: projectred_expansion
b697bf3bc54738e649092c6b88cbb4fd9b3da8a3 assets/projectred_expansion/blockstates/auto_crafter.json
1d92e2503aa76e8cf9e908f7afa248a291fcf387 assets/projectred_expansion/blockstates/battery_box.json
325a4ac57dbf6f6f049812d1442992b5f7368d21 assets/projectred_expansion/blockstates/block_breaker.json
ac22e2b26c326b40d94951ed7a69b7b994f14aca assets/projectred_expansion/blockstates/charging_bench.json
2742c5200239a1933b73b45885d8d5fe0ec5ed3d assets/projectred_expansion/blockstates/deployer.json
fe88677fa2e1cf270a91e8e1ac1f8b598786949f assets/projectred_expansion/blockstates/fire_starter.json
e285658b615ec1141d09ddb523656ad8dcd0c634 assets/projectred_expansion/blockstates/frame.json
ca6b372af9ea72459f49dc7ffd30ce5c744aedf9 assets/projectred_expansion/blockstates/frame.json
2ea35b8dcec2486da65f2464436c04aba36624b1 assets/projectred_expansion/blockstates/frame_actuator.json
da1694043a21b0b85aa2918f534786f5e0de0cb7 assets/projectred_expansion/blockstates/frame_motor.json
906c41f10706c0c5d48631877a7fa58a18590b8b assets/projectred_expansion/blockstates/frame_motor.json
97acab0b18004d35a03674349f4c14542707ad66 assets/projectred_expansion/blockstates/project_bench.json
99538255fa8dddf3c50e280e1e4d9f7d3248231c assets/projectred_expansion/blockstates/transposer.json
37c0bb69db6a7bdf44866469f4d8e0a69d22d137 assets/projectred_expansion/models/block/auto_crafter.json
Expand All @@ -30,11 +30,11 @@ b2c9b5a1a4bf62a48df2c407c571f58251dd79ea assets/projectred_expansion/models/bloc
8abdb147b3c3e33a1c3ca5903f6bf57b269061c8 assets/projectred_expansion/models/block/deployer_active.json
99b61408e0d2bdaae3a09a6c17e762435068537e assets/projectred_expansion/models/block/fire_starter.json
d34961059b05c1caf2059ffba539b5ffc38c36a5 assets/projectred_expansion/models/block/fire_starter_active.json
9049814fa7507a8bfdb47497310140da703d6417 assets/projectred_expansion/models/block/frame.json
9dbba6f59658244da05c4cdeaeb1691deef902d8 assets/projectred_expansion/models/block/frame_actuator.json
9130fd3156286ec9bcc1e958be94505d47cf1e36 assets/projectred_expansion/models/block/frame_actuator_state1.json
441616b7dbe0c0ec337ad807c7214514c45979dc assets/projectred_expansion/models/block/frame_actuator_state2.json
176677c516b3203abbf46daed70cbcfcca83eab5 assets/projectred_expansion/models/block/frame_motor_programmatically_rendered.json
cf74edee7186e05fd24bd7fae56c2e23d1bd1de4 assets/projectred_expansion/models/block/frame_programmatically_rendered.json
9f4fe5a1992cc2f32eafc351e05c8c1f836e7e60 assets/projectred_expansion/models/block/frame_motor.json
645544cf14d5ca7f1577a11532a3321c06a51e18 assets/projectred_expansion/models/block/project_bench.json
17e1cc736c14625f137dbe9d5871e07d4eb85e73 assets/projectred_expansion/models/block/transposer.json
6bbf26b37dd2a946ced5c52327c3e4c860918566 assets/projectred_expansion/models/block/transposer_active.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 1.21.1 2025-08-10T20:38:13.265665 projectred_expansion Item models.
// 1.21.1 2026-04-12T17:10:13.738951 projectred_expansion Item models.
599e9047cbf1215359e3106b1a6a0757a569ffc9 assets/projectred_expansion/models/item/auto_crafter.json
736ab07c8745c163e8a3cb90abc9308466032009 assets/projectred_expansion/models/item/battery.json
d887cd7b776f1227da04cf267bf0a48dbc706027 assets/projectred_expansion/models/item/battery_box.json
Expand All @@ -16,9 +16,9 @@ ca8ee7426c8d4b145e75bc0bebca77c90e05779e assets/projectred_expansion/models/item
f8ad62a7aa4f5ae87d36e422722c4ffbf46d22e1 assets/projectred_expansion/models/item/electric_screwdriver.json
c04ad8c2f44fd4f5a6ea7c5bb9ddf98629332a84 assets/projectred_expansion/models/item/empty_battery.json
8adfe244bf33706f67d587942e9179b74cf38fd0 assets/projectred_expansion/models/item/fire_starter.json
432462cb1b080b869c472c0e8f7495e9b4e1d638 assets/projectred_expansion/models/item/frame.json
4b23c55840a25bba29226122efb428357ce7c98b assets/projectred_expansion/models/item/frame.json
933ec48f28e2627aefbdcaa7d989eeac271ad282 assets/projectred_expansion/models/item/frame_actuator.json
78ea8ea37f9467201dc2e05ef372f4403ccbadb2 assets/projectred_expansion/models/item/frame_motor.json
369295af47e837e0fffaf9174fda04d7175bbc4d assets/projectred_expansion/models/item/frame_motor.json
efabd61ed85b4d67f546ea6cfb90d9f5f17773cc assets/projectred_expansion/models/item/pneumatic_tube.json
9457da7d0b200c883ca98241d9bf155043221c53 assets/projectred_expansion/models/item/project_bench.json
5d8ae0bcb189be1eb7ce726fc4d28637dcdfaac8 assets/projectred_expansion/models/item/recipe_plan.json
Expand Down
Loading
Loading