Skip to content
Merged
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
- build.gradle
- gradle.properties
- settings.gradle
- .github/workflows/pr-build-release.yaml

jobs:
build:
Expand All @@ -18,14 +19,22 @@ jobs:
contents: write

steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version-file: .java-version
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
gradle-version: 8.14.5

- name: Build and test
run: |
./gradlew build test --console=verbose
13 changes: 10 additions & 3 deletions .github/workflows/pr-build.yml → .github/workflows/pr-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@ on:
- build.gradle
- gradle.properties
- settings.gradle
- .github/workflows/pr-build.yaml

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version-file: .java-version
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
gradle-version: 8.14.5

- name: Build and test
run: |
gradle build test --console=verbose
File renamed without changes.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ out
*.iws
*.iml
.idea/workspace.xml
.idea/shelf/

# gradle
build
Expand Down
50 changes: 50 additions & 0 deletions .idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .java-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
17.0.13
17.0.19
1 change: 1 addition & 0 deletions CHANGELOG/1.18/current.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [NEW] JEI is now an optional dependency
8 changes: 5 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ minecraft {
property 'forge.logging.console.level', 'debug'
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
args '--mod', project.mod_id, '--all', '--output', '"' + file('src/generated/resources/') + '"', '--existing', '"' + sourceSets.main.resources.srcDirs[0] + '"'
args '--mod', project.mod_id, '--all',
'--output', file('src/generated/resources/'),
'--existing', sourceSets.main.resources.srcDirs[0]
mods {
create(mod_id) {
source(sourceSets.main)
Expand Down Expand Up @@ -204,7 +206,7 @@ curseforge {
addGameVersion project.target_mc_version
relations {
optionalDependency 'configured'
requiredDependency 'jei'
optionalDependency 'jei'
optionalDependency 'patchouli'
}
}
Expand All @@ -224,7 +226,7 @@ modrinth {
loaders = ["forge"]
dependencies {
optional.project "configured"
required.project "jei"
optional.project "jei"
optional.project "patchouli"
}
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## 1. Hover provider abstraction

- [x] 1.1 Add a `HoverItemProvider` interface under `integration/` returning the item under the mouse for a given
screen + mouse position (priority + `getName()`)
- [x] 1.2 Implement `VanillaSlotHoverProvider` using `AbstractContainerScreen.getSlotUnderMouse()` → `slot.getItem()`;
register it unconditionally
- [x] 1.3 Implement `JeiHoverProvider` wrapping `getIngredientListOverlay().getIngredientUnderMouse()`; this is the only
client-path class that imports JEI API types
- [x] 1.4 Add a registry/lookup that returns registered providers in priority order, with the JEI provider ahead of the
native provider

## 2. JEI classloading isolation & registration

- [x] 2.1 Hand the `IJeiRuntime` from `CTPlugin.onRuntimeAvailable` to `JeiHoverProvider` instead of exposing
`CTPlugin.jeiRuntime` to `ClientEventHandler`
- [x] 2.2 Register `JeiHoverProvider` only behind `ModList.get().isLoaded("jei")`, wired through the existing `Addon`/
`AddonManager` integration layer
- [x] 2.3 Confirm no class on a no-JEI code path statically references `CTPlugin` or any JEI API type

## 3. Repoint add-to-queue

- [x] 3.1 Rewrite `ClientEventHandler#handleAddToQueue` to query the provider lookup, take the first resolved item, and
call `CraftingQueueManager.INSTANCE.addProduct(player, id, 1)` + send the `QUEUE_ITEM` advancement
- [x] 3.2 Remove the JEI import and `CTPlugin.jeiRuntime` reference from `ClientEventHandler`
- [x] 3.3 Confirm `onKeyInput` still gates the action to container screens (extend the allowed screen list if needed)

## 4. JEI-independent data lifecycle

- [x] 4.1 Add a client world-join / login listener that loads `CraftingQueueManager` and `ShoppingListManager` for the
client player, registered in the existing client event wiring
- [x] 4.2 Remove the `load(player)` calls from `CTPlugin.onRuntimeAvailable`
- [x] 4.3 Ensure loading is idempotent and fires once per world entry

## 5. Native item picker in Queue Management screen

- [x] 5.1 Add a search box + scrollable item list to `QueueManagementScreen` backed by `ForgeRegistries.ITEMS`, filtered
by the search term
- [x] 5.2 On selection, call `addProduct(player, itemId, 1)` and refresh the screen/queue
- [x] 5.3 Add any new translation keys to `common/Constants` and `CTLangProvider`, then regenerate with `./gradlew data`

## 6. Dependency metadata

- [x] 6.1 Set `mandatory=false` for the `jei` dependency block in `META-INF/mods.toml`
- [x] 6.2 Change CurseForge `requiredDependency 'jei'` and Modrinth `required.project "jei"` to their optional
equivalents in `build.gradle` (keep `runtimeOnly` JEI for dev)

## 7. Verification

- [x] 7.1 `./gradlew build` and `./gradlew test` pass
- [x] 7.2 Launch `./gradlew client` with JEI present: verify hover-add from container slots, hover-add from the JEI panel, the picker, and that queue/list load on join
- [x] 7.3 Launch the client with JEI removed from `runtimeOnly`: verify the mod loads (no `NoClassDefFoundError`), hover-add from slots works, the picker works, and queue/list load on join
41 changes: 0 additions & 41 deletions openspec/changes/remove-jei-hard-dependency/tasks.md

This file was deleted.

42 changes: 42 additions & 0 deletions openspec/specs/hover-provider-integration/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# hover-provider-integration Specification

## Purpose
TBD - created by archiving change remove-jei-hard-dependency. Update Purpose after archive.
## Requirements
### Requirement: Pluggable item-under-mouse providers

The mod SHALL resolve "the item under the mouse" through a provider abstraction rather than a
direct JEI call. A native provider backed by the vanilla container slot SHALL always be
available. Optional providers backed by other mods (e.g. JEI, and in future REI) SHALL be
available only when the corresponding mod is loaded.

#### Scenario: Native provider always present

- **WHEN** the add-to-queue action runs and no optional item-list mod is loaded
- **THEN** the native container-slot provider resolves the hovered item

#### Scenario: Optional provider used when its mod is present

- **WHEN** JEI is loaded and the player hovers an item in JEI's ingredient list overlay
- **THEN** the JEI provider resolves that item, including items the player does not currently possess

#### Scenario: Provider selection order

- **WHEN** more than one provider could resolve an item under the mouse
- **THEN** the mod queries providers in a defined order and uses the first that returns an item

### Requirement: JEI API code is isolated from no-JEI runtimes

All code that references JEI API types SHALL be confined to classes that are loaded only when
JEI is present, so that running without JEI does not cause class-loading failures.

#### Scenario: Running without JEI does not load JEI classes

- **WHEN** the game starts with Craft Tracker installed but JEI absent
- **THEN** no JEI API class is loaded and the mod initializes without `NoClassDefFoundError`

#### Scenario: Guarded access to the JEI provider

- **WHEN** the mod decides whether to register the JEI hover provider
- **THEN** it checks that JEI is loaded before referencing any JEI-backed class

31 changes: 31 additions & 0 deletions openspec/specs/queue-data-lifecycle/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# queue-data-lifecycle Specification

## Purpose
TBD - created by archiving change remove-jei-hard-dependency. Update Purpose after archive.
## Requirements
### Requirement: Queue and shopping list load independent of JEI

The crafting queue and shopping list SHALL be loaded for the client player on a JEI-independent
client lifecycle event (e.g. client login / world join), not from JEI's runtime-available
callback. Persisted data SHALL load whether or not JEI is installed.

#### Scenario: Joining a world without JEI

- **WHEN** the player joins a world with JEI absent
- **THEN** the crafting queue and shopping list are loaded from disk and reflect their previously saved state

#### Scenario: Joining a world with JEI present

- **WHEN** the player joins a world with JEI installed
- **THEN** the crafting queue and shopping list are loaded exactly once, with no dependence on JEI's runtime callback

### Requirement: JEI dependency is optional

The mod's dependency metadata SHALL declare JEI as optional rather than mandatory, and the mod
SHALL load successfully when JEI is not installed.

#### Scenario: Loading with JEI absent

- **WHEN** the game loads Craft Tracker without JEI installed
- **THEN** the mod loads without a missing-dependency error and all non-JEI features are available

46 changes: 46 additions & 0 deletions openspec/specs/queue-item-input/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# queue-item-input Specification

## Purpose
TBD - created by archiving change remove-jei-hard-dependency. Update Purpose after archive.
## Requirements
### Requirement: Add hovered item to queue from any container view

The mod SHALL add the item currently under the mouse to the crafting queue when the
add-to-queue key is pressed while a vanilla container screen is open, without requiring JEI.
The hovered item SHALL be resolved from the container slot under the mouse so the action works
in the inventory, crafting table, and other container views.

#### Scenario: Hovering an occupied slot in the inventory

- **WHEN** the player opens the inventory, hovers a slot containing an item, and presses the add-to-queue key
- **THEN** that item is added to the crafting queue with quantity 1
- **AND** the queue-item advancement is granted

#### Scenario: Hovering an empty slot

- **WHEN** the player presses the add-to-queue key while the slot under the mouse is empty
- **THEN** no item is added to the queue and no error is shown

#### Scenario: JEI is not installed

- **WHEN** JEI is absent and the player hovers an item in a container view and presses the add-to-queue key
- **THEN** the item is added to the queue using the native container slot, exactly as it would with JEI installed

### Requirement: Add an item to the queue directly from the Queue Management screen

The Queue Management screen SHALL let the player find any registered item by searching and/or
browsing and add it to the crafting queue directly, without needing to hover it in a container
or in JEI. This provides the full-registry add capability when the player does not currently
possess the item.

#### Scenario: Searching for and adding an item

- **WHEN** the player opens the Queue Management screen, enters a search term, and selects a matching item
- **THEN** that item is added to the crafting queue
- **AND** the queue recomputes its intermediates, raw materials, and fuel

#### Scenario: Adding an item the player does not own

- **WHEN** the player selects an item that is not present in any of their containers
- **THEN** the item is still added to the queue, since the picker browses the item registry rather than the player's inventory

2 changes: 2 additions & 0 deletions src/generated/resources/assets/crafttracker/lang/de_de.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"crafttracker.screen.queue_mgr.button.dec.tooltip": "Reduzieren Sie die Menge an hergestellten",
"crafttracker.screen.queue_mgr.button.del.tooltip": "Dieses Element aus der Warteschlange l\u00F6schen",
"crafttracker.screen.queue_mgr.button.inc.tooltip": "Erh\u00F6hen Sie die Menge an hergestellten",
"crafttracker.screen.queue_mgr.picker.search_label": "Suchen:",
"crafttracker.screen.queue_mgr.picker.title": "Gegenstand hinzuf\u00FCgen",
"crafttracker.screen.queue_mgr.title": "Warteschlangenmanager",
"crafttracker.screen.shopping_list.empty_message": "The shopping list is empty.",
"crafttracker.screen.shopping_list.help_message": "To clear the list:",
Expand Down
Loading
Loading