diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..68a16fe --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,227 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via +[GitHub issues](https://github.com/refinedmods/refinedstorage-jei-integration/issues), [Discord](https://discordapp.com/invite/VYzsydb), +or any other method with the owners of this repository before making a change. + +## Quickstart + +These are the most important things to know before contributing (also explained in more detail later in this document): + +- Commit messages must adhere to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). +- Branch names must be formatted correctly. The format is `{category}/GH-{issue number}/{lowercase-description}`. + Category must match a + category [used in our Commitlint config](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional#type-enum). +- We use [Checkstyle](https://checkstyle.sourceforge.io/) in our build workflow to validate coding style. It is + recommended to import the [config/checkstyle/checkstyle.xml](../config/checkstyle/checkstyle.xml) + or [config/intellij-code-style.xml](../config/intellij-code-style.xml) file into your + IDE, so that formatting rules are respected. +- Branches are kept up to date by rebasing, not by merging. +- For non-technical changes, adding a changelog entry is required. + +## Pull requests + +- Keep your pull request (PR) as small as possible, this makes reviewing easier. +- Commits serve a clear purpose and have a fitting commit message. +- Branches are kept up to date by rebasing (updating a branch by merging makes for a confusing Git history). +- PRs are merged by merging the commits on top of the target branch (which is `develop`). +- Remember to add your changes in `CHANGELOG.md`. If your changes are merely technical, it's not necessary to update the + changelog as it's not relevant for users. + +### Commit messages + +Commit messages must adhere to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). We +use [Commitlint](https://commitlint.js.org/) to validate commit messages. + +We use +the [conventional configuration](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) +for Commitlint. + +It is recommended to install +the [Conventional Commit plugin](https://plugins.jetbrains.com/plugin/13389-conventional-commit) to make it +easier to write commit messages. + +### Branch names + +Because we use merge commits when merging a PR, branch names will be part of the history of the repository. That is why +branch names must follow a certain standard. + +The format is `{category}/GH-{issue number}/{lowercase-description}` and a branch name can be maximum 50 characters of +length. + +Category must match a +category [used in our Commitlint config](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional#type-enum). + +Valid examples are: + +- `fix/GH-123/add-branch-linting` +- `docs/GH-123/cleanup` + +## Versioning + +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Changelog + +The changelog is kept in `CHANGELOG.md`. + +Keeping a readable, relevant and user-friendly changelog is essential for our end users +to stay up to date with the project. + +Please refrain from using technical terminology or adding entries for technical changes +that are (generally) not relevant to the end-user. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +### Javadoc + +Javadoc is available after every release on https://refinedmods.com/javadoc/. + +## Gitflow + +This project uses [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). + +## Documentation + +Documentation must be kept up to date when adding or changing functionality. + +### API annotations + +Public APIs must be annotated with an `@API` annotation +from [API Guardian](https://github.com/apiguardian-team/apiguardian). + +## Code style + +We use [Checkstyle](https://checkstyle.sourceforge.io/) in our build workflow to validate coding style. + +It is recommended to import the [config/checkstyle/checkstyle.xml](../config/checkstyle/checkstyle.xml) +or [config/intellij-code-style.xml](../config/intellij-code-style.xml) file into your +IDE, so that formatting rules are respected. + +Moreover, the [CheckStyle-IDEA plugin](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) can be used to check +if there are no style violations. + +## Architecture + +## Testing + +When adding functionality or fixing a bug, it is important to add tests. Tests are important, if not more important, +than the implementation code. + +That means that they need to be first class citizens in the codebase, and must be readable +at all times. + +They ensure that there are no regressions, act as general documentation for the codebase, +and ensure that the project can evolve over time. + +To avoid brittle tests, tests need to validate behavior. A test cannot rely on the internal code structure, so most +mocking should be avoided. + +### Test coverage + +Our [SonarQube quality gate](https://sonarcloud.io/organizations/refinedmods/quality_gates/show/9) requires a minimum +test coverage percentage of 80%. + +### Mutation testing + +We also use [Pitest](https://pitest.org/) mutation testing. + +Our build workflow requires a minimum test coverage percentage of 80% and a minimum mutation +coverage percentage of 90%. + +## Release process + +The release process is automated and follows Gitflow. + +Before running the "Draft release" workflow to start the release process make sure `CHANGELOG.md` contains all the +unreleased changes. + +To determine the version number to be released, the workflow will ask you which release type this is (major, minor, +patch). +The latest version from `CHANGELOG.md` will be used as a base, and that will be incremented +depending on the release type. + +`CHANGELOG.md` will be updated by this workflow, you can review this in the resulting release PR. + +If you merge the release PR, the "Publish release" workflow will automatically publish the release. An additional PR +will be created to merge the changes in `CHANGELOG.md` back into `develop`. + +## Hotfix process + +The hotfix process is semi-automated and follows Gitflow: + +- Create a hotfix branch off `main`. +- Commit your changes on this branch. +- Update `CHANGELOG.md` (with version number and release date) manually on this branch. +- Push the branch and create a PR for it, merging into `main`. + +The "Publish release" workflow will take care of the rest. + +## Workflows + +We have a few GitHub workflows: + +- Build (PRs, pushes to `develop` and `main`) +- Draft release (manual trigger) +- Publish release (merging a PR to `main`) +- Validate changelog (PRs) + - To validate if `CHANGELOG.md` is valid and updated. + - Not every pull request needs a changelog change, so the `skip-changelog` label can be added to the pull request to + ignore this. +- Validate commit messages (PRs) + - Validates whether the commits on a pull request + respect [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). + - We use + the [conventional configuration](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional). +- Validate branch names (PRs) +- Issue for unsupported version (issues) + - Posts a message on a GitHub issue if the issue is about an unsupported version. +- Lock resolved issues and PRs (every night) + +### Build + +The build workflow triggers when a pull request is updated or when a commit is pushed to `develop` or `main`. + +The build workflow takes care of the following: + +- Running a Gradle build, running our tests in the process and generating an aggregated code coverage report for the API + modules. +- Analyzing the code on SonarQube. + > Because of + > [limitations with SonarQube](https://portal.productboard.com/sonarsource/1-sonarcloud/c/50-sonarcloud-analyzes-external-pull-request), + > pull requests originating from a fork aren't analyzed on SonarQube. + +- Code style validation with Checkstyle. +- Mutation and line coverage test with Pitest. +- Uploading the artifacts on the action. + +### Draft release + +The draft release workflow is a manual workflow which will create a release branch from `develop`. + +To determine the version number to be released, it will extract the latest version number from `CHANGELOG.md` and +increment it depending on the release type selected. + +This workflow takes care of the following: + +- Creating the release branch. +- Updating the changelog on this release branch. +- Creating a pull request merging the release branch into `main`. + +### Publish release + +The "publish release" workflow is triggered when a release or hotfix PR is merged to `main`. Usually, this will be the +PR created earlier in the "Draft release" workflow. + +The workflow takes care of the following: + +- Extracting the version number from the release or hotfix branch name that is merged in the PR. +- Extracting the changelog entry for this version number. +- Running a build. +- Publishing on [GitHub packages](https://github.com/refinedmods/refinedstorage-jei-integration/packages) and + CreeperHost Maven. +- Publishing Javadoc on [GitHub pages](https://github.com/refinedmods/javadoc). +- Deploying on [GitHub releases](https://github.com/refinedmods/refinedstorage-jei-integration/releases). +- Announcing the release on Discord and Twitter. +- Creating a PR that merges `main` back into `develop` to get the changes to `CHANGELOG.md` and `build.gradle` + into `develop` from the draft release workflow. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..bc4961c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +patreon: raoulvdberge \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..60e28f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,59 @@ +name: Bug report +description: Found a bug or encountered a crash? Please report it here. +labels: [ bug ] +body: + - type: markdown + attributes: + value: | + Provide a summary of the issue in the title above. + - type: textarea + id: description + attributes: + label: Describe the bug + description: | + Be as detailed as possible. + If applicable, also tell us what you expected to happen instead. + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: How can we reproduce this bug or crash? + description: | + Provide us with steps on how to reproduce this issue. + placeholder: | + 1. + 2. + 3. + validations: + required: true + - type: dropdown + id: minecraft + attributes: + label: What Minecraft version is this happening on? + description: | + If your Minecraft version isn't listed here, it means that it's no longer supported. In that case, don't create an issue. + options: + - Minecraft 1.20.4 + validations: + required: true + - type: input + id: modloader-version + attributes: + label: What NeoForge or Fabric version is this happening on? + validations: + required: true + - type: input + id: version + attributes: + label: What version is this happening on? + description: | + Ensure that you are using the latest version. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..9e5add6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Discord Community Support + url: https://discordapp.com/invite/VYzsydb + about: Please ask and answer questions here. Issues should be used for bugs and feature requests. diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml new file mode 100644 index 0000000..5509c3a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.yml @@ -0,0 +1,23 @@ +name: Enhancement +description: Do you have a suggestion for a new feature or improvement? Let us know. +labels: [ enhancement ] +body: + - type: markdown + attributes: + value: | + Provide a summary of the enhancement in the title above. + + Please follow following guidelines before proposing an enchancement: + 1) Ensure that you are running on the latest version (to ensure that the enhancement does not exist yet). + 2) Ensure that your enhancement hasn't already been posted. Please look in the closed issues as well (for enhancements that have been denied). + + We might close your issue, without explanation, if you do not follow these guidelines. + - type: textarea + id: describe + attributes: + label: Describe your enhancement + description: | + Be as detailed as possible. + Tell us how your idea should work. Why should we consider this? + validations: + required: true diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..e48eaf6 --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,11 @@ +# Support + +If you have a problem and need help, we offer various channels where you can ask for help. + +## I have a question + +Questions can be asked on [Discord](https://discordapp.com/invite/VYzsydb). + +## I have found a bug + +If you have found a bug, please report it on [GitHub issues](https://github.com/refinedmods/refinedstorage-jei-integration/issues). \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..74e8b46 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,14 @@ +name: Build +on: + push: + branches: + - develop + - main + pull_request: + types: [ opened, synchronize, reopened ] +jobs: + build: + uses: refinedmods/refinedarchitect/.github/workflows/build.yml@v0.12.1 + with: + mutation-testing: false + secrets: inherit diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml new file mode 100644 index 0000000..6fad3ac --- /dev/null +++ b/.github/workflows/draft-release.yml @@ -0,0 +1,24 @@ +name: Draft release +on: + workflow_dispatch: + inputs: + release-type: + description: 'Release type' + required: true + default: 'minor' + type: choice + options: + - major + - minor + - patch + version-number-override: + description: 'Version number override' + required: false + type: string +jobs: + draft: + uses: refinedmods/refinedarchitect/.github/workflows/draft-release.yml@v0.12.1 + with: + release-type: ${{ inputs.release-type }} + version-number-override: ${{ inputs.version-number-override }} + secrets: inherit diff --git a/.github/workflows/issue-for-unsupported-version.yml b/.github/workflows/issue-for-unsupported-version.yml new file mode 100644 index 0000000..1664acf --- /dev/null +++ b/.github/workflows/issue-for-unsupported-version.yml @@ -0,0 +1,7 @@ +name: Issue for unsupported version +on: + issues: + types: [ labeled, unlabeled, reopened ] +jobs: + unsupported-labeler: + uses: refinedmods/refinedarchitect/.github/workflows/issue-for-unsupported-version.yml@v0.12.1 \ No newline at end of file diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000..52d0e4d --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,14 @@ +name: Publish release +on: + pull_request: + branches: + - main + types: + - closed +jobs: + publish-release: + uses: refinedmods/refinedarchitect/.github/workflows/publish-release.yml@v0.12.1 + secrets: inherit + with: + project-name: 'Refined Storage - JEI Integration' + mutation-testing: false \ No newline at end of file diff --git a/.github/workflows/resolved-issue-locking.yml b/.github/workflows/resolved-issue-locking.yml new file mode 100644 index 0000000..6023644 --- /dev/null +++ b/.github/workflows/resolved-issue-locking.yml @@ -0,0 +1,7 @@ +name: Lock resolved issues and PRs +on: + schedule: + - cron: '0 0 * * *' +jobs: + lock: + uses: refinedmods/refinedarchitect/.github/workflows/resolved-issue-locking.yml@v0.12.1 \ No newline at end of file diff --git a/.github/workflows/validate-branch-name.yml b/.github/workflows/validate-branch-name.yml new file mode 100644 index 0000000..c862e1c --- /dev/null +++ b/.github/workflows/validate-branch-name.yml @@ -0,0 +1,5 @@ +name: Validate branch name +on: [ pull_request ] +jobs: + validate-branch-name: + uses: refinedmods/refinedarchitect/.github/workflows/validate-branch-name.yml@v0.12.1 \ No newline at end of file diff --git a/.github/workflows/validate-changelog.yml b/.github/workflows/validate-changelog.yml new file mode 100644 index 0000000..8c6b2e8 --- /dev/null +++ b/.github/workflows/validate-changelog.yml @@ -0,0 +1,7 @@ +name: Validate changelog +on: + pull_request: + types: [ opened, synchronize, reopened, ready_for_review, labeled, unlabeled ] +jobs: + validate-changelog: + uses: refinedmods/refinedarchitect/.github/workflows/validate-changelog.yml@v0.12.1 \ No newline at end of file diff --git a/.github/workflows/validate-commit-messages.yml b/.github/workflows/validate-commit-messages.yml new file mode 100644 index 0000000..306fbb8 --- /dev/null +++ b/.github/workflows/validate-commit-messages.yml @@ -0,0 +1,5 @@ +name: Validate commit messages +on: [ pull_request ] +jobs: + validate-commit-messages: + uses: refinedmods/refinedarchitect/.github/workflows/validate-commit-messages.yml@v0.12.1 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..924b02b --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.gradle/ +.nb-gradle/ +.settings/ +build/ +eclipse/ +.classpath +.nb-gradle-properties +.project +*.launch +*.iml +*.ipr +*.iws +.idea/ +out/ +/bin/ +logs/ +.cache/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d0262ca --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres +to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Added + +- Initial release. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e9057d6 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,20 @@ +# The MIT License (MIT) + +Copyright © 2024 Refined Mods + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the “Software”), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2228b35 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# Refined Storage - JEI Integration [![Build Status](https://github.com/refinedmods/refinedstorage-jei-integration/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/refinedmods/refinedstorage-jei-integration/actions/workflows/build.yml) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=refinedmods_refinedstorage-jei-integration&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=refinedmods_refinedstorage-jei-integration) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=refinedmods_refinedstorage-jei-integration&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=refinedmods_refinedstorage-jei-integration) [![Discord](https://img.shields.io/discord/342942776494653441)](https://discordapp.com/invite/VYzsydb) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md) + +## About + +JEI integration for [Refined Storage](https://github.com/refinedmods/refinedstorage2). + +## Links + +- [GitHub](https://github.com/refinedmods/refinedstorage-jei-integration) + - [Releases](https://github.com/refinedmods/refinedstorage-jei-integration/releases) + - [Packages](https://github.com/refinedmods/refinedstorage-jei-integration/packages) + - [Issues](https://github.com/refinedmods/refinedstorage-jei-integration/issues) + - [Refined Mods on GitHub](https://github.com/refinedmods) +- [Discord](https://discordapp.com/invite/VYzsydb) +- [Twitter](https://twitter.com/refinedmods) +- [Mastodon](https://anvil.social/@refinedmods) + +## Building + +Clone the repository and import the Gradle project. + +## Contributing + +See [CONTRIBUTING.md](.github/CONTRIBUTING.md). + +## Support + +See [SUPPORT.md](.github/SUPPORT.md). + +## Changelog + +See [CHANGELOG.md](CHANGELOG.md). diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7f2727d --- /dev/null +++ b/build.gradle @@ -0,0 +1,7 @@ +apply from: "https://raw.githubusercontent.com/refinedmods/refinedarchitect/v${gradle.ext.refinedArchitectVersion}/helper.gradle" + +subprojects { + group = 'com.refinedmods.refinedstorage' +} + +enableSonarQube("refinedmods_refinedstorage-jei-integration") \ No newline at end of file diff --git a/config/checkstyle/checkstyle-imports.xml b/config/checkstyle/checkstyle-imports.xml new file mode 100644 index 0000000..6788c49 --- /dev/null +++ b/config/checkstyle/checkstyle-imports.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/config/checkstyle/checkstyle-suppressions.xml b/config/checkstyle/checkstyle-suppressions.xml new file mode 100644 index 0000000..3d00140 --- /dev/null +++ b/config/checkstyle/checkstyle-suppressions.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000..87191bb --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/intellij-code-style.xml b/config/intellij-code-style.xml new file mode 100644 index 0000000..be27458 --- /dev/null +++ b/config/intellij-code-style.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..c408a30 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +# Gradle +org.gradle.jvmargs=-Xmx1G +refinedstorageVersion=2.0.0-milestone.3.7 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..249e583 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b82aa23 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..a69d9cb --- /dev/null +++ b/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f127cfd --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/refinedstorage-jei-integration-common/build.gradle b/refinedstorage-jei-integration-common/build.gradle new file mode 100644 index 0000000..7905ef1 --- /dev/null +++ b/refinedstorage-jei-integration-common/build.gradle @@ -0,0 +1,27 @@ +archivesBaseName = 'refinedstorage-jei-integration-common' + +repositories { + maven { + name = 'JEI' + url = "https://maven.blamejared.com/" + } + maven { + url = uri("https://maven.pkg.github.com/refinedmods/refinedstorage2") + credentials { + username = "anything" + password = "\u0067hp_oGjcDFCn8jeTzIj4Ke9pLoEVtpnZMP4VQgaX" + } + } +} + +commonProject() + +dependencies { + compileOnly common.jei.api + implementation "com.refinedmods.refinedstorage2:refinedstorage2-platform-common:${refinedstorageVersion}" + implementation "com.refinedmods.refinedstorage2:refinedstorage2-platform-api:${refinedstorageVersion}" + implementation "com.refinedmods.refinedstorage2:refinedstorage2-resource-api:${refinedstorageVersion}" + implementation "com.refinedmods.refinedstorage2:refinedstorage2-grid-api:${refinedstorageVersion}" +} + +enablePublishing() \ No newline at end of file diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ClickableIngredient.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ClickableIngredient.java new file mode 100644 index 0000000..6249589 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ClickableIngredient.java @@ -0,0 +1,25 @@ +package com.refinedmods.refinedstorage.jei.common; + +import mezz.jei.api.ingredients.ITypedIngredient; +import mezz.jei.api.runtime.IClickableIngredient; +import net.minecraft.client.renderer.Rect2i; + +class ClickableIngredient implements IClickableIngredient { + private final ITypedIngredient ingredient; + private final Rect2i area; + + ClickableIngredient(final ITypedIngredient ingredient, final int x, final int y) { + this.ingredient = ingredient; + area = new Rect2i(x, y, 16, 16); + } + + @Override + public ITypedIngredient getTypedIngredient() { + return ingredient; + } + + @Override + public Rect2i getArea() { + return area; + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/Common.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/Common.java new file mode 100644 index 0000000..7914423 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/Common.java @@ -0,0 +1,20 @@ +package com.refinedmods.refinedstorage.jei.common; + +import static java.util.Objects.requireNonNull; + +public final class Common { + public static final String MOD_ID = "refinedstorage_jei_integration"; + + private static Platform platform; + + private Common() { + } + + public static void setPlatform(final Platform platform) { + Common.platform = platform; + } + + public static Platform getPlatform() { + return requireNonNull(platform, "Platform isn't set yet"); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/CraftingGridRecipeTransferHandler.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/CraftingGridRecipeTransferHandler.java new file mode 100644 index 0000000..886224d --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/CraftingGridRecipeTransferHandler.java @@ -0,0 +1,102 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +import com.refinedmods.refinedstorage2.api.resource.list.ResourceList; +import com.refinedmods.refinedstorage2.platform.common.content.Menus; +import com.refinedmods.refinedstorage2.platform.common.grid.CraftingGridContainerMenu; +import com.refinedmods.refinedstorage2.platform.common.support.resource.ItemResource; +import mezz.jei.api.constants.RecipeTypes; +import mezz.jei.api.gui.ingredient.IRecipeSlotView; +import mezz.jei.api.gui.ingredient.IRecipeSlotsView; +import mezz.jei.api.recipe.RecipeIngredientRole; +import mezz.jei.api.recipe.RecipeType; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.RecipeHolder; + +class CraftingGridRecipeTransferHandler implements + IRecipeTransferHandler> { + @Override + public Class getContainerClass() { + return CraftingGridContainerMenu.class; + } + + @Override + public Optional> getMenuType() { + return Optional.of(Menus.INSTANCE.getCraftingGrid()); + } + + @Override + public RecipeType> getRecipeType() { + return RecipeTypes.CRAFTING; + } + + @Override + @Nullable + public IRecipeTransferError transferRecipe(final CraftingGridContainerMenu containerMenu, + final RecipeHolder recipe, + final IRecipeSlotsView recipeSlots, + final Player player, + final boolean maxTransfer, + final boolean doTransfer) { + if (doTransfer) { + doTransfer(recipeSlots, containerMenu); + return null; + } + final ResourceList available = containerMenu.getAvailableListForRecipeTransfer(); + final List missingSlots = findMissingSlots(recipeSlots, available); + return missingSlots.isEmpty() ? null : new MissingItemRecipeTransferError(missingSlots); + } + + private void doTransfer(final IRecipeSlotsView recipeSlots, final CraftingGridContainerMenu containerMenu) { + final List> inputs = getInputs(recipeSlots); + containerMenu.transferRecipe(inputs); + } + + private List findMissingSlots(final IRecipeSlotsView recipeSlots, final ResourceList available) { + return recipeSlots.getSlotViews(RecipeIngredientRole.INPUT).stream().filter(slotView -> { + if (slotView.isEmpty()) { + return false; + } + return !isAvailable(available, slotView); + }).toList(); + } + + private boolean isAvailable(final ResourceList available, final IRecipeSlotView slotView) { + final List possibilities = slotView.getItemStacks().toList(); + for (final ItemStack possibility : possibilities) { + final ItemResource possibilityResource = ItemResource.ofItemStack(possibility); + if (available.remove(possibilityResource, 1).isPresent()) { + return true; + } + } + return false; + } + + private List> getInputs(final IRecipeSlotsView recipeSlots) { + return recipeSlots.getSlotViews(RecipeIngredientRole.INPUT).stream().map(slotView -> { + final List stacks = slotView.getItemStacks().collect(Collectors.toList()); + prioritizeDisplayedStack(slotView, stacks); + return stacks.stream().map(ItemResource::ofItemStack).toList(); + }).toList(); + } + + private void prioritizeDisplayedStack(final IRecipeSlotView slotView, final List stacks) { + slotView.getDisplayedItemStack().ifPresent(displayed -> { + final int index = stacks.indexOf(displayed); + if (index > 0) { + return; + } + stacks.remove(index); + stacks.add(0, displayed); + }); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ExclusionZonesGuiContainerHandler.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ExclusionZonesGuiContainerHandler.java new file mode 100644 index 0000000..112a0da --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ExclusionZonesGuiContainerHandler.java @@ -0,0 +1,14 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.List; + +import com.refinedmods.refinedstorage2.platform.common.support.AbstractBaseScreen; +import mezz.jei.api.gui.handlers.IGuiContainerHandler; +import net.minecraft.client.renderer.Rect2i; + +class ExclusionZonesGuiContainerHandler implements IGuiContainerHandler> { + @Override + public List getGuiExtraAreas(final AbstractBaseScreen screen) { + return screen.getExclusionZones(); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/GhostIngredientHandler.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/GhostIngredientHandler.java new file mode 100644 index 0000000..6b4dcae --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/GhostIngredientHandler.java @@ -0,0 +1,86 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.refinedmods.refinedstorage2.platform.api.recipemod.IngredientConverter; +import com.refinedmods.refinedstorage2.platform.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage2.platform.common.Platform; +import com.refinedmods.refinedstorage2.platform.common.support.AbstractBaseScreen; +import com.refinedmods.refinedstorage2.platform.common.support.containermenu.AbstractResourceContainerMenu; +import com.refinedmods.refinedstorage2.platform.common.support.containermenu.ResourceSlot; +import mezz.jei.api.gui.handlers.IGhostIngredientHandler; +import mezz.jei.api.ingredients.ITypedIngredient; +import net.minecraft.client.renderer.Rect2i; + +@SuppressWarnings("rawtypes") +class GhostIngredientHandler implements IGhostIngredientHandler { + private final IngredientConverter ingredientConverter; + + GhostIngredientHandler(final IngredientConverter ingredientConverter) { + this.ingredientConverter = ingredientConverter; + } + + @Override + public List> getTargetsTyped(final AbstractBaseScreen screen, + final ITypedIngredient ingredient, + final boolean doStart) { + if (screen.getMenu() instanceof AbstractResourceContainerMenu menu) { + return getTargets(screen, ingredient.getIngredient(), menu); + } + return Collections.emptyList(); + } + + private List> getTargets(final AbstractBaseScreen screen, + final I ingredient, + final AbstractResourceContainerMenu menu) { + final List> targets = new ArrayList<>(); + ingredientConverter.convertToResource(ingredient).ifPresent(resource -> { + for (final ResourceSlot slot : menu.getResourceSlots()) { + if (slot.isFilter() && slot.isValid(resource)) { + final Rect2i bounds = getBounds(screen, slot); + targets.add(new TargetImpl<>(bounds, slot.index)); + } + } + }); + return targets; + } + + private Rect2i getBounds(final AbstractBaseScreen screen, final ResourceSlot slot) { + return new Rect2i(screen.getLeftPos() + slot.x, screen.getTopPos() + slot.y, 17, 17); + } + + @Override + public void onComplete() { + // no op + } + + private class TargetImpl implements Target { + private final Rect2i area; + private final int slotIndex; + + TargetImpl(final Rect2i area, final int slotIndex) { + this.area = area; + this.slotIndex = slotIndex; + } + + @Override + public Rect2i getArea() { + return area; + } + + @Override + public void accept(final I ingredient) { + ingredientConverter.convertToResource(ingredient).ifPresent(this::accept); + } + + private void accept(final PlatformResourceKey resource) { + Platform.INSTANCE.getClientToServerCommunications().sendResourceFilterSlotChange( + resource, + slotIndex + ); + } + } +} + diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/GridGuiContainerHandler.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/GridGuiContainerHandler.java new file mode 100644 index 0000000..b4ca9d6 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/GridGuiContainerHandler.java @@ -0,0 +1,52 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.Optional; + +import com.refinedmods.refinedstorage2.platform.api.grid.view.PlatformGridResource; +import com.refinedmods.refinedstorage2.platform.api.recipemod.IngredientConverter; +import com.refinedmods.refinedstorage2.platform.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage2.platform.common.grid.screen.AbstractGridScreen; +import mezz.jei.api.gui.handlers.IGuiContainerHandler; +import mezz.jei.api.ingredients.IIngredientHelper; +import mezz.jei.api.ingredients.ITypedIngredient; +import mezz.jei.api.runtime.IClickableIngredient; +import mezz.jei.api.runtime.IIngredientManager; + +class GridGuiContainerHandler implements IGuiContainerHandler> { + private final IngredientConverter converter; + private final IIngredientManager ingredientManager; + + GridGuiContainerHandler(final IngredientConverter converter, final IIngredientManager ingredientManager) { + this.converter = converter; + this.ingredientManager = ingredientManager; + } + + @Override + public Optional> getClickableIngredientUnderMouse( + final AbstractGridScreen screen, + final double mouseX, + final double mouseY + ) { + final PlatformGridResource resource = screen.getCurrentGridResource(); + if (resource == null) { + return Optional.empty(); + } + final PlatformResourceKey underlyingResource = resource.getUnderlyingResource(); + if (underlyingResource == null) { + return Optional.empty(); + } + return converter.convertToIngredient(underlyingResource).flatMap( + ingredient -> convertToClickableIngredient(mouseX, mouseY, ingredient) + ); + } + + private Optional> convertToClickableIngredient(final double x, + final double y, + final Object ingredient) { + final IIngredientHelper helper = ingredientManager.getIngredientHelper(ingredient); + final Optional> maybeTypedIngredient = + ingredientManager.createTypedIngredient(helper.getIngredientType(), ingredient); + return maybeTypedIngredient + .map(typedIngredient -> new ClickableIngredient<>(typedIngredient, (int) x, (int) y)); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/IngredientConvertImpl.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/IngredientConvertImpl.java new file mode 100644 index 0000000..04b5e5c --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/IngredientConvertImpl.java @@ -0,0 +1,46 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.Optional; + +import com.refinedmods.refinedstorage2.platform.api.recipemod.IngredientConverter; +import com.refinedmods.refinedstorage2.platform.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage2.platform.common.Platform; +import com.refinedmods.refinedstorage2.platform.common.support.resource.FluidResource; +import com.refinedmods.refinedstorage2.platform.common.support.resource.ItemResource; +import mezz.jei.api.helpers.IPlatformFluidHelper; +import net.minecraft.world.item.ItemStack; + +class IngredientConvertImpl implements IngredientConverter { + private final IPlatformFluidHelper fluidHelper; + + IngredientConvertImpl(final IPlatformFluidHelper fluidHelper) { + this.fluidHelper = fluidHelper; + } + + @Override + public Optional convertToResource(final Object ingredient) { + final var fluid = Common.getPlatform().convertJeiIngredientToFluid(ingredient); + if (fluid.isPresent()) { + return fluid.map(f -> f); + } + if (ingredient instanceof ItemStack itemStack) { + return Optional.of(ItemResource.ofItemStack(itemStack)); + } + return Optional.empty(); + } + + @Override + public Optional convertToIngredient(final PlatformResourceKey resource) { + if (resource instanceof ItemResource itemResource) { + return Optional.of(itemResource.toItemStack()); + } + if (resource instanceof FluidResource fluidResource) { + return Optional.of(fluidHelper.create( + fluidResource.fluid(), + fluidHelper.bucketVolume(), + fluidResource.tag() + )); + } + return Optional.empty(); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/JeiGridSynchronizer.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/JeiGridSynchronizer.java new file mode 100644 index 0000000..6f36939 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/JeiGridSynchronizer.java @@ -0,0 +1,58 @@ +package com.refinedmods.refinedstorage.jei.common; + +import javax.annotation.Nullable; + +import com.refinedmods.refinedstorage2.platform.common.grid.AbstractGridSynchronizer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; + +import static com.refinedmods.refinedstorage.jei.common.Common.MOD_ID; + +class JeiGridSynchronizer extends AbstractGridSynchronizer { + private static final MutableComponent TITLE = Component.translatable( + "gui.%s.grid.synchronizer.jei".formatted(MOD_ID) + ); + private static final MutableComponent TITLE_TWO_WAY = Component.translatable( + "gui.%s.grid.synchronizer.jei.two_way".formatted(MOD_ID) + ); + private static final Component HELP = Component.translatable( + "gui.%s.grid.synchronizer.jei.help".formatted(MOD_ID) + ); + private static final Component HELP_TWO_WAY = Component.translatable( + "gui.%s.grid.synchronizer.jei.two_way.help".formatted(MOD_ID) + ); + + private final JeiProxy jeiProxy; + private final boolean twoWay; + + JeiGridSynchronizer(final JeiProxy jeiProxy, final boolean twoWay) { + this.jeiProxy = jeiProxy; + this.twoWay = twoWay; + } + + @Override + public MutableComponent getTitle() { + return twoWay ? TITLE_TWO_WAY : TITLE; + } + + @Override + public Component getHelpText() { + return twoWay ? HELP_TWO_WAY : HELP; + } + + @Override + public void synchronizeFromGrid(final String text) { + jeiProxy.setSearchFieldText(text); + } + + @Override + @Nullable + public String getTextToSynchronizeToGrid() { + return twoWay ? jeiProxy.getSearchFieldText() : null; + } + + @Override + public int getXTexture() { + return twoWay ? 32 : 48; + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/JeiProxy.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/JeiProxy.java new file mode 100644 index 0000000..88ff332 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/JeiProxy.java @@ -0,0 +1,20 @@ +package com.refinedmods.refinedstorage.jei.common; + +import mezz.jei.api.runtime.IJeiRuntime; + +public class JeiProxy { + public String getSearchFieldText() { + final IJeiRuntime runtime = RefinedStorageJeiModPlugin.getRuntime(); + if (runtime == null) { + return ""; + } + return runtime.getIngredientFilter().getFilterText(); + } + + public void setSearchFieldText(final String text) { + final IJeiRuntime runtime = RefinedStorageJeiModPlugin.getRuntime(); + if (runtime != null) { + runtime.getIngredientFilter().setFilterText(text); + } + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/MissingItemRecipeTransferError.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/MissingItemRecipeTransferError.java new file mode 100644 index 0000000..b409edd --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/MissingItemRecipeTransferError.java @@ -0,0 +1,58 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.awt.Color; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import mezz.jei.api.gui.ingredient.IRecipeSlotView; +import mezz.jei.api.gui.ingredient.IRecipeSlotsView; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; + +class MissingItemRecipeTransferError implements IRecipeTransferError { + private static final Color COLOR = new Color(1.0f, 0.0f, 0.0f, 0.4f); + private static final List MISSING_MESSAGE = List.of( + Component.translatable("jei.tooltip.transfer").getVisualOrderText(), + Component.translatable("jei.tooltip.error.recipe.transfer.missing").withStyle(ChatFormatting.RED) + .getVisualOrderText() + ); + + private final List slotsWithMissingItems; + + MissingItemRecipeTransferError(final List slotsWithMissingItems) { + this.slotsWithMissingItems = slotsWithMissingItems; + } + + @Override + public Type getType() { + return Type.COSMETIC; + } + + @Override + public int getButtonHighlightColor() { + return COLOR.getRGB(); + } + + @Override + public void showError(final GuiGraphics graphics, + final int mouseX, + final int mouseY, + final IRecipeSlotsView recipeSlotsView, + final int recipeX, + final int recipeY) { + final PoseStack poseStack = graphics.pose(); + poseStack.pushPose(); + poseStack.translate(recipeX, recipeY, 0); + slotsWithMissingItems.forEach(slot -> slot.drawHighlight(graphics, COLOR.getRGB())); + poseStack.popPose(); + final Screen screen = Minecraft.getInstance().screen; + if (screen != null) { + graphics.renderTooltip(Minecraft.getInstance().font, MISSING_MESSAGE, mouseX, mouseY); + } + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/Platform.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/Platform.java new file mode 100644 index 0000000..be2f7f7 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/Platform.java @@ -0,0 +1,9 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.Optional; + +import com.refinedmods.refinedstorage2.platform.common.support.resource.FluidResource; + +public interface Platform { + Optional convertJeiIngredientToFluid(Object ingredient); +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/RefinedStorageJeiModPlugin.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/RefinedStorageJeiModPlugin.java new file mode 100644 index 0000000..aeee06e --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/RefinedStorageJeiModPlugin.java @@ -0,0 +1,89 @@ +package com.refinedmods.refinedstorage.jei.common; + +import javax.annotation.Nullable; + +import com.refinedmods.refinedstorage2.platform.api.PlatformApi; +import com.refinedmods.refinedstorage2.platform.api.recipemod.IngredientConverter; +import com.refinedmods.refinedstorage2.platform.common.grid.screen.AbstractGridScreen; +import com.refinedmods.refinedstorage2.platform.common.support.AbstractBaseScreen; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.RecipeTypes; +import mezz.jei.api.helpers.IPlatformFluidHelper; +import mezz.jei.api.registration.IGuiHandlerRegistration; +import mezz.jei.api.registration.IRecipeTransferRegistration; +import mezz.jei.api.runtime.IJeiRuntime; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@JeiPlugin +public class RefinedStorageJeiModPlugin implements IModPlugin { + private static final ResourceLocation ID = new ResourceLocation(Common.MOD_ID, "plugin"); + private static final Logger LOGGER = LoggerFactory.getLogger(RefinedStorageJeiModPlugin.class); + @Nullable + private static IJeiRuntime runtime; + + @Override + public ResourceLocation getPluginUid() { + return ID; + } + + @Override + public void registerRecipeTransferHandlers(final IRecipeTransferRegistration registration) { + registration.addRecipeTransferHandler(new CraftingGridRecipeTransferHandler(), RecipeTypes.CRAFTING); + } + + @Override + public void onRuntimeAvailable(final IJeiRuntime newRuntime) { + if (runtime == null) { + initializePlatform(newRuntime.getJeiHelpers().getPlatformFluidHelper()); + } + RefinedStorageJeiModPlugin.runtime = newRuntime; + } + + @Override + public void registerGuiHandlers(final IGuiHandlerRegistration registration) { + final IngredientConverter converter = PlatformApi.INSTANCE.getIngredientConverter(); + registration.addGenericGuiContainerHandler( + AbstractBaseScreen.class, + new ResourceGuiContainerHandler(converter, registration.getJeiHelpers().getIngredientManager()) + ); + registration.addGenericGuiContainerHandler( + AbstractGridScreen.class, + new GridGuiContainerHandler(converter, registration.getJeiHelpers().getIngredientManager()) + ); + registration.addGenericGuiContainerHandler( + AbstractBaseScreen.class, + new ExclusionZonesGuiContainerHandler() + ); + registration.addGhostIngredientHandler(AbstractBaseScreen.class, new GhostIngredientHandler(converter)); + } + + @Nullable + public static IJeiRuntime getRuntime() { + return runtime; + } + + private void initializePlatform(final IPlatformFluidHelper fluidHelper) { + LOGGER.debug("Enabling JEI integration"); + registerIngredientConverters(fluidHelper); + registerGridSynchronizers(); + } + + private void registerGridSynchronizers() { + final JeiProxy jeiProxy = new JeiProxy(); + PlatformApi.INSTANCE.getGridSynchronizerRegistry().register( + new ResourceLocation(Common.MOD_ID, "jei"), + new JeiGridSynchronizer(jeiProxy, false) + ); + PlatformApi.INSTANCE.getGridSynchronizerRegistry().register( + new ResourceLocation(Common.MOD_ID, "jei_two_way"), + new JeiGridSynchronizer(jeiProxy, true) + ); + } + + private void registerIngredientConverters(final IPlatformFluidHelper fluidHelper) { + PlatformApi.INSTANCE.registerIngredientConverter(new IngredientConvertImpl(fluidHelper)); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ResourceGuiContainerHandler.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ResourceGuiContainerHandler.java new file mode 100644 index 0000000..4495c66 --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/ResourceGuiContainerHandler.java @@ -0,0 +1,48 @@ +package com.refinedmods.refinedstorage.jei.common; + +import java.util.Optional; +import javax.annotation.Nullable; + +import com.refinedmods.refinedstorage2.platform.api.recipemod.IngredientConverter; +import com.refinedmods.refinedstorage2.platform.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage2.platform.common.support.AbstractBaseScreen; +import mezz.jei.api.gui.handlers.IGuiContainerHandler; +import mezz.jei.api.ingredients.IIngredientHelper; +import mezz.jei.api.ingredients.ITypedIngredient; +import mezz.jei.api.runtime.IClickableIngredient; +import mezz.jei.api.runtime.IIngredientManager; + +class ResourceGuiContainerHandler implements IGuiContainerHandler> { + private final IngredientConverter converter; + private final IIngredientManager ingredientManager; + + ResourceGuiContainerHandler(final IngredientConverter converter, final IIngredientManager ingredientManager) { + this.converter = converter; + this.ingredientManager = ingredientManager; + } + + @Override + public Optional> getClickableIngredientUnderMouse( + final AbstractBaseScreen baseScreen, + final double mouseX, + final double mouseY + ) { + return convertToIngredient(baseScreen.getHoveredResource()).flatMap(this::convertToClickableIngredient); + } + + public Optional convertToIngredient(@Nullable final PlatformResourceKey resource) { + if (resource == null) { + return Optional.empty(); + } + return converter.convertToIngredient(resource); + } + + private Optional> convertToClickableIngredient(final Object ingredient) { + final IIngredientHelper helper = ingredientManager.getIngredientHelper(ingredient); + final Optional> maybeTypedIngredient = ingredientManager.createTypedIngredient( + helper.getIngredientType(), + ingredient + ); + return maybeTypedIngredient.map(typedIngredient -> new ClickableIngredient<>(typedIngredient, 16, 16)); + } +} diff --git a/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/package-info.java b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/package-info.java new file mode 100644 index 0000000..2d8e30a --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/java/com/refinedmods/refinedstorage/jei/common/package-info.java @@ -0,0 +1,4 @@ +@ParametersAreNonnullByDefault +package com.refinedmods.refinedstorage.jei.common; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/refinedstorage-jei-integration-common/src/main/resources/assets/refinedstorage_jei_integration/lang/en_us.json b/refinedstorage-jei-integration-common/src/main/resources/assets/refinedstorage_jei_integration/lang/en_us.json new file mode 100644 index 0000000..2f3961a --- /dev/null +++ b/refinedstorage-jei-integration-common/src/main/resources/assets/refinedstorage_jei_integration/lang/en_us.json @@ -0,0 +1,6 @@ +{ + "gui.refinedstorage_jei_integration.grid.synchronizer.jei": "JEI", + "gui.refinedstorage_jei_integration.grid.synchronizer.jei.help": "Sync the search box text to the JEI filter.", + "gui.refinedstorage_jei_integration.grid.synchronizer.jei.two_way": "JEI two-way", + "gui.refinedstorage_jei_integration.grid.synchronizer.jei.two_way.help": "Sync the search box text to the JEI filter, and the JEI filter to the search box text." +} \ No newline at end of file diff --git a/refinedstorage-jei-integration-fabric/.gitignore b/refinedstorage-jei-integration-fabric/.gitignore new file mode 100644 index 0000000..737e26b --- /dev/null +++ b/refinedstorage-jei-integration-fabric/.gitignore @@ -0,0 +1 @@ +run/ \ No newline at end of file diff --git a/refinedstorage-jei-integration-fabric/build.gradle b/refinedstorage-jei-integration-fabric/build.gradle new file mode 100644 index 0000000..15efb1c --- /dev/null +++ b/refinedstorage-jei-integration-fabric/build.gradle @@ -0,0 +1,49 @@ +archivesBaseName = 'refinedstorage-jei-integration-fabric' + +fabricProject("refinedstorage_jei_integration", project(":refinedstorage-jei-integration-common")) + +repositories { + maven { + name = 'JEI' + url = "https://maven.blamejared.com/" + } + maven { + url = uri("https://maven.pkg.github.com/refinedmods/refinedstorage2") + credentials { + username = "anything" + password = "\u0067hp_oGjcDFCn8jeTzIj4Ke9pLoEVtpnZMP4VQgaX" + } + } + maven { + name = 'ModMenu' + url 'https://maven.terraformersmc.com/' + } + maven { + name = 'Cloth Config, REI' + url 'https://maven.shedaniel.me/' + } + maven { + name = 'wthit' + url "https://maven.bai.lol" + } + maven { + name = 'NoIndium' + url = 'https://maven.cafeteria.dev/releases/' + } + maven { + name = "Trinkets" + url = 'https://maven.ladysnake.org/releases' + } +} + +dependencies { + modImplementation "com.refinedmods.refinedstorage2:refinedstorage2-platform-fabric:${refinedstorageVersion}" + implementation "com.refinedmods.refinedstorage2:refinedstorage2-platform-api:${refinedstorageVersion}" + implementation "com.refinedmods.refinedstorage2:refinedstorage2-resource-api:${refinedstorageVersion}" + implementation "com.refinedmods.refinedstorage2:refinedstorage2-grid-api:${refinedstorageVersion}" + modCompileOnly common.jei.api + modCompileOnly fabric.jei.api + modRuntimeOnly fabric.jei.impl +} + +enablePublishing() \ No newline at end of file diff --git a/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/FabricPlatform.java b/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/FabricPlatform.java new file mode 100644 index 0000000..ab964cb --- /dev/null +++ b/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/FabricPlatform.java @@ -0,0 +1,21 @@ +package com.refinedmods.refinedstorage.jei.fabric; + +import com.refinedmods.refinedstorage.jei.common.Platform; + +import java.util.Optional; + +import com.refinedmods.refinedstorage2.platform.common.support.resource.FluidResource; +import mezz.jei.api.fabric.ingredients.fluids.IJeiFluidIngredient; + +public class FabricPlatform implements Platform { + @Override + public Optional convertJeiIngredientToFluid(Object ingredient) { + if (ingredient instanceof IJeiFluidIngredient fluidIngredient) { + return Optional.of(new FluidResource( + fluidIngredient.getFluid(), + fluidIngredient.getTag().orElse(null) + )); + } + return Optional.empty(); + } +} diff --git a/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/ModInitializerImpl.java b/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/ModInitializerImpl.java new file mode 100644 index 0000000..f2b627c --- /dev/null +++ b/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/ModInitializerImpl.java @@ -0,0 +1,12 @@ +package com.refinedmods.refinedstorage.jei.fabric; + +import com.refinedmods.refinedstorage.jei.common.Common; + +import net.fabricmc.api.ModInitializer; + +public class ModInitializerImpl implements ModInitializer { + @Override + public void onInitialize() { + Common.setPlatform(new FabricPlatform()); + } +} diff --git a/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/package-info.java b/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/package-info.java new file mode 100644 index 0000000..0b279a5 --- /dev/null +++ b/refinedstorage-jei-integration-fabric/src/main/java/com/refinedmods/refinedstorage/jei/fabric/package-info.java @@ -0,0 +1,4 @@ +@ParametersAreNonnullByDefault +package com.refinedmods.refinedstorage.jei.fabric; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/refinedstorage-jei-integration-fabric/src/main/resources/fabric.mod.json b/refinedstorage-jei-integration-fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..2cb0937 --- /dev/null +++ b/refinedstorage-jei-integration-fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,39 @@ +{ + "schemaVersion": 1, + "id": "refinedstorage_jei_integration", + "version": "${version}", + "name": "Refined Storage - JEI Integration", + "description": "JEI integration for Refined Storage.", + "authors": [ + "Refined Mods" + ], + "contact": { + "sources": "https://github.com/refinedmods/refinedstorage-jei-integration", + "issues": "https://github.com/refinedmods/refinedstorage-jei-integration/issues" + }, + "license": "MIT", + "environment": "*", + "entrypoints": { + "main": [ + "com.refinedmods.refinedstorage.jei.fabric.ModInitializerImpl" + ], + "jei_mod_plugin": [ + "com.refinedmods.refinedstorage.jei.common.RefinedStorageJeiModPlugin" + ] + }, + "custom": { + "modmenu": { + "links": { + "modmenu.discord": "https://discordapp.com/invite/VYzsydb" + }, + "parent": "refinedstorage2" + } + }, + "depends": { + "fabricloader": ">=0.14.6", + "fabric-api": "*", + "minecraft": "~1.20.4", + "jei": ">=17", + "java": ">=17" + } +} diff --git a/refinedstorage-jei-integration-forge/.gitignore b/refinedstorage-jei-integration-forge/.gitignore new file mode 100644 index 0000000..643cb18 --- /dev/null +++ b/refinedstorage-jei-integration-forge/.gitignore @@ -0,0 +1 @@ +runs/ \ No newline at end of file diff --git a/refinedstorage-jei-integration-forge/build.gradle b/refinedstorage-jei-integration-forge/build.gradle new file mode 100644 index 0000000..25f1e9c --- /dev/null +++ b/refinedstorage-jei-integration-forge/build.gradle @@ -0,0 +1,29 @@ +archivesBaseName = 'refinedstorage-jei-integration-forge' + +forgeProject("refinedstorage_jei_integration", project(":refinedstorage-jei-integration-common")) + +repositories { + maven { + name = 'JEI' + url = "https://maven.blamejared.com/" + } + maven { + url = uri("https://maven.pkg.github.com/refinedmods/refinedstorage2") + credentials { + username = "anything" + password = "\u0067hp_oGjcDFCn8jeTzIj4Ke9pLoEVtpnZMP4VQgaX" + } + } +} + +dependencies { + implementation("com.refinedmods.refinedstorage2:refinedstorage2-platform-forge:${refinedstorageVersion}") { + transitive = false + } + + compileOnly common.jei.api + compileOnly forge.jei.api + runtimeOnly forge.jei.impl +} + +enablePublishing() \ No newline at end of file diff --git a/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/ForgePlatform.java b/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/ForgePlatform.java new file mode 100644 index 0000000..6b8031b --- /dev/null +++ b/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/ForgePlatform.java @@ -0,0 +1,20 @@ +package com.refinedmods.refinedstorage.jei.forge; + +import com.refinedmods.refinedstorage.jei.common.Platform; + +import java.util.Optional; + +import com.refinedmods.refinedstorage2.platform.common.support.resource.FluidResource; +import net.neoforged.neoforge.fluids.FluidStack; + +import static com.refinedmods.refinedstorage2.platform.forge.support.resource.VariantUtil.ofFluidStack; + +public class ForgePlatform implements Platform { + @Override + public Optional convertJeiIngredientToFluid(Object ingredient) { + if (ingredient instanceof FluidStack fluidStack) { + return Optional.of(ofFluidStack(fluidStack)); + } + return Optional.empty(); + } +} diff --git a/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/ModInitializer.java b/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/ModInitializer.java new file mode 100644 index 0000000..75ffe8f --- /dev/null +++ b/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/ModInitializer.java @@ -0,0 +1,22 @@ +package com.refinedmods.refinedstorage.jei.forge; + +import com.refinedmods.refinedstorage.jei.common.Common; + +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.registries.RegisterEvent; + +@Mod(Common.MOD_ID) +public class ModInitializer { + public ModInitializer(final IEventBus eventBus) { + // no op + } + + @SubscribeEvent + public void onRegister(final RegisterEvent e) { + Common.setPlatform(new ForgePlatform()); + } +} diff --git a/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/package-info.java b/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/package-info.java new file mode 100644 index 0000000..4102778 --- /dev/null +++ b/refinedstorage-jei-integration-forge/src/main/java/com/refinedmods/refinedstorage/jei/forge/package-info.java @@ -0,0 +1,4 @@ +@ParametersAreNonnullByDefault +package com.refinedmods.refinedstorage.jei.forge; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/refinedstorage-jei-integration-forge/src/main/resources/META-INF/mods.toml b/refinedstorage-jei-integration-forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..0eff57c --- /dev/null +++ b/refinedstorage-jei-integration-forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,23 @@ +modLoader = "javafml" +loaderVersion = "[2,)" +issueTrackerURL = "https://github.com/refinedmods/refinedstorage-jei-integration" +license = "MIT" +[[mods]] +modId = "refinedstorage_jei_integration" +version = "${version}" +displayName = "Refined Storage - JEI Integration" +displayURL = "https://github.com/refinedmods/refinedstorage-jei-integration" +authors = "Refined Mods" +description = ''' +JEI integration for Refined Storage. +''' +[[dependencies.refinedstorage_jei_integration]] +modId = "refinedstorage2" +type = "required" +versionRange = "2.0.0-milestone.3.6" +side = "BOTH" +[[dependencies.refinedstorage_jei_integration]] +modId = "jei" +type = "required" +versionRange = "[17,)" +side = "BOTH" diff --git a/refinedstorage-jei-integration-forge/src/main/resources/pack.mcmeta b/refinedstorage-jei-integration-forge/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..1969c21 --- /dev/null +++ b/refinedstorage-jei-integration-forge/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": { + "text": "Refined Storage - JEI Integration resources" + }, + "pack_format": 18 + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..1ac7431 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,29 @@ +gradle.ext.refinedArchitectVersion = "0.12.1" + +dependencyResolutionManagement { + repositories { + maven { + url = "https://maven.pkg.github.com/refinedmods/refinedarchitect" + credentials { + username = "anything" + password = "\u0067hp_oGjcDFCn8jeTzIj4Ke9pLoEVtpnZMP4VQgaX" + } + } + } + versionCatalogs { + create("common") { + from("com.refinedmods.refinedarchitect:refinedarchitect-catalog-platform-common:${gradle.ext.refinedArchitectVersion}") + } + create("fabric") { + from("com.refinedmods.refinedarchitect:refinedarchitect-catalog-platform-fabric:${gradle.ext.refinedArchitectVersion}") + } + create("forge") { + from("com.refinedmods.refinedarchitect:refinedarchitect-catalog-platform-forge:${gradle.ext.refinedArchitectVersion}") + } + } +} + +rootProject.name = 'refinedstorage-jei-integration' +include 'refinedstorage-jei-integration-common' +include 'refinedstorage-jei-integration-forge' +include 'refinedstorage-jei-integration-fabric'