Merge remote-tracking branch 'architectury/1.16' into 1.17

Signed-off-by: shedaniel <daniel@shedaniel.me>

# Conflicts:
#	.github/workflows/publish.yml
#	.github/workflows/snapshot.yml
#	build.gradle
#	common/src/main/resources/architectury-common.mixins.json
#	fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinLevelChunk.java
#	fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java
#	fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinServerLevel.java
#	fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMouseHandler.java
#	fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinScreen.java
#	forge/gradle.properties
#	gradle.properties
#	gradle/wrapper/gradle-wrapper.properties
#	testmod-fabric/build.gradle
#	testmod-forge/gradle.properties
This commit is contained in:
shedaniel
2021-05-19 22:25:49 +08:00
98 changed files with 1966 additions and 394 deletions

File diff suppressed because it is too large Load Diff

3
.github/FUNDING.yml vendored
View File

@@ -1 +1,2 @@
patreon: shedaniel
patreon: shedaniel
github: [ shedaniel, MaxNeedsSnacks ]

137
.github/workflows/pr.yml vendored Normal file
View File

@@ -0,0 +1,137 @@
name: Build PR snapshot
on:
pull_request:
paths:
- '**.gradle'
- '**.properties'
- '**/src/**'
types: [ opened, synchronize, reopened ]
jobs:
validate-gradle:
name: "Validate Gradle wrapper"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: gradle/wrapper-validation-action@v1
license:
name: "Verify License integrity"
runs-on: ubuntu-20.04
if: |
!contains(github.event.head_commit.message, '[ci skip]')
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: 8
distribution: 'adopt'
- name: Cache Gradle wrapper
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: gradle-wrapper-${{ runner.os }}-${{ hashFiles('gradle/wrapper/**/*') }}
restore-keys: gradle-wrapper-${{ runner.os }}-
- name: Cache packages
id: cache-packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: gradle-packages-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-packages-${{ runner.os }}-
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Verify license using Licenser
run: |
./gradlew licenseCheck
# Remove some potentially problematic files from the Gradle cache,
# so that GitHub Actions doesn't cache them.
- name: Cleanup Gradle Cache
if: steps.cache-packages.outputs.cache-hit != 'true'
run: |
rm -f $HOME/.gradle/caches/*/*.lock
rm -rf $HOME/.gradle/caches/*/plugin-resolution/
rm -rf $HOME/.gradle/caches/*/scripts/
rm -rf $HOME/.gradle/caches/*/scripts-remapped/
rm -rf $HOME/.gradle/caches/*/fileHashes/
rm -f $HOME/.gradle/caches/journal-1/file-access.bin
build:
name: "Build"
strategy:
matrix:
java: [ 8, 15 ] # Build on Java 8 (version shipped with MC 1.16) and Java 15 (iirc the latest version supported by both loaders on 1.16)
runs-on: ubuntu-20.04
if: |
!contains(github.event.head_commit.message, '[ci skip]')
steps:
- uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: 'adopt'
- name: Cache Gradle wrapper
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: gradle-wrapper-${{ runner.os }}-${{ hashFiles('gradle/wrapper/**/*') }}
restore-keys: gradle-wrapper-${{ runner.os }}-
- name: Cache packages
id: cache-packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: gradle-packages-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-packages-${{ runner.os }}-
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Build with Gradle
run: |
./gradlew build --stacktrace --no-daemon
# Remove some potentially problematic files from the Gradle cache,
# so that GitHub Actions doesn't cache them.
- name: Cleanup Gradle Cache
if: steps.cache-packages.outputs.cache-hit != 'true'
run: |
rm -f $HOME/.gradle/caches/*/*.lock
rm -rf $HOME/.gradle/caches/*/plugin-resolution/
rm -rf $HOME/.gradle/caches/*/scripts/
rm -rf $HOME/.gradle/caches/*/scripts-remapped/
rm -rf $HOME/.gradle/caches/*/fileHashes/
rm -f $HOME/.gradle/caches/journal-1/file-access.bin
- name: Setting mod version
if: ${{ matrix.java == '8' }} # Only upload Java 8 artifacts for MC 1.16
run: |
cat $GITHUB_WORKSPACE/gradle.properties | grep ^archives_base_name= >> $GITHUB_ENV
cat $GITHUB_WORKSPACE/gradle.properties | grep ^minecraft_version= >> $GITHUB_ENV
cat $GITHUB_WORKSPACE/gradle.properties | grep ^base_version= >> $GITHUB_ENV
- name: Create package name
if: ${{ matrix.java == '8' }} # Only upload Java 8 artifacts for MC 1.16
run: echo "package_name=[$minecraft_version] $archives_base_name-$base_version.${{ github.run_number }}" >> $GITHUB_ENV
- uses: actions/upload-artifact@v2
if: ${{ matrix.java == '8' }} # Only upload Java 8 artifacts for MC 1.16
with:
name: ${{ env.package_name }}
path: |
**/build/libs/
!build/libs/
!**/*-dev.jar
!**/*-shadow.jar
!**/*-transformProduction*.jar
!**/testmod*/

View File

@@ -1,28 +0,0 @@
name: Java CI
on:
push:
paths:
- '**.gradle'
- '**.properties'
- '**/src/**'
branches:
- "1.16"
- "1.17"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up JDK 16
uses: actions/setup-java@v1
with:
java-version: 16
- name: Upload to Maven
run: ./gradlew publish curseforgePublish --stacktrace
if: |
!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.pull_request.title, '[ci skip]')
env:
MAVEN_PASS: ${{ secrets.MAVEN_PASS }}
curse_api_key: ${{ secrets.CURSE_API_KEY }}

202
.github/workflows/push.yml vendored Normal file
View File

@@ -0,0 +1,202 @@
name: Build and Release
on:
push:
paths:
- '**.gradle'
- '**.properties'
- '**/src/**'
branches:
- "1.16"
- "1.17"
workflow_dispatch:
inputs:
norelease:
description: 'Do not publish'
required: true
default: 'false'
jobs:
validate-gradle:
name: "Validate Gradle wrapper"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: gradle/wrapper-validation-action@v1
license:
name: "Verify License integrity"
runs-on: ubuntu-20.04
if: |
!contains(github.event.head_commit.message, '[ci skip]')
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: 8
distribution: 'adopt'
- name: Cache Gradle wrapper
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: gradle-wrapper-${{ runner.os }}-${{ hashFiles('gradle/wrapper/**/*') }}
restore-keys: gradle-wrapper-${{ runner.os }}-
- name: Cache packages
id: cache-packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: gradle-packages-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-packages-${{ runner.os }}-
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Verify license using Licenser
run: |
./gradlew licenseCheck
# Remove some potentially problematic files from the Gradle cache,
# so that GitHub Actions doesn't cache them.
- name: Cleanup Gradle Cache
if: steps.cache-packages.outputs.cache-hit != 'true'
run: |
rm -f $HOME/.gradle/caches/*/*.lock
rm -rf $HOME/.gradle/caches/*/plugin-resolution/
rm -rf $HOME/.gradle/caches/*/scripts/
rm -rf $HOME/.gradle/caches/*/scripts-remapped/
rm -rf $HOME/.gradle/caches/*/fileHashes/
rm -f $HOME/.gradle/caches/journal-1/file-access.bin
build:
name: "Build"
strategy:
matrix:
java: [ 8, 15 ] # Build on Java 8 (version shipped with MC 1.16) and Java 15 (iirc the latest version supported by both loaders on 1.16)
runs-on: ubuntu-20.04
if: |
!contains(github.event.head_commit.message, '[ci skip]')
steps:
- uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: 'adopt'
- name: Cache Gradle wrapper
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: gradle-wrapper-${{ runner.os }}-${{ hashFiles('gradle/wrapper/**/*') }}
restore-keys: gradle-wrapper-${{ runner.os }}-
- name: Cache packages
id: cache-packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: gradle-packages-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-packages-${{ runner.os }}-
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Build with Gradle
run: |
./gradlew build --stacktrace --no-daemon
# Remove some potentially problematic files from the Gradle cache,
# so that GitHub Actions doesn't cache them.
- name: Cleanup Gradle Cache
if: steps.cache-packages.outputs.cache-hit != 'true'
run: |
rm -f $HOME/.gradle/caches/*/*.lock
rm -rf $HOME/.gradle/caches/*/plugin-resolution/
rm -rf $HOME/.gradle/caches/*/scripts/
rm -rf $HOME/.gradle/caches/*/scripts-remapped/
rm -rf $HOME/.gradle/caches/*/fileHashes/
rm -f $HOME/.gradle/caches/journal-1/file-access.bin
- name: Setting mod version
if: ${{ matrix.java == '8' }} # Only upload Java 8 artifacts for MC 1.16
run: |
cat $GITHUB_WORKSPACE/gradle.properties | grep ^archives_base_name= >> $GITHUB_ENV
cat $GITHUB_WORKSPACE/gradle.properties | grep ^minecraft_version= >> $GITHUB_ENV
cat $GITHUB_WORKSPACE/gradle.properties | grep ^base_version= >> $GITHUB_ENV
- name: Create package name
if: ${{ matrix.java == '8' }} # Only upload Java 8 artifacts for MC 1.16
run: echo "package_name=[$minecraft_version] $archives_base_name-$base_version.${{ github.run_number }}" >> $GITHUB_ENV
- uses: actions/upload-artifact@v2
if: ${{ matrix.java == '8' }} # Only upload Java 8 artifacts for MC 1.16
with:
name: ${{ env.package_name }}
path: |
**/build/libs/
!build/libs/
!**/*-dev.jar
!**/*-shadow.jar
!**/*-transformProduction*.jar
!**/testmod*/
publish:
needs:
- validate-gradle
- license
- build
runs-on: ubuntu-20.04
if: |
!contains(github.event.head_commit.message, '[norelease]') && github.event.inputs.norelease != 'true'
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: 8
distribution: 'adopt'
- name: Cache Gradle wrapper
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: gradle-wrapper-${{ runner.os }}-${{ hashFiles('gradle/wrapper/**/*') }}
restore-keys: gradle-wrapper-${{ runner.os }}-
- name: Cache packages
id: cache-packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: gradle-packages-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-packages-${{ runner.os }}-
- name: Release to Maven and CurseForge
env:
# currently unused, may want to use these for changelogs though!
# GIT_COMMIT: ${{ github.event.after }}
# GIT_PREVIOUS_COMMIT: ${{ github.event.before }}
MAVEN_PASS: ${{ secrets.MAVEN_PASS }}
CURSE_API_KEY: ${{ secrets.CURSE_API_KEY }}
# TODO: make this use the artifacts from the previous build step
run: |
./gradlew build publish curseforgePublish --stacktrace --no-daemon
# Remove some potentially problematic files from the Gradle cache,
# so that GitHub Actions doesn't cache them.
- name: Cleanup Gradle Cache
if: steps.cache-packages.outputs.cache-hit != 'true'
run: |
rm -f $HOME/.gradle/caches/*/*.lock
rm -rf $HOME/.gradle/caches/*/plugin-resolution/
rm -rf $HOME/.gradle/caches/*/scripts/
rm -rf $HOME/.gradle/caches/*/scripts-remapped/
rm -rf $HOME/.gradle/caches/*/fileHashes/
rm -f $HOME/.gradle/caches/journal-1/file-access.bin

View File

@@ -1,28 +0,0 @@
name: Snapshot Compile & Release
on:
pull_request:
paths:
- '**.gradle'
- '**.properties'
- '**/src/**'
types: [ opened, synchronize, reopened ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up JDK 16
uses: actions/setup-java@v1
with:
java-version: 16
- name: Upload to Maven
run: ./gradlew publish --stacktrace
if: |
!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.pull_request.title, '[ci skip]')
env:
MAVEN_PASS: ${{ secrets.MAVEN_PASS }}
PR_NUM: ${{github.event.number}}

View File

@@ -4,160 +4,116 @@ GNU Lesser General Public License
_Version 3, 29 June 2007_
_Copyright © 2007 Free Software Foundation, Inc. &lt;<http://fsf.org/>&gt;_
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU
General Public License, supplemented by the additional permissions listed below.
### 0. Additional Definitions
As used herein, “this License” refers to version 3 of the GNU Lesser
General Public License, and the GNU GPL” refers to version 3 of the GNU
General Public License.
As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to
version 3 of the GNU General Public License.
“The Library” refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined
below.
An “Application” is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on
the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by
the Library.
A “Combined Work” is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the “Linked
Version”.
A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of
the Library with which the Combined Work was made is also called the Linked Version”.
The “Minimal Corresponding Source” for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding
any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not
on the Linked Version.
The “Corresponding Application Code” for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application,
including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the
System Libraries of the Combined Work.
### 1. Exception to Section 3 of the GNU GPL
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.
### 2. Conveying Modified Versions
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied
by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may
convey a copy of the modified version:
* **a)** under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
* **a)** under this License, provided that you make a good faith effort to ensure that, in the event an Application does
not supply the function or data, the facility still operates, and performs whatever part of its purpose remains
meaningful, or
* **b)** under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
* **b)** under the GNU GPL, with none of the additional permissions of this License applicable to that copy.
### 3. Object Code Incorporating Material from Library Header Files
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
The object code form of an Application may incorporate material from a header file that is part of the Library. You may
convey such object code under terms of your choice, provided that, if the incorporated material is not limited to
numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
* **a)** Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
* **b)** Accompany the object code with a copy of the GNU GPL and this license
document.
* **a)** Give prominent notice with each copy of the object code that the Library is used in it and that the Library and
its use are covered by this License.
* **b)** Accompany the object code with a copy of the GNU GPL and this license document.
### 4. Combined Works
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification
of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications,
if you also do each of the following:
* **a)** Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
* **a)** Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library
and its use are covered by this License.
* **b)** Accompany the Combined Work with a copy of the GNU GPL and this license
* **b)** Accompany the Combined Work with a copy of the GNU GPL and this license document.
* **c)** For a Combined Work that displays copyright notices during execution, include the copyright notice for the
Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license
document.
* **c)** For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
* **d)** Do one of the following:
- **0)** Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- **1)** Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that **(a)** uses at run time
a copy of the Library already present on the user's computer
system, and **(b)** will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
- **0)** Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application
Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a
modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6
of the GNU GPL for conveying Corresponding Source.
- **1)** Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that **(
a)** uses at run time a copy of the Library already present on the user's computer system, and **(b)** will
operate properly with a modified version of the Library that is interface-compatible with the Linked Version.
* **e)** Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option **4d0**, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option **4d1**, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
* **e)** Provide Installation Information, but only if you would otherwise be required to provide such information under
section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified
version of the Combined Work produced by recombining or relinking the Application with a modified version of the
Linked Version. (If you use option **4d0**, the Installation Information must accompany the Minimal Corresponding
Source and Corresponding Application Code. If you use option **4d1**, you must provide the Installation Information in
the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)
### 5. Combined Libraries
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
You may place library facilities that are a work based on the Library side by side in a single library together with
other library facilities that are not Applications and are not covered by this License, and convey such a combined
library under terms of your choice, if you do both of the following:
* **a)** Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
* **b)** Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
* **a)** Accompany the combined library with a copy of the same work based on the Library, uncombined with any other
library facilities, conveyed under the terms of this License.
* **b)** Give prominent notice with the combined library that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
### 6. Revised Versions of the GNU Lesser General Public License
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time
to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new
problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License “or any later version”
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
Each version is given a distinguishing version number. If the Library as you received it specifies that a certain
numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of
following the terms and conditions either of that published version or of any later version published by the Free
Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General
Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software
Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General
Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for
you to choose that version for the Library.

View File

@@ -1,26 +1,38 @@
# Architectury API
Talk to us on [Discord](https://discord.gg/C2RdJDpRBP)!
An intermediary api aimed to ease developing multiplatform mods.
### What is Architectury API
Architectury API is an api to abstract calls to fabric api and forge api as both loader has different implementations of what can be perceived as the same thing.
Architectury API updates regularly, with new hooks and features. Currently contains over **90** events hooks, networking abstraction, loader calls abstraction, game registry abstraction and an easy to use @ExpectPlatform annotation (Only works on static methods).
Architectury API is an api to abstract calls to fabric api and forge api as both loader has different implementations of
what can be perceived as the same thing.
Architectury API updates regularly, with new hooks and features. Currently contains over **90** events hooks, networking
abstraction, loader calls abstraction, game registry abstraction and an easy to use @ExpectPlatform annotation (Only
works on static methods).
### Do I really need this API?
Architectury API is only one part of the architectury ecosystem, **Architectury Plugin** is the gradle plugin enabling all this multiplatform actions.
Architectury API is optional for projects built on architectury, you may create your architectury project with just Architectury Plugin.
Architectury API is only one part of the architectury ecosystem, **Architectury Plugin** is the gradle plugin enabling
all this multiplatform actions.
Architectury API is optional for projects built on architectury, you may create your architectury project with just
Architectury Plugin.
### Advantages of Architectury
- Open sourced
- Less boilerplate for your multiplatform mod
### Getting started with making multiplatform mods
Gradle Plugin: https://github.com/architectury/architectury-plugin
Example Mod: https://github.com/architectury/architectury-example-mod
### Credits
This library bundles typetools, which you can find its license [here](https://github.com/jhalterman/typetools/blob/master/LICENSE.txt "")
This library bundles typetools, which you can find its
license [here](https://github.com/jhalterman/typetools/blob/master/LICENSE.txt "")

View File

@@ -1,5 +1,5 @@
plugins {
id "architectury-plugin" version "3.1-SNAPSHOT"
id "architectury-plugin" version "3.2-SNAPSHOT"
id "dev.architectury.loom" version "0.7.2-SNAPSHOT" apply false
id "org.cadixdev.licenser" version "0.5.0"
id "com.matthewprenger.cursegradle" version "1.4.0" apply false
@@ -23,11 +23,11 @@ allprojects {
apply plugin: "java"
apply plugin: "architectury-plugin"
apply plugin: "org.cadixdev.licenser"
ext {
isSnapshot = System.getenv("PR_NUM") != null
}
def runNumber = (System.getenv("GITHUB_RUN_NUMBER") == null ? "9999" : System.getenv("GITHUB_RUN_NUMBER"))
if (!ext.isSnapshot) {
@@ -37,7 +37,7 @@ allprojects {
version = rootProject.base_version + "-PR." + System.getenv("PR_NUM") + "." + runNumber
archivesBaseName = rootProject.archives_base_name_snapshot
}
group = rootProject.maven_group
tasks.withType(JavaCompile) {

View File

@@ -32,23 +32,23 @@ public class PlatformMethods {
String lookupType = lookupClass.getName().replace("$", "") + "Impl";
String platformExpectedClass = lookupType.substring(0, lookupType.lastIndexOf('.')) + "." + ArchitecturyTarget.getCurrentTarget() + "." +
lookupType.substring(lookupType.lastIndexOf('.') + 1);
lookupType.substring(lookupType.lastIndexOf('.') + 1);
Class<?> newClass;
try {
newClass = Class.forName(platformExpectedClass, false, lookupClass.getClassLoader());
} catch (ClassNotFoundException exception) {
throw new PlatformExpectedError(lookupClass.getName() + "#" + name + " expected platform implementation in " + platformExpectedClass +
"#" + name + ", but the class doesn't exist!", exception);
"#" + name + ", but the class doesn't exist!", exception);
}
MethodHandle platformMethod;
try {
platformMethod = lookup.findStatic(newClass, name, type);
} catch (NoSuchMethodException exception) {
throw new PlatformExpectedError(lookupClass.getName() + "#" + name + " expected platform implementation in " + platformExpectedClass +
"#" + name + ", but the method doesn't exist!", exception);
"#" + name + ", but the method doesn't exist!", exception);
} catch (IllegalAccessException exception) {
throw new PlatformExpectedError(lookupClass.getName() + "#" + name + " expected platform implementation in " + platformExpectedClass +
"#" + name + ", but the method's modifier doesn't match the access requirements!", exception);
"#" + name + ", but the method's modifier doesn't match the access requirements!", exception);
}
return new ConstantCallSite(platformMethod);
}

View File

@@ -37,7 +37,8 @@ import java.util.function.Consumer;
import java.util.function.Function;
public final class EventFactory {
private EventFactory() {}
private EventFactory() {
}
public static <T> Event<T> of(Function<List<T>, T> function) {
return new EventImpl<>(function);

View File

@@ -29,7 +29,8 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
public final class EventHandler {
private EventHandler() {}
private EventHandler() {
}
private static boolean initialized = false;

View File

@@ -63,11 +63,13 @@ public interface LifecycleEvent {
void stateChanged(T instance);
}
interface ServerState extends InstanceState<MinecraftServer> {}
interface ServerState extends InstanceState<MinecraftServer> {
}
interface WorldState<T extends Level> {
void act(T world);
}
interface ServerWorldState extends WorldState<ServerLevel> {}
interface ServerWorldState extends WorldState<ServerLevel> {
}
}

View File

@@ -35,11 +35,15 @@ public interface TickEvent<T> {
void tick(T instance);
interface Server extends TickEvent<MinecraftServer> {}
interface Server extends TickEvent<MinecraftServer> {
}
interface WorldTick<T extends Level> extends TickEvent<T> {}
interface WorldTick<T extends Level> extends TickEvent<T> {
}
interface ServerWorld extends WorldTick<ServerLevel> {}
interface ServerWorld extends WorldTick<ServerLevel> {
}
interface Player extends TickEvent<net.minecraft.world.entity.player.Player> {}
interface Player extends TickEvent<net.minecraft.world.entity.player.Player> {
}
}

View File

@@ -32,11 +32,13 @@ public interface ClientLifecycleEvent {
/**
* Invoked when client has been initialised, not available in forge.
*/
@Deprecated Event<ClientState> CLIENT_STARTED = EventFactory.createLoop();
@Deprecated
Event<ClientState> CLIENT_STARTED = EventFactory.createLoop();
/**
* Invoked when client is stopping, not available in forge.
*/
@Deprecated Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop();
@Deprecated
Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop();
/**
* Invoked after a world is loaded only on client, equivalent to forge's {@code WorldEvent.Load}.
*/
@@ -44,8 +46,10 @@ public interface ClientLifecycleEvent {
Event<ClientState> CLIENT_SETUP = EventFactory.createLoop();
@Environment(EnvType.CLIENT)
interface ClientState extends LifecycleEvent.InstanceState<Minecraft> {}
interface ClientState extends LifecycleEvent.InstanceState<Minecraft> {
}
@Environment(EnvType.CLIENT)
interface ClientWorldState extends LifecycleEvent.WorldState<ClientLevel> {}
interface ClientWorldState extends LifecycleEvent.WorldState<ClientLevel> {
}
}

View File

@@ -36,8 +36,10 @@ public interface ClientTickEvent<T> {
void tick(T instance);
@Environment(EnvType.CLIENT)
interface Client extends ClientTickEvent<Minecraft> {}
interface Client extends ClientTickEvent<Minecraft> {
}
@Environment(EnvType.CLIENT)
interface ClientWorld extends ClientTickEvent<ClientLevel> {}
interface ClientWorld extends ClientTickEvent<ClientLevel> {
}
}

View File

@@ -23,7 +23,8 @@ import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.world.level.block.entity.BlockEntity;
public class BlockEntityHooks {
private BlockEntityHooks() {}
private BlockEntityHooks() {
}
/**
* Sync data to the clients.

View File

@@ -23,7 +23,8 @@ import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.world.item.DyeColor;
public class DyeColorHooks {
private DyeColorHooks() {}
private DyeColorHooks() {
}
@ExpectPlatform
public static int getColorValue(DyeColor color) {

View File

@@ -25,7 +25,8 @@ import net.minecraft.world.phys.shapes.CollisionContext;
import org.jetbrains.annotations.Nullable;
public final class EntityHooks {
private EntityHooks() {}
private EntityHooks() {
}
@ExpectPlatform
public static String getEncodeId(Entity entity) {

View File

@@ -26,7 +26,8 @@ import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public final class ExplosionHooks {
private ExplosionHooks() {}
private ExplosionHooks() {
}
@ExpectPlatform
public static Vec3 getPosition(Explosion explosion) {

View File

@@ -34,7 +34,8 @@ import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
public class FluidStackHooks {
private FluidStackHooks() {}
private FluidStackHooks() {
}
@ExpectPlatform
public static Component getName(FluidStack stack) {

View File

@@ -24,7 +24,8 @@ import me.shedaniel.architectury.utils.IntValue;
import net.minecraft.world.entity.item.ItemEntity;
public final class ItemEntityHooks {
private ItemEntityHooks() {}
private ItemEntityHooks() {
}
/**
* The lifespan of an {@link ItemEntity}.

View File

@@ -26,7 +26,8 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
public final class ItemStackHooks {
private ItemStackHooks() {}
private ItemStackHooks() {
}
public static ItemStack copyWithCount(ItemStack stack, int count) {
ItemStack copy = stack.copy();

View File

@@ -22,7 +22,8 @@ package me.shedaniel.architectury.hooks;
import net.minecraft.world.level.storage.LevelResource;
public class LevelResourceHooks {
private LevelResourceHooks() {}
private LevelResourceHooks() {
}
public static LevelResource create(String id) {
return new LevelResource(id);

View File

@@ -24,7 +24,8 @@ import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.repository.RepositorySource;
public class PackRepositoryHooks {
private PackRepositoryHooks() {}
private PackRepositoryHooks() {
}
@ExpectPlatform
public static void addSource(PackRepository repository, RepositorySource source) {

View File

@@ -23,7 +23,8 @@ import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.world.entity.player.Player;
public final class PlayerHooks {
private PlayerHooks() {}
private PlayerHooks() {
}
@ExpectPlatform
public static boolean isFake(Player player) {

View File

@@ -30,7 +30,8 @@ import java.util.List;
@Environment(EnvType.CLIENT)
public final class ScreenHooks {
private ScreenHooks() {}
private ScreenHooks() {
}
@ExpectPlatform
public static List<AbstractWidget> getButtons(Screen screen) {

View File

@@ -31,7 +31,8 @@ import net.minecraft.world.level.material.Fluid;
import java.util.function.Supplier;
public final class TagHooks {
private TagHooks() {}
private TagHooks() {
}
@ExpectPlatform
public static <T> Tag.Named<T> getOptional(ResourceLocation id, Supplier<TagCollection<T>> collection) {

View File

@@ -31,7 +31,6 @@ import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -61,10 +60,10 @@ public final class BiomeHooks {
}
public BiomeWrapped(Biome biome,
ClimateProperties climateProperties,
EffectsProperties effectsProperties,
GenerationProperties generationProperties,
SpawnProperties spawnProperties) {
ClimateProperties climateProperties,
EffectsProperties effectsProperties,
GenerationProperties generationProperties,
SpawnProperties spawnProperties) {
this.biome = biome;
this.climateProperties = climateProperties;
this.effectsProperties = effectsProperties;
@@ -110,8 +109,8 @@ public final class BiomeHooks {
public static class MutableBiomeWrapped extends BiomeWrapped implements BiomeProperties.Mutable {
public MutableBiomeWrapped(Biome biome,
GenerationProperties.Mutable generationProperties,
SpawnProperties.Mutable spawnProperties) {
GenerationProperties.Mutable generationProperties,
SpawnProperties.Mutable spawnProperties) {
this(biome,
new ClimateWrapped(biome.climateSettings),
new EffectsWrapped(biome.getSpecialEffects()),
@@ -120,10 +119,10 @@ public final class BiomeHooks {
}
public MutableBiomeWrapped(Biome biome,
ClimateProperties.Mutable climateProperties,
EffectsProperties.Mutable effectsProperties,
GenerationProperties.Mutable generationProperties,
SpawnProperties.Mutable spawnProperties) {
ClimateProperties.Mutable climateProperties,
EffectsProperties.Mutable effectsProperties,
GenerationProperties.Mutable generationProperties,
SpawnProperties.Mutable spawnProperties) {
super(biome,
climateProperties,
effectsProperties,

View File

@@ -21,7 +21,6 @@ package me.shedaniel.architectury.hooks.biome;
import net.minecraft.world.level.biome.Biome.Precipitation;
import net.minecraft.world.level.biome.Biome.TemperatureModifier;
import org.jetbrains.annotations.NotNull;
public interface ClimateProperties {
Precipitation getPrecipitation();

View File

@@ -32,14 +32,15 @@ import java.util.Collection;
import java.util.Optional;
public final class Platform {
private Platform() {}
private Platform() {
}
private static int simpleLoaderCache = -1;
/**
* @return the current mod loader, either "fabric" or "forge"
* @deprecated does not reflect the true mod loader, "quilt" is never returned,
* use {@link ArchitecturyTarget#getCurrentTarget()} instead.
* use {@link ArchitecturyTarget#getCurrentTarget()} instead.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")

View File

@@ -32,7 +32,8 @@ import java.util.function.Function;
@Environment(EnvType.CLIENT)
public final class BlockEntityRenderers {
private BlockEntityRenderers() {}
private BlockEntityRenderers() {
}
@ExpectPlatform
public static <T extends BlockEntity> void registerRenderer(BlockEntityType<T> type, BlockEntityRendererProvider<? super T> provider) {

View File

@@ -32,7 +32,8 @@ import java.util.function.Supplier;
@Environment(EnvType.CLIENT)
public final class ColorHandlers {
private ColorHandlers() {}
private ColorHandlers() {
}
public static void registerItemColors(ItemColor color, ItemLike... items) {
Supplier<ItemLike>[] array = new Supplier[items.length];

View File

@@ -27,7 +27,8 @@ import net.minecraft.world.item.ItemStack;
import java.util.function.Supplier;
public final class CreativeTabs {
private CreativeTabs() {}
private CreativeTabs() {
}
// I am sorry, fabric wants a resource location instead of the translation key for whatever reason
@ExpectPlatform

View File

@@ -23,7 +23,8 @@ import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.advancements.CriterionTrigger;
public final class CriteriaTriggersRegistry {
private CriteriaTriggersRegistry() {}
private CriteriaTriggersRegistry() {
}
/**
* Invokes {@link net.minecraft.advancements.CriteriaTriggers#register(CriterionTrigger)}.

View File

@@ -29,8 +29,9 @@ import java.util.function.BiConsumer;
* A utility class for creating game rule types.
*/
public final class GameRuleFactory {
private GameRuleFactory() {}
private GameRuleFactory() {
}
/**
* Creates a boolean rule type.
*
@@ -41,7 +42,7 @@ public final class GameRuleFactory {
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue) {
throw new AssertionError();
}
/**
* Creates a boolean rule type.
*
@@ -53,7 +54,7 @@ public final class GameRuleFactory {
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changedCallback) {
throw new AssertionError();
}
/**
* Creates an integer rule type.
*
@@ -64,7 +65,7 @@ public final class GameRuleFactory {
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue) {
throw new AssertionError();
}
/**
* Creates an integer rule type.
*

View File

@@ -26,15 +26,16 @@ import net.minecraft.world.level.GameRules;
* A registry for registering game rules.
*/
public final class GameRuleRegistry {
private GameRuleRegistry() {}
private GameRuleRegistry() {
}
/**
* Registers a game rule.
*
* @param name the rule's name
* @param category the rule category
* @param type the type of the rule
* @param <T> the type of the rule value
* @param <T> the type of the rule value
* @return a key for the registered rule
*/
@ExpectPlatform

View File

@@ -26,7 +26,8 @@ import net.minecraft.client.KeyMapping;
@Environment(EnvType.CLIENT)
public final class KeyBindings {
private KeyBindings() {}
private KeyBindings() {
}
@ExpectPlatform
public static void registerKeyBinding(KeyMapping binding) {

View File

@@ -41,7 +41,8 @@ import java.util.function.Consumer;
* A utility class to register {@link MenuType}s and {@link Screen}s for containers
*/
public final class MenuRegistry {
private MenuRegistry() {}
private MenuRegistry() {
}
/**
* Opens the menu.

View File

@@ -24,7 +24,8 @@ import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.PreparableReloadListener;
public final class ReloadListeners {
private ReloadListeners() {}
private ReloadListeners() {
}
@ExpectPlatform
public static void registerReloadListener(PackType type, PreparableReloadListener listener) {

View File

@@ -28,7 +28,8 @@ import net.minecraft.world.level.material.Fluid;
@Environment(EnvType.CLIENT)
public final class RenderTypes {
private RenderTypes() {}
private RenderTypes() {
}
@ExpectPlatform
public static void register(RenderType type, Block... blocks) {

View File

@@ -27,7 +27,8 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import java.util.function.Supplier;
public final class EntityAttributes {
private EntityAttributes() {}
private EntityAttributes() {
}
/**
* Registers default attributes to entities.

View File

@@ -32,7 +32,8 @@ import java.util.function.Function;
@Environment(EnvType.CLIENT)
public final class EntityRenderers {
private EntityRenderers() {}
private EntityRenderers() {
}
@ExpectPlatform
public static <T extends Entity> void register(EntityType<T> type, EntityRendererProvider<T> provider) {

View File

@@ -24,7 +24,8 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
public final class FuelRegistry {
private FuelRegistry() {}
private FuelRegistry() {
}
/**
* Registers a burn time for items.

View File

@@ -0,0 +1,73 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.trade;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.npc.VillagerTrades;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.trading.MerchantOffer;
import org.jetbrains.annotations.Nullable;
import java.util.Random;
/**
* This class is the easiest implementation of a trade object.
* All trades added by vanilla do have custom classes like {@link VillagerTrades.EmeraldForItems}, but they aren't accessible.
* <p>
* Instead of widening the access of those classes or recreating them, this class was added to serve a basic trading implementation.
* To register a trade, just call
* {@link TradeRegistry#registerVillagerTrade(net.minecraft.world.entity.npc.VillagerProfession, int, VillagerTrades.ItemListing...)}
* or
* {@link TradeRegistry#registerTradeForWanderingTrader(boolean, VillagerTrades.ItemListing...)}.
*/
public class SimpleTrade implements VillagerTrades.ItemListing {
private final ItemStack primaryPrice;
private final ItemStack secondaryPrice;
private final ItemStack sale;
private final int maxTrades;
private final int experiencePoints;
private final float priceMultiplier;
/**
* Constructor for creating the trade.
* You can take a look at all the values the vanilla game uses right here {@link VillagerTrades#TRADES}.
*
* @param primaryPrice The first price a player has to pay to get the 'sale' stack.
* @param secondaryPrice A optional, secondary price to pay as well as the primary one. If not needed just use {@link ItemStack#EMPTY}.
* @param sale The ItemStack which a player can purchase in exchange for the two prices.
* @param maxTrades The amount of trades one villager or wanderer can do. When the amount is surpassed, the trade can't be purchased anymore.
* @param experiencePoints How much experience points does the player get, when trading. Vanilla uses between 2 and 30 for this.
* @param priceMultiplier How much should the price rise, after the trade is used. It is added to the stack size of the primary price. Vanilla uses between 0.05 and 0.2.
*/
public SimpleTrade(ItemStack primaryPrice, ItemStack secondaryPrice, ItemStack sale, int maxTrades, int experiencePoints, float priceMultiplier) {
this.primaryPrice = primaryPrice;
this.secondaryPrice = secondaryPrice;
this.sale = sale;
this.maxTrades = maxTrades;
this.experiencePoints = experiencePoints;
this.priceMultiplier = priceMultiplier;
}
@Nullable
@Override
public MerchantOffer getOffer(Entity entity, Random random) {
return new MerchantOffer(this.primaryPrice, this.secondaryPrice, this.sale, this.maxTrades, this.experiencePoints, this.priceMultiplier);
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.trade;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerTrades;
public class TradeRegistry {
private TradeRegistry() {
}
/**
* Register a trade ({@link VillagerTrades.ItemListing}) for a villager by its profession and level.
* When the mod loader is Forge, the {@code VillagerTradesEvent} event is used.
*
* @param profession The Profession the villager needs to have this trade.
* @param level The level the villager needs. Vanilla range is 1 to 5, however mods may extend that upper limit further.
* @param trades The trades to add to this profession at the specified level.
*/
public static void registerVillagerTrade(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
if (level < 1) {
throw new IllegalArgumentException("Villager Trade level has to be at least 1!");
}
registerVillagerTrade0(profession, level, trades);
}
@ExpectPlatform
private static void registerVillagerTrade0(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
throw new AssertionError();
}
/**
* Register a trade ({@link VillagerTrades.ItemListing}) to a wandering trader by its rarity.
* When the mod loader is Forge, the {@code WandererTradesEvent} event is used.
*
* @param rare Whether this trade is "rare". Rare trades have a five times lower chance of being used.
* @param trades The trades to add to the wandering trader.
*/
@ExpectPlatform
public static void registerTradeForWanderingTrader(boolean rare, VillagerTrades.ItemListing... trades) {
throw new AssertionError();
}
}

View File

@@ -56,5 +56,6 @@ public final class EnvExecutor {
}
}
private EnvExecutor() {}
private EnvExecutor() {
}
}

View File

@@ -40,5 +40,6 @@ public final class NbtType {
*/
public static final int NUMBER = 99;
private NbtType() {}
private NbtType() {
}
}

View File

@@ -22,19 +22,19 @@ package me.shedaniel.architectury.utils;
public class PlatformExpectedError extends Error {
public PlatformExpectedError() {
}
public PlatformExpectedError(String message) {
super(message);
}
public PlatformExpectedError(String message, Throwable cause) {
super(message, cause);
}
public PlatformExpectedError(Throwable cause) {
super(cause);
}
public PlatformExpectedError(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}

View File

@@ -22,4 +22,5 @@ package me.shedaniel.architectury.utils;
import java.util.function.Consumer;
import java.util.function.Supplier;
public interface Value<T> extends Supplier<T>, Consumer<T> {}
public interface Value<T> extends Supplier<T>, Consumer<T> {
}

View File

@@ -5,7 +5,11 @@
"minVersion": "0.7.11",
"client": [
],
"mixins": ["MixinFallingBlockEntity", "FluidTagsAccessor", "MixinLightningBolt"],
"mixins": [
"MixinFallingBlockEntity",
"FluidTagsAccessor",
"MixinLightningBolt"
],
"injectors": {
"maxShiftBy": 5,
"defaultRequire": 1

View File

@@ -22,8 +22,8 @@ package me.shedaniel.architectury.compat.fabric;
import com.google.common.collect.Maps;
import io.github.prospector.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi;
import me.shedaniel.architectury.platform.fabric.PlatformImpl;
import me.shedaniel.architectury.platform.Mod;
import me.shedaniel.architectury.platform.fabric.PlatformImpl;
import java.util.Map;

View File

@@ -19,7 +19,6 @@
package me.shedaniel.architectury.hooks.fabric;
import com.google.common.base.Preconditions;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;

View File

@@ -35,10 +35,10 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(value = {Level.class, ServerLevel.class})
public class ExplosionPreInvoker {
@Inject(method = "explode(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Explosion$BlockInteraction;)Lnet/minecraft/world/level/Explosion;",
@Inject(method = "explode(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Explosion$BlockInteraction;)Lnet/minecraft/world/level/Explosion;",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Explosion;explode()V"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
private void explodePre(Entity entity, DamageSource damageSource, ExplosionDamageCalculator explosionDamageCalculator, double d, double e, double f, float g, boolean bl, Explosion.BlockInteraction blockInteraction, CallbackInfoReturnable<Explosion> cir, Explosion explosion) {
if (ExplosionEvent.PRE.invoker().explode((Level)(Object) this, explosion) == InteractionResult.FAIL) {
if (ExplosionEvent.PRE.invoker().explode((Level) (Object) this, explosion) == InteractionResult.FAIL) {
cir.setReturnValue(explosion);
}
}

View File

@@ -32,7 +32,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public abstract class MixinBlockItem {
@Inject(method = "place",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/item/context/BlockPlaceContext;getClickedPos()Lnet/minecraft/core/BlockPos;"),
target = "Lnet/minecraft/world/item/context/BlockPlaceContext;getClickedPos()Lnet/minecraft/core/BlockPos;"),
cancellable = true)
private void place(BlockPlaceContext context, CallbackInfoReturnable<InteractionResult> cir) {
InteractionResult result = BlockEvent.PLACE.invoker().placeBlock(context.getLevel(), context.getClickedPos(), context.getLevel().getBlockState(context.getClickedPos()), context.getPlayer());

View File

@@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Commands.class)
public class MixinCommands {
@Redirect(method = "performCommand",
at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/CommandDispatcher;execute(Lcom/mojang/brigadier/StringReader;Ljava/lang/Object;)I", remap = false))
at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/CommandDispatcher;execute(Lcom/mojang/brigadier/StringReader;Ljava/lang/Object;)I", remap = false))
private int performCommand(CommandDispatcher<CommandSourceStack> dispatcher, StringReader input, Object source) throws CommandSyntaxException {
CommandSourceStack stack = (CommandSourceStack) source;
ParseResults<CommandSourceStack> parse = dispatcher.parse(input, stack);

View File

@@ -38,13 +38,28 @@ import java.util.Set;
@Mixin(Explosion.class)
public class MixinExplosion implements ExplosionHooksImpl.ExplosionExtensions {
@Shadow @Final private Level level;
@Shadow @Final private double x;
@Shadow @Final private double y;
@Shadow @Final private double z;
@Shadow @Final @Nullable private Entity source;
@Shadow @Final @Mutable private float radius;
@Unique Vec3 position;
@Shadow
@Final
private Level level;
@Shadow
@Final
private double x;
@Shadow
@Final
private double y;
@Shadow
@Final
private double z;
@Shadow
@Final
@Nullable
private Entity source;
@Shadow
@Final
@Mutable
private float radius;
@Unique
Vec3 position;
@Inject(method = "explode", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/Vec3;<init>(DDD)V", ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD)

View File

@@ -21,19 +21,15 @@ package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.event.events.InteractionEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Tuple;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.FarmBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.commons.lang3.tuple.Triple;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(FarmBlock.class)

View File

@@ -32,7 +32,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(FurnaceResultSlot.class)
public class MixinFurnaceResultSlot {
@Shadow @Final private Player player;
@Shadow
@Final
private Player player;
@Inject(method = "checkTakeAchievements", at = @At("RETURN"))
private void checkTakeAchievements(ItemStack itemStack, CallbackInfo ci) {

View File

@@ -22,7 +22,8 @@ package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.event.EventResult;
import me.shedaniel.architectury.event.events.EntityEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.NaturalSpawner;
import org.spongepowered.asm.mixin.Mixin;

View File

@@ -53,8 +53,8 @@ public abstract class MixinPhantomSpawner {
locals = LocalCapture.CAPTURE_FAILSOFT // SOFT, because this will break in 2 seconds
)
private void checkPhantomSpawn(ServerLevel level, boolean bl, boolean bl2, CallbackInfoReturnable<Integer> cir,
Random random, int i, Iterator<ServerPlayer> it, Player player, BlockPos pos, DifficultyInstance diff, BlockPos pos2,
SpawnGroupData sgd, int l, int m, Phantom entity) {
Random random, int i, Iterator<ServerPlayer> it, Player player, BlockPos pos, DifficultyInstance diff, BlockPos pos2,
SpawnGroupData sgd, int l, int m, Phantom entity) {
if (EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(entity, level, pos.getX(), pos.getY(), pos.getZ(), MobSpawnType.NATURAL, null).value() == Boolean.FALSE) {
cir.setReturnValue(0);
cir.cancel();

View File

@@ -54,8 +54,8 @@ public class MixinPlayer {
}
@Inject(method = "interactOn", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;",
ordinal = 0),
target = "Lnet/minecraft/world/entity/player/Player;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;",
ordinal = 0),
cancellable = true)
private void entityInteract(Entity entity, InteractionHand interactionHand, CallbackInfoReturnable<InteractionResult> cir) {
InteractionResult result = InteractionEvent.INTERACT_ENTITY.invoker().interact((Player) (Object) this, entity, interactionHand);

View File

@@ -31,11 +31,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerAdvancements.class)
public class MixinPlayerAdvancements {
@Shadow private ServerPlayer player;
@Shadow
private ServerPlayer player;
@Inject(method = "award",
at = @At(value = "INVOKE", target = "Lnet/minecraft/advancements/AdvancementRewards;grant(Lnet/minecraft/server/level/ServerPlayer;)V",
shift = At.Shift.AFTER))
shift = At.Shift.AFTER))
private void award(Advancement advancement, String string, CallbackInfoReturnable<Boolean> cir) {
PlayerEvent.PLAYER_ADVANCEMENT.invoker().award(player, advancement);
}

View File

@@ -33,13 +33,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ResultSlot.class)
public class MixinResultSlot {
@Shadow @Final private Player player;
@Shadow
@Final
private Player player;
@Shadow @Final private CraftingContainer craftSlots;
@Shadow
@Final
private CraftingContainer craftSlots;
@Inject(method = "checkTakeAchievements", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/item/ItemStack;onCraftedBy(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;I)V",
shift = At.Shift.AFTER))
target = "Lnet/minecraft/world/item/ItemStack;onCraftedBy(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;I)V",
shift = At.Shift.AFTER))
private void craft(ItemStack itemStack, CallbackInfo ci) {
PlayerEvent.CRAFT_ITEM.invoker().craft(player, itemStack, craftSlots);
}

View File

@@ -24,14 +24,12 @@ import me.shedaniel.architectury.impl.fabric.ChatComponentImpl;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.game.ServerboundChatPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.server.network.TextFilter;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import org.apache.commons.lang3.StringUtils;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -44,11 +42,15 @@ import java.util.Objects;
@Mixin(ServerGamePacketListenerImpl.class)
public abstract class MixinServerGamePacketListenerImpl {
@Shadow public ServerPlayer player;
@Shadow
public ServerPlayer player;
@Shadow @Final private MinecraftServer server;
@Shadow
@Final
private MinecraftServer server;
@Shadow private int chatSpamTickCount;
@Shadow
private int chatSpamTickCount;
@Shadow
public abstract void disconnect(Component component);

View File

@@ -54,7 +54,7 @@ public class MixinServerPlayer {
@Inject(method = "doCloseContainer",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/AbstractContainerMenu;removed(Lnet/minecraft/world/entity/player/Player;)V",
shift = At.Shift.AFTER))
shift = At.Shift.AFTER))
private void doCloseContainer(CallbackInfo ci) {
PlayerEvent.CLOSE_MENU.invoker().close((ServerPlayer) (Object) this, ((ServerPlayer) (Object) this).containerMenu);
}

View File

@@ -35,13 +35,15 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ServerPlayerGameMode.class)
public class MixinServerPlayerGameMode {
@Shadow public ServerLevel level;
@Shadow
public ServerLevel level;
@Shadow public ServerPlayer player;
@Shadow
public ServerPlayer player;
@Inject(method = "destroyBlock", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/level/block/state/BlockState;getBlock()Lnet/minecraft/world/level/block/Block;",
ordinal = 0),
target = "Lnet/minecraft/world/level/block/state/BlockState;getBlock()Lnet/minecraft/world/level/block/Block;",
ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private void onBreak(BlockPos blockPos, CallbackInfoReturnable<Boolean> cir, BlockState state) {
if (BlockEvent.BREAK.invoker().breakBlock(this.level, blockPos, state, this.player, null) == InteractionResult.FAIL) {

View File

@@ -43,9 +43,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPacketListener.class)
public class MixinClientPacketListener {
@Shadow private Minecraft minecraft;
@Shadow @Final private RecipeManager recipeManager;
@Unique private LocalPlayer tmpPlayer;
@Shadow
private Minecraft minecraft;
@Shadow
@Final
private RecipeManager recipeManager;
@Unique
private LocalPlayer tmpPlayer;
@Inject(method = "handleLogin", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;broadcastOptions()V"))
private void handleLogin(ClientboundLoginPacket packet, CallbackInfo ci) {
@@ -58,14 +62,14 @@ public class MixinClientPacketListener {
}
@Inject(method = "handleRespawn", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/multiplayer/ClientLevel;addPlayer(ILnet/minecraft/client/player/AbstractClientPlayer;)V"))
target = "Lnet/minecraft/client/multiplayer/ClientLevel;addPlayer(ILnet/minecraft/client/player/AbstractClientPlayer;)V"))
private void handleRespawn(ClientboundRespawnPacket packet, CallbackInfo ci) {
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(tmpPlayer, minecraft.player);
this.tmpPlayer = null;
}
@Inject(method = "handleChat", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/Gui;handleChat(Lnet/minecraft/network/chat/ChatType;Lnet/minecraft/network/chat/Component;Ljava/util/UUID;)V"),
target = "Lnet/minecraft/client/gui/Gui;handleChat(Lnet/minecraft/network/chat/ChatType;Lnet/minecraft/network/chat/Component;Ljava/util/UUID;)V"),
cancellable = true)
private void handleChat(ClientboundChatPacket packet, CallbackInfo ci) {
InteractionResultHolder<Component> process = ClientChatEvent.CLIENT_RECEIVED.invoker().process(packet.getType(), packet.getMessage(), packet.getSender());

View File

@@ -34,11 +34,13 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(GameRenderer.class)
public abstract class MixinGameRenderer {
@Shadow @Final private Minecraft minecraft;
@Shadow
@Final
private Minecraft minecraft;
@Inject(method = "render(FJZ)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;render(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V",
ordinal = 0), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
ordinal = 0), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
public void renderScreenPre(float tickDelta, long startTime, boolean tick, CallbackInfo ci, int mouseX, int mouseY, PoseStack matrices) {
if (GuiEvent.RENDER_PRE.invoker().render(minecraft.screen, matrices, mouseX, mouseY, minecraft.getDeltaFrameTime()) == InteractionResult.FAIL) {
ci.cancel();
@@ -47,7 +49,7 @@ public abstract class MixinGameRenderer {
@Inject(method = "render(FJZ)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;render(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V",
shift = At.Shift.AFTER, ordinal = 0), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
shift = At.Shift.AFTER, ordinal = 0), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
public void renderScreenPost(float tickDelta, long startTime, boolean tick, CallbackInfo ci, int mouseX, int mouseY, PoseStack matrices) {
GuiEvent.RENDER_POST.invoker().render(minecraft.screen, matrices, mouseX, mouseY, minecraft.getDeltaFrameTime());
}

View File

@@ -78,8 +78,8 @@ public class MixinKeyboardHandler {
}
@Inject(method = "keyPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0), cancellable = true)
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0), cancellable = true)
public void onKey(long long_1, int int_1, int int_2, int int_3, int int_4, CallbackInfo info) {
if (!info.isCancelled()) {
if (int_3 != 1 && (int_3 != 2 || !this.sendRepeatsToGui)) {
@@ -97,8 +97,8 @@ public class MixinKeyboardHandler {
}
@Inject(method = "keyPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD,
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD,
cancellable = true)
public void onKeyAfter(long long_1, int int_1, int int_2, int int_3, int int_4, CallbackInfo info, ContainerEventHandler containerEventHandler, boolean bls[]) {
if (!info.isCancelled() && !bls[0]) {

View File

@@ -43,9 +43,13 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Unique
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
@Shadow @Nullable public LocalPlayer player;
@Shadow
@Nullable
public LocalPlayer player;
@Shadow @Nullable public HitResult hitResult;
@Shadow
@Nullable
public HitResult hitResult;
@Shadow
public abstract void setScreen(@Nullable Screen screen);
@@ -75,10 +79,10 @@ public abstract class MixinMinecraft {
@ModifyVariable(
method = "setScreen",
at = @At(value = "FIELD",
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
argsOnly = true
)
public Screen modifyScreen(Screen screen) {
@@ -102,10 +106,10 @@ public abstract class MixinMinecraft {
@Inject(
method = "setScreen",
at = @At(value = "FIELD",
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
cancellable = true
)
public void cancelSetScreen(@Nullable Screen screen, CallbackInfo ci) {

View File

@@ -52,7 +52,7 @@ public class MixinMouseHandler {
@Inject(method = "onScroll",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDD)Z",
ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void onMouseScrolled(long handle, double xOffset, double yOffset, CallbackInfo info, double amount, double x, double y) {
if (!info.isCancelled()) {
InteractionResult result = ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(minecraft, minecraft.screen, x, y, amount);
@@ -63,7 +63,7 @@ public class MixinMouseHandler {
@Inject(method = "onScroll",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDD)Z",
ordinal = 0, shift = At.Shift.AFTER), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
ordinal = 0, shift = At.Shift.AFTER), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void onMouseScrolledPost(long handle, double xOffset, double yOffset, CallbackInfo info, double amount, double x, double y) {
if (!info.isCancelled()) {
InteractionResult result = ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(minecraft, minecraft.screen, x, y, amount);
@@ -72,7 +72,7 @@ public class MixinMouseHandler {
@Inject(method = "onScroll",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;isSpectator()Z",
ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void onRawMouseScrolled(long handle, double xOffset, double yOffset, CallbackInfo info, double amount) {
if (!info.isCancelled()) {
InteractionResult result = ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(minecraft, amount);
@@ -107,7 +107,7 @@ public class MixinMouseHandler {
@Inject(method = "onPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/Minecraft;getOverlay()Lnet/minecraft/client/gui/screens/Overlay;",
ordinal = 0), cancellable = true)
ordinal = 0), cancellable = true)
public void onRawMouseClicked(long handle, int button, int action, int mods, CallbackInfo info) {
if (!info.isCancelled()) {
InteractionResult result = ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(minecraft, button, action, mods);

View File

@@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class MixinMultiPlayerGameMode {
@Inject(method = "interact",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V",
shift = At.Shift.AFTER),
shift = At.Shift.AFTER),
cancellable = true)
private void entityInteract(Player player, Entity entity, InteractionHand interactionHand, CallbackInfoReturnable<InteractionResult> cir) {
InteractionResult result = InteractionEvent.INTERACT_ENTITY.invoker().interact(player, entity, interactionHand);

View File

@@ -44,9 +44,13 @@ import java.util.List;
@Mixin(Screen.class)
public abstract class MixinScreen implements ScreenInputDelegate {
@Shadow @Final public List<AbstractWidget> buttons;
@Unique private static ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
@Unique private static ThreadLocal<TooltipEventColorContextImpl> tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new);
@Shadow
@Final
public List<AbstractWidget> buttons;
@Unique
private static ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
@Unique
private static ThreadLocal<TooltipEventColorContextImpl> tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new);
@Shadow
public abstract List<? extends GuiEventListener> children();
@@ -102,13 +106,13 @@ public abstract class MixinScreen implements ScreenInputDelegate {
}
@ModifyVariable(method = "renderTooltipInternal",
at = @At(value = "HEAD"), ordinal = 0)
at = @At(value = "HEAD"), ordinal = 0)
private int modifyTooltipX(int original) {
return tooltipPositionContext.get().getTooltipX();
}
@ModifyVariable(method = "renderTooltipInternal",
at = @At(value = "HEAD"), ordinal = 1)
at = @At(value = "HEAD"), ordinal = 1)
private int modifyTooltipY(int original) {
return tooltipPositionContext.get().getTooltipY();
}

View File

@@ -38,7 +38,7 @@ import java.util.stream.Stream;
public class MixinTextureAtlas {
@Inject(method = "prepareToStitch",
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", ordinal = 0,
shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
private void preStitch(ResourceManager resourceManager, Stream<ResourceLocation> stream, ProfilerFiller profilerFiller, int i, CallbackInfoReturnable<TextureAtlas.Preparations> cir, Set<ResourceLocation> set) {
TextureStitchEvent.PRE.invoker().stitch((TextureAtlas) (Object) this, set::add);
}

View File

@@ -79,13 +79,13 @@ public class BiomeModificationsImpl {
static {
BiomeModification modification = net.fabricmc.fabric.api.biome.v1.BiomeModifications.create(FABRIC_MODIFICATION);
registerModification(modification,ModificationPhase.ADDITIONS, ADDITIONS);
registerModification(modification,ModificationPhase.POST_PROCESSING, POST_PROCESSING);
registerModification(modification,ModificationPhase.REMOVALS, REMOVALS);
registerModification(modification,ModificationPhase.REPLACEMENTS, REPLACEMENTS);
registerModification(modification, ModificationPhase.ADDITIONS, ADDITIONS);
registerModification(modification, ModificationPhase.POST_PROCESSING, POST_PROCESSING);
registerModification(modification, ModificationPhase.REMOVALS, REMOVALS);
registerModification(modification, ModificationPhase.REPLACEMENTS, REPLACEMENTS);
}
private static void registerModification( BiomeModification modification, ModificationPhase phase, List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> list ) {
private static void registerModification(BiomeModification modification, ModificationPhase phase, List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> list) {
modification.add(phase, Predicates.alwaysTrue(), (biomeSelectionContext, biomeModificationContext) -> {
BiomeContext biomeContext = wrapSelectionContext(biomeSelectionContext);
BiomeProperties.Mutable mutableBiome = wrapMutableBiome(biomeSelectionContext.getBiome(), biomeModificationContext);
@@ -153,43 +153,43 @@ public class BiomeModificationsImpl {
super(biome);
this.context = context;
}
@Override
public Mutable setSurfaceBuilder(ConfiguredSurfaceBuilder<?> builder) {
this.context.setBuiltInSurfaceBuilder(builder);
return this;
}
@Override
public Mutable addFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
this.context.addBuiltInFeature(decoration, feature);
return this;
}
@Override
public Mutable addCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
context.addBuiltInCarver(carving, feature);
return this;
}
@Override
public Mutable addStructure(ConfiguredStructureFeature<?, ?> feature) {
context.addBuiltInStructure(feature);
return this;
}
@Override
public Mutable removeFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
context.removeBuiltInFeature(decoration, feature);
return this;
}
@Override
public Mutable removeCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
context.removeBuiltInCarver(carving, feature);
return this;
}
@Override
public Mutable removeStructure(ConfiguredStructureFeature<?, ?> feature) {
context.removeBuiltInStructure(feature);
@@ -199,47 +199,47 @@ public class BiomeModificationsImpl {
private static class MutableSpawnProperties extends BiomeHooks.SpawnSettingsWrapped implements SpawnProperties.Mutable {
protected final SpawnSettingsContext context;
public MutableSpawnProperties(Biome biome, SpawnSettingsContext context) {
super(biome);
this.context = context;
}
@Override
public @NotNull Mutable setCreatureProbability(float probability) {
context.setCreatureSpawnProbability(probability);
return this;
}
@Override
public Mutable addSpawn(MobCategory category, MobSpawnSettings.SpawnerData data) {
context.addSpawn(category, data);
return this;
}
@Override
public boolean removeSpawns(BiPredicate<MobCategory, MobSpawnSettings.SpawnerData> predicate) {
return context.removeSpawns(predicate);
}
@Override
public Mutable setSpawnCost(EntityType<?> entityType, MobSpawnSettings.MobSpawnCost cost) {
context.setSpawnCost(entityType, cost.getCharge(), cost.getEnergyBudget());
return this;
}
@Override
public Mutable setSpawnCost(EntityType<?> entityType, double mass, double gravityLimit) {
context.setSpawnCost(entityType, mass, gravityLimit);
return this;
}
@Override
public Mutable clearSpawnCost(EntityType<?> entityType) {
context.clearSpawnCost(entityType);
return this;
}
@Override
public @NotNull Mutable setPlayerSpawnFriendly(boolean friendly) {
context.setPlayerSpawnFriendly(friendly);

View File

@@ -29,15 +29,15 @@ public class GameRuleFactoryImpl {
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue) {
return GameRuleFactory.createBooleanRule(defaultValue);
}
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changedCallback) {
return GameRuleFactory.createBooleanRule(defaultValue, changedCallback);
}
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue) {
return GameRuleFactory.createIntRule(defaultValue);
}
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changedCallback) {
return GameRuleFactory.createIntRule(defaultValue, changedCallback);
}

View File

@@ -0,0 +1,36 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.trade.fabric;
import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerTrades;
import java.util.Collections;
public class TradeRegistryImpl {
public static void registerVillagerTrade0(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
TradeOfferHelper.registerVillagerOffers(profession, level, allTradesList -> Collections.addAll(allTradesList, trades));
}
public static void registerTradeForWanderingTrader(boolean rare, VillagerTrades.ItemListing... trades) {
TradeOfferHelper.registerWanderingTraderOffers(rare ? 2 : 1, allTradesList -> Collections.addAll(allTradesList, trades));
}
}

View File

@@ -68,7 +68,7 @@ publishing {
}
}
}
repositories {
if (System.getenv("MAVEN_PASS") != null) {
maven {

View File

@@ -1 +1 @@
loom.platform=forge
loom.platform=forge

View File

@@ -23,7 +23,8 @@ import me.shedaniel.architectury.fluid.FluidStack;
import me.shedaniel.architectury.utils.Fraction;
public final class FluidStackHooksForge {
private FluidStackHooksForge() {}
private FluidStackHooksForge() {
}
public static FluidStack fromForge(net.minecraftforge.fluids.FluidStack stack) {
return FluidStack.create(stack.getFluid().delegate, Fraction.ofWhole(stack.getAmount()), stack.getTag());

View File

@@ -33,7 +33,6 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor;

View File

@@ -25,7 +25,8 @@ import java.util.*;
import java.util.function.Consumer;
public final class EventBuses {
private EventBuses() {}
private EventBuses() {
}
private static final Map<String, IEventBus> EVENT_BUS_MAP = new HashMap<>();
private static final Map<String, List<Consumer<IEventBus>>> ON_REGISTERED = new HashMap<>();

View File

@@ -27,7 +27,6 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraftforge.event.entity.EntityAttributeCreationEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

View File

@@ -157,7 +157,9 @@ public class BiomeModificationsImpl {
private static class GenerationSettingsBuilderWrapped implements GenerationProperties {
protected final BiomeGenerationSettingsBuilder generation;
public GenerationSettingsBuilderWrapped(BiomeGenerationSettingsBuilder generation) {this.generation = generation;}
public GenerationSettingsBuilderWrapped(BiomeGenerationSettingsBuilder generation) {
this.generation = generation;
}
@Override
public @NotNull Optional<Supplier<ConfiguredSurfaceBuilder<?>>> getSurfaceBuilder() {
@@ -184,7 +186,9 @@ public class BiomeModificationsImpl {
private static class SpawnSettingsBuilderWrapped implements SpawnProperties {
protected final MobSpawnInfoBuilder builder;
public SpawnSettingsBuilderWrapped(MobSpawnInfoBuilder builder) {this.builder = builder;}
public SpawnSettingsBuilderWrapped(MobSpawnInfoBuilder builder) {
this.builder = builder;
}
@Override
public float getCreatureProbability() {

View File

@@ -26,7 +26,8 @@ import net.minecraft.world.level.GameRules;
import java.util.function.BiConsumer;
public class GameRuleFactoryImpl {
private GameRuleFactoryImpl() {}
private GameRuleFactoryImpl() {
}
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue) {
return GameRulesAccessor.BooleanValueSimple.invokeCreateArchitectury(defaultValue);

View File

@@ -0,0 +1,75 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.trade.forge;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import me.shedaniel.architectury.forge.ArchitecturyForge;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerTrades;
import net.minecraftforge.event.village.VillagerTradesEvent;
import net.minecraftforge.event.village.WandererTradesEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.*;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
public class TradeRegistryImpl {
private static final Map<VillagerProfession, Int2ObjectMap<List<VillagerTrades.ItemListing>>> TRADES_TO_ADD = new HashMap<>();
private static final List<VillagerTrades.ItemListing> WANDERER_TRADER_TRADES_GENERIC = new ArrayList<>();
private static final List<VillagerTrades.ItemListing> WANDERER_TRADER_TRADES_RARE = new ArrayList<>();
public static void registerVillagerTrade0(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
Int2ObjectMap<List<VillagerTrades.ItemListing>> tradesForProfession = TRADES_TO_ADD.computeIfAbsent(profession, $ -> new Int2ObjectOpenHashMap<>());
List<VillagerTrades.ItemListing> tradesForLevel = tradesForProfession.computeIfAbsent(level, $ -> new ArrayList<>());
Collections.addAll(tradesForLevel, trades);
}
public static void registerTradeForWanderingTrader(boolean rare, VillagerTrades.ItemListing... trades) {
if (rare) {
Collections.addAll(WANDERER_TRADER_TRADES_RARE, trades);
} else {
Collections.addAll(WANDERER_TRADER_TRADES_GENERIC, trades);
}
}
@SubscribeEvent
public static void onTradeRegistering(VillagerTradesEvent event) {
Int2ObjectMap<List<VillagerTrades.ItemListing>> trades = TRADES_TO_ADD.get(event.getType());
if (trades != null) {
for (Int2ObjectMap.Entry<List<VillagerTrades.ItemListing>> entry : trades.int2ObjectEntrySet()) {
event.getTrades().computeIfAbsent(entry.getIntKey(), $ -> NonNullList.create()).addAll(entry.getValue());
}
}
}
@SubscribeEvent
public static void onWanderingTradeRegistering(WandererTradesEvent event) {
if (!WANDERER_TRADER_TRADES_GENERIC.isEmpty()) {
event.getGenericTrades().addAll(WANDERER_TRADER_TRADES_GENERIC);
}
if (!WANDERER_TRADER_TRADES_RARE.isEmpty()) {
event.getRareTrades().addAll(WANDERER_TRADER_TRADES_RARE);
}
}
}

View File

@@ -11,7 +11,7 @@ authors = "shedaniel"
description = '''
A intermediary api aimed to ease developing multiplatform mods.
'''
logoFile="icon.png"
logoFile = "icon.png"
license = "LGPL-3"
[[dependencies.architectury]]

View File

@@ -7,9 +7,17 @@
"client": [
],
"mixins": [
"BiomeGenerationSettingsBuilderAccessor", "GameRulesAccessor", "GameRulesAccessor$BooleanValue", "GameRulesAccessor$BooleanValueSimple",
"GameRulesAccessor$IntegerValue", "GameRulesAccessor$IntegerValueSimple", "MixinBlockEntity", "MixinBlockEntityExtension", "MixinItemExtension",
"MixinRegistryEntry", "MobSpawnSettingsBuilderAccessor"
"BiomeGenerationSettingsBuilderAccessor",
"GameRulesAccessor",
"GameRulesAccessor$BooleanValue",
"GameRulesAccessor$BooleanValueSimple",
"GameRulesAccessor$IntegerValue",
"GameRulesAccessor$IntegerValueSimple",
"MixinBlockEntity",
"MixinBlockEntityExtension",
"MixinItemExtension",
"MixinRegistryEntry",
"MobSpawnSettingsBuilderAccessor"
],
"injectors": {
"defaultRequire": 1

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -28,6 +28,7 @@ import me.shedaniel.architectury.test.gamerule.TestGameRules;
import me.shedaniel.architectury.test.registry.TestRegistries;
import me.shedaniel.architectury.test.registry.client.TestKeybinds;
import me.shedaniel.architectury.test.tags.TestTags;
import me.shedaniel.architectury.test.trade.TestTrades;
import me.shedaniel.architectury.utils.Env;
import me.shedaniel.architectury.utils.EnvExecutor;
@@ -40,6 +41,7 @@ public class TestMod {
TestRegistries.initialize();
TestGameRules.init();
TestTags.initialize();
TestTrades.init();
if (Platform.getEnvironment() == Env.CLIENT)
TestKeybinds.initialize();
}

View File

@@ -29,7 +29,6 @@ import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.Env;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.screens.ChatScreen;
import net.minecraft.client.gui.screens.inventory.AnvilScreen;
import net.minecraft.core.Position;
import net.minecraft.core.Vec3i;

View File

@@ -28,11 +28,12 @@ import static me.shedaniel.architectury.registry.GameRuleRegistry.register;
public class TestGameRules {
private static final Logger LOGGER = LogManager.getLogger();
public static final GameRules.Key<GameRules.BooleanValue> SIMPLE_BOOL = register("simpleBool", GameRules.Category.MISC, GameRuleFactory.createBooleanRule(true));
public static final GameRules.Key<GameRules.IntegerValue> SIMPLE_INT = register("simpleInt", GameRules.Category.MISC, GameRuleFactory.createIntRule(10));
public static final GameRules.Key<GameRules.BooleanValue> CALLBACK_BOOL = register("callbackBool", GameRules.Category.MISC, GameRuleFactory.createBooleanRule(true, (server, value) -> LOGGER.info("changed to {}", value.get())));
public static final GameRules.Key<GameRules.IntegerValue> CALLBACK_INT = register("callbackInt", GameRules.Category.MISC, GameRuleFactory.createIntRule(10, (server, value) -> LOGGER.info("changed to {}", value.get())));
public static void init() {}
public static void init() {
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.test.trade;
import me.shedaniel.architectury.registry.trade.SimpleTrade;
import me.shedaniel.architectury.registry.trade.TradeRegistry;
import net.minecraft.core.Registry;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerTrades;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
public class TestTrades {
public static void init() {
for (VillagerProfession villagerProfession : Registry.VILLAGER_PROFESSION) {
TradeRegistry.registerVillagerTrade(villagerProfession, 1, TestTrades.createTrades());
}
TradeRegistry.registerTradeForWanderingTrader(false, TestTrades.createTrades());
}
private static VillagerTrades.ItemListing[] createTrades() {
SimpleTrade trade = new SimpleTrade(Items.APPLE.getDefaultInstance(), ItemStack.EMPTY, Items.ACACIA_BOAT.getDefaultInstance(), 1, 0, 1.0F);
return new VillagerTrades.ItemListing[]{trade};
}
}

View File

@@ -1,6 +1,6 @@
{
"replace": false,
"values": [
"minecraft:emerald_block"
]
"replace": false,
"values": [
"minecraft:emerald_block"
]
}

View File

@@ -12,7 +12,7 @@ dependencies {
minecraft "com.mojang:minecraft:${rootProject.architectury.minecraft}"
mappings loom.officialMojangMappings()
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
implementation project(path: ":fabric", configuration: "dev")
implementation(project(path: ":common")) {

View File

@@ -5,7 +5,7 @@ plugins {
loom {
mixinConfig "architectury.mixins.json"
localMods {
it.add(project(":forge").sourceSets.main)
}

View File

@@ -1 +1 @@
loom.platform=forge
loom.platform=forge