Compare commits
154 Commits
5.24.0+1.2
...
1.20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
667ac6c6ee | ||
|
|
2d760eecbb | ||
|
|
292a6aeab3 | ||
|
|
7fbfcf1a92 | ||
|
|
1bcb28a1ad | ||
|
|
d51b0f60a2 | ||
|
|
ab9880159e | ||
|
|
0f94634361 | ||
|
|
f1492cc829 | ||
|
|
0ecee529d7 | ||
|
|
e9bfd96dd9 | ||
|
|
fb9dcf77c6 | ||
|
|
33851c1cb6 | ||
|
|
494203ef5a | ||
|
|
74f76f7305 | ||
|
|
62dbbea083 | ||
|
|
538c52bc2a | ||
|
|
b62eb1845b | ||
|
|
7c45564979 | ||
|
|
f8d2425242 | ||
|
|
50cedfc699 | ||
|
|
f4f596ca0c | ||
|
|
85aab426c5 | ||
|
|
29ff5f152e | ||
|
|
8213a720a3 | ||
|
|
afe3e09a27 | ||
|
|
ae20fa17c9 | ||
|
|
a6c03e9928 | ||
|
|
864c751aea | ||
|
|
f931d5c442 | ||
|
|
55cec86e5f | ||
|
|
4ec8ef753a | ||
|
|
3f22e23565 | ||
|
|
a73dd5ef6a | ||
|
|
653a477060 | ||
|
|
44113d2536 | ||
|
|
1165d3bdd1 | ||
|
|
c73cdc49a4 | ||
|
|
4e3ecf9b6d | ||
|
|
a40363c1fb | ||
|
|
46dd5ecddd | ||
|
|
b765bcb51f | ||
|
|
26bd7116a1 | ||
|
|
4d2f0da1fc | ||
|
|
c2f585da95 | ||
|
|
327c3cd9ff | ||
|
|
c64ca2e54b | ||
|
|
85955ebf75 | ||
|
|
d749205427 | ||
|
|
438ceb1984 | ||
|
|
5acb5115b9 | ||
|
|
37dc9e60eb | ||
|
|
c2191df359 | ||
|
|
d08da1b3c8 | ||
|
|
36f425b8cd | ||
|
|
dc3c379049 | ||
|
|
4ff7d4c554 | ||
|
|
db13f39b30 | ||
|
|
5a9c49f8d4 | ||
|
|
8ee85f2c16 | ||
|
|
2081b63b56 | ||
|
|
94f1fbf4db | ||
|
|
ab8a8068e0 | ||
|
|
79d2b28d5b | ||
|
|
18dc488ab9 | ||
|
|
a9340b2642 | ||
|
|
670e06816b | ||
|
|
53349cbd1a | ||
|
|
1794c81b61 | ||
|
|
dbe9acb3d8 | ||
|
|
22915a91a1 | ||
|
|
1289897004 | ||
|
|
9692da12b4 | ||
|
|
e34a99b38c | ||
|
|
f79eae8b83 | ||
|
|
38288d5e6a | ||
|
|
2050516bf1 | ||
|
|
02f486ebf4 | ||
|
|
9edce9ad91 | ||
|
|
ac8d93d5b9 | ||
|
|
bee4536c1a | ||
|
|
da2206168b | ||
|
|
17f930ea6f | ||
|
|
f23348c6cb | ||
|
|
21cbcb0e04 | ||
|
|
925c7526ee | ||
|
|
30e3deb8e2 | ||
|
|
ee34dcf96e | ||
|
|
49d800ff27 | ||
|
|
15f30b532c | ||
|
|
df06010846 | ||
|
|
696b344ef5 | ||
|
|
e63d99763e | ||
|
|
60850610f9 | ||
|
|
e16179b797 | ||
|
|
784b914a43 | ||
|
|
b9933b1158 | ||
|
|
878b3798f3 | ||
|
|
bc0e9a09fc | ||
|
|
8c34c0de50 | ||
|
|
5a93bc6109 | ||
|
|
8125da7882 | ||
|
|
d699187006 | ||
|
|
cff29149db | ||
|
|
3926f27d33 | ||
|
|
9bc5f06a19 | ||
|
|
a70f76a34d | ||
|
|
4dcdf09a01 | ||
|
|
f26d35070e | ||
|
|
a04266df54 | ||
|
|
2ec6a6afbc | ||
|
|
49f5b527db | ||
|
|
00287612de | ||
|
|
4b18cc2cc6 | ||
|
|
b2ed5b9341 | ||
|
|
a30dd08cd1 | ||
|
|
7420a7c7ab | ||
|
|
3f9148fa62 | ||
|
|
8cc41fa222 | ||
|
|
f06fb8c32e | ||
|
|
6ee15122f9 | ||
|
|
c9843e08bd | ||
|
|
7b47c39e6b | ||
|
|
b26ab375b5 | ||
|
|
9c4da7fa68 | ||
|
|
d64a1c760b | ||
|
|
555213714f | ||
|
|
7f27141a16 | ||
|
|
a8227a964d | ||
|
|
a7a9aac23a | ||
|
|
1176cc98e3 | ||
|
|
a7622f58ae | ||
|
|
67814db6ad | ||
|
|
8959c2ff91 | ||
|
|
a6eb99d23c | ||
|
|
fd46baae21 | ||
|
|
273bab7856 | ||
|
|
8133198cc2 | ||
|
|
25976f3b87 | ||
|
|
f71277eb64 | ||
|
|
b30b319214 | ||
|
|
e411f11c0c | ||
|
|
e30a7fccf2 | ||
|
|
12a0414f61 | ||
|
|
44322a7d07 | ||
|
|
8d4a7c3374 | ||
|
|
29c1a479a4 | ||
|
|
ee6489fb69 | ||
|
|
87c977a3e6 | ||
|
|
54e55e7534 | ||
|
|
65ab37b819 | ||
|
|
873e3bd676 | ||
|
|
6b37051980 | ||
|
|
cf5c81f7e2 |
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -4,51 +4,75 @@ body:
|
|||
- type: markdown
|
||||
attributes:
|
||||
value: >-
|
||||
**Note: This issue tracker is not intended for support requests!** If you need help with crashes or other issues, then
|
||||
you should [ask on our Discord server](https://discord.gg/rN9Y7caguP) instead. Unless you are certain that you
|
||||
have found a defect, and you are able to point to where the problem is, you should not open an issue.
|
||||
<br><br>
|
||||
Additionally, please make sure you have done the following:
|
||||
**Need help?** Ask on [Discord](https://discord.gg/rN9Y7caguP) instead of opening an issue.
|
||||
|
||||
- **Have you ensured that all of your mods (including ModernFix) are up-to-date?** The latest version of ModernFix
|
||||
can always be found [on Modrinth](https://modrinth.com/mod/modernfix).
|
||||
|
||||
- **Have you used the [search tool](https://github.com/embeddedt/ModernFix/issues) to check whether your issue
|
||||
has already been reported?** If it has been, then consider adding more information to the existing issue instead.
|
||||
|
||||
- **Have you determined the minimum set of instructions to reproduce the issue?** If your problem only occurs
|
||||
with other mods installed, then you should narrow down exactly which mods are causing the issue. Please do not
|
||||
provide your entire list of mods to us and expect that we will be able to figure out the problem.
|
||||
**Issues that do not meet the requirements below (or are otherwise impossible to address with the given info) will be closed without investigation.**
|
||||
- type: checkboxes
|
||||
id: confirmations
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: I am reporting a defect, not asking for help
|
||||
required: true
|
||||
- label: I have searched existing issues and this has not been reported
|
||||
required: true
|
||||
- label: I have reduced my mod list to the minimum required to reproduce this issue (see below)
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: >-
|
||||
Use this section to describe the issue you are experiencing in as much depth as possible. The description should
|
||||
explain what behavior you were expecting, and why you believe the issue to be a bug. If the issue you are reporting
|
||||
only occurs with specific mods installed, then provide the name and version of each mod.
|
||||
Describe the issue in detail. Be sure to include what you expected to happen and what actually happened.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: minimal-mods
|
||||
attributes:
|
||||
label: Minimal Mod List
|
||||
description: >-
|
||||
List ONLY the mods required to reproduce this issue. Maintainers have debugging tools that help them
|
||||
locate problems quickly, but these generally don't work well in modpacks or large mod sets.
|
||||
A minimal list should typically contain fewer than 10 mods.
|
||||
|
||||
**Hint:** If you have any screenshots, videos, or other information that you feel is necessary to
|
||||
explain the issue, you can attach them here.
|
||||
Reports with large mod lists will likely be closed without investigation, unless the problem is very clear.
|
||||
|
||||
If you don't know which mods are causing your problem, use binary search:
|
||||
|
||||
1. Remove half your mods
|
||||
|
||||
2. Test if the issue still occurs
|
||||
|
||||
3. If yes, remove half again. If no, restore the last removed half and repeat from step 1.
|
||||
|
||||
4. Repeat until only the necessary mods remain
|
||||
placeholder: "- ModernFix 5.x.x\n- SomeMod 1.2.3"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description-reproduction-steps
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: >-
|
||||
Provide as much information as possible on how to reproduce this bug. Make sure your instructions are as clear and
|
||||
concise as possible, because other people will need to be able to follow your guide in order to re-create the issue.
|
||||
|
||||
**Hint:** A common way to fill this section out is to write a step-by-step guide.
|
||||
Provide clear steps to reproduce the bug. Each step should be a single concrete action.
|
||||
|
||||
Maintainers are busy and need to be able to quickly replicate your problem. Your reproduction steps should be
|
||||
clear enough for someone who is unfamiliar with your mods to follow in 5 minutes or less (not counting time
|
||||
to launch the game).
|
||||
|
||||
Providing vague steps is likely to result in the issue being closed.
|
||||
|
||||
placeholder: "1. \n2. \n3. "
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log-file
|
||||
id: diagnostic-info
|
||||
attributes:
|
||||
label: Log File
|
||||
label: Diagnostic Info
|
||||
description: >-
|
||||
**Hint:** You can usually find the log files within the folder `.minecraft/logs`. Most often, you will want the `latest.log`
|
||||
file, since that file belongs to the last played session of the game.
|
||||
placeholder: >-
|
||||
Drag-and-drop the log file here.
|
||||
Drag and drop `latest.log` from `.minecraft/logs/` for the session where the issue occurred.
|
||||
Do not paste log text inline. Issues without a valid `latest.log` will be closed.
|
||||
|
||||
If a crash occurred, also attach the relevant file from `.minecraft/crash-reports/`.
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
|||
109
.github/workflows/gradle.yml
vendored
109
.github/workflows/gradle.yml
vendored
|
|
@ -11,6 +11,11 @@ on:
|
|||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
issues: write
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -22,20 +27,108 @@ jobs:
|
|||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
check-latest: true
|
||||
- name: Check if release branch
|
||||
id: check_branch
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" =~ ^refs/heads/[0-9]+\. ]]; then
|
||||
echo "is_release=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_release=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
with:
|
||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') }}
|
||||
cache-read-only: ${{ steps.check_branch.outputs.is_release != 'true' }}
|
||||
gradle-home-cache-cleanup: true
|
||||
- name: Setup project Loom cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.gradle/loom-cache
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle.properties', '**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
- name: Remove tags for release on other versions
|
||||
if: steps.check_branch.outputs.is_release == 'true'
|
||||
run: ./scripts/tagcleaner.sh
|
||||
- name: Build ModernFix using Gradle
|
||||
run: ./gradlew build
|
||||
- name: Run mixin audit
|
||||
run: timeout 60 xvfb-run ./gradlew runAuditClient
|
||||
- name: Publish mod to CurseForge & Modrinth
|
||||
if: steps.check_branch.outputs.is_release == 'true'
|
||||
run: ./gradlew publishMods copyJarToBin
|
||||
env:
|
||||
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
- name: Capture mod version
|
||||
if: steps.check_branch.outputs.is_release == 'true'
|
||||
run: |
|
||||
echo "MOD_VERSION=$(./gradlew properties -q | grep '^version:' | awk '{print $2}')" >> $GITHUB_ENV
|
||||
echo "MC_VERSION=$(grep '^minecraft_version=' gradle.properties | cut -d= -f2)" >> $GITHUB_ENV
|
||||
- name: Comment on fixed issues
|
||||
if: steps.check_branch.outputs.is_release == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const branch = context.ref.replace('refs/heads/', '');
|
||||
const { data: runs } = await github.rest.actions.listWorkflowRuns({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'gradle.yml',
|
||||
branch,
|
||||
status: 'success',
|
||||
per_page: 1
|
||||
});
|
||||
|
||||
const logArgs = runs.workflow_runs.length > 0
|
||||
? `${runs.workflow_runs[0].head_sha}..${context.sha}`
|
||||
: `-1 ${context.sha}`;
|
||||
const log = execSync(`git log ${logArgs} --format=%s%n%b`, { encoding: 'utf8' });
|
||||
|
||||
const issueNumbers = new Set();
|
||||
const pattern = /(?:fix(?:es|ed)?|close[sd]?|resolve[sd]?)\s+#(\d+)/gi;
|
||||
let match;
|
||||
while ((match = pattern.exec(log)) !== null) {
|
||||
issueNumbers.add(parseInt(match[1]));
|
||||
}
|
||||
|
||||
if (issueNumbers.size === 0) {
|
||||
console.log('No fixed issues found in commits');
|
||||
return;
|
||||
}
|
||||
|
||||
const MARKER = '<!-- modernfix-fix-tracker -->';
|
||||
const modVersion = process.env.MOD_VERSION;
|
||||
const mcVersion = process.env.MC_VERSION;
|
||||
const newLine = `- ${modVersion} for Minecraft ${mcVersion}`;
|
||||
|
||||
for (const issueNumber of issueNumbers) {
|
||||
try {
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
per_page: 100
|
||||
});
|
||||
|
||||
const existing = comments.find(c => c.body.includes(MARKER));
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body: existing.body + `\n${newLine}`
|
||||
});
|
||||
console.log(`Updated comment on issue #${issueNumber}`);
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
body: `${MARKER}\nThe fix for this issue has been released in the following versions of ModernFix:\n${newLine}`
|
||||
});
|
||||
console.log(`Created comment on issue #${issueNumber}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`Could not comment on #${issueNumber}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
- name: Upload Artifacts to GitHub
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
|
|||
41
.github/workflows/release.yml
vendored
41
.github/workflows/release.yml
vendored
|
|
@ -1,41 +0,0 @@
|
|||
name: Release ModernFix Artifacts
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.repository_owner == 'embeddedt'
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
check-latest: true
|
||||
- name: Remove tags for release on other versions
|
||||
run: ./scripts/tagcleaner.sh
|
||||
- name: Build and publish mod to CurseForge & Modrinth
|
||||
run: ./gradlew publishToModSites copyJarToBin
|
||||
env:
|
||||
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
- name: Upload assets to GitHub
|
||||
uses: AButler/upload-release-assets@v3.0
|
||||
with:
|
||||
files: 'bin/*'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Add changelog to release
|
||||
uses: irongut/EditRelease@v1.2.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
id: ${{ github.event.release.id }}
|
||||
replacebody: true
|
||||
files: "CHANGELOG.md"
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
plugins {
|
||||
id 'com.github.johnrengelman.shadow'
|
||||
id 'com.gradleup.shadow' version '8.3.9'
|
||||
id 'java-library'
|
||||
id 'com.diffplug.spotless'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
@ -31,7 +30,7 @@ dependencies {
|
|||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.release = 21
|
||||
options.release = 17
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
|
|
@ -52,9 +51,4 @@ shadowJar {
|
|||
include {it.getName() == 'EnvType.class'}
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
removeUnusedImports()
|
||||
}
|
||||
}
|
||||
version = '1.1.4'
|
||||
|
|
|
|||
|
|
@ -90,24 +90,19 @@ public class ClientMixinValidator {
|
|||
}
|
||||
|
||||
private boolean targetsClient(Object classTarget) {
|
||||
return switch (classTarget) {
|
||||
case TypeElement te ->
|
||||
isClientMarked(te);
|
||||
case TypeMirror tm -> {
|
||||
var el = types.asElement(tm);
|
||||
yield el != null ? targetsClient(el) : warn("TypeMirror of " + tm);
|
||||
}
|
||||
// If you're using a dollar sign in class names you are insane
|
||||
case String s -> {
|
||||
var te =
|
||||
elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
|
||||
yield te != null ? targetsClient(te) : warn(s);
|
||||
}
|
||||
default ->
|
||||
throw new IllegalArgumentException("Unhandled type: "
|
||||
if (classTarget instanceof TypeElement te) {
|
||||
return isClientMarked(te);
|
||||
} else if (classTarget instanceof TypeMirror tm) {
|
||||
var el = types.asElement(tm);
|
||||
return el != null ? targetsClient(el) : warn("TypeMirror of " + tm);
|
||||
} else if (classTarget instanceof String s) {
|
||||
var te = elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
|
||||
return te != null ? targetsClient(te) : warn(s);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unhandled type: "
|
||||
+ classTarget.getClass() + "\n" + "Stringified contents: "
|
||||
+ classTarget.toString());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isClientMarked(TypeElement te) {
|
||||
|
|
@ -166,7 +161,6 @@ public class ClientMixinValidator {
|
|||
|
||||
clzsses = wrappedClzss.stream()
|
||||
.map(AnnotationValue::getValue)
|
||||
.filter(o -> o instanceof TypeMirror)
|
||||
.map(TypeMirror.class::cast)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public record MixinConfig(
|
|||
InjectorOptions injectors, OverwriteOptions overwrites
|
||||
) {
|
||||
public MixinConfig(String packageName, List<String> commonMixins, List<String> clientMixins) {
|
||||
this(true, "0.8", packageName, "org.embeddedt.modernfix.core.ModernFixMixinPlugin", "JAVA_21",
|
||||
this(true, "0.8", packageName, "org.embeddedt.modernfix.core.ModernFixMixinPlugin", "JAVA_17",
|
||||
commonMixins, clientMixins, InjectorOptions.DEFAULT, OverwriteOptions.DEFAULT);
|
||||
}
|
||||
public record InjectorOptions(int defaultRequire) {
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
plugins {
|
||||
id 'modernfix.common-conventions'
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
version = '1.1.0'
|
||||
10
annotations/build.gradle.kts
Normal file
10
annotations/build.gradle.kts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
plugins {
|
||||
id("java")
|
||||
}
|
||||
|
||||
version = "1.1.0"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package org.embeddedt.modernfix.annotation;
|
||||
|
||||
public enum FeatureLevel {
|
||||
GA, BETA;
|
||||
|
||||
public boolean isAtLeast(FeatureLevel required) {
|
||||
return this.ordinal() >= required.ordinal();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.embeddedt.modernfix.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.TYPE, ElementType.PACKAGE})
|
||||
public @interface RequiresFeatureLevel {
|
||||
FeatureLevel value() default FeatureLevel.GA;
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.TYPE)
|
||||
@Target({ElementType.TYPE, ElementType.PACKAGE})
|
||||
public @interface RequiresMod {
|
||||
String value() default "";
|
||||
}
|
||||
|
|
|
|||
67
build.gradle
67
build.gradle
|
|
@ -1,67 +0,0 @@
|
|||
plugins {
|
||||
id "architectury-plugin" version "3.4-SNAPSHOT"
|
||||
id "dev.architectury.loom" version "1.9-SNAPSHOT" apply false
|
||||
id "maven-publish"
|
||||
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
|
||||
id 'com.palantir.git-version' version '1.0.0'
|
||||
id 'org.ajoberstar.grgit' version '5.2.0'
|
||||
id 'se.bjurr.gitchangelog.git-changelog-gradle-plugin' version '1.79.0'
|
||||
id "com.modrinth.minotaur" version "2.+" apply false
|
||||
id("com.diffplug.spotless") version "6.25.0" apply false
|
||||
id 'modernfix.common-conventions' apply false
|
||||
}
|
||||
|
||||
architectury {
|
||||
minecraft = rootProject.minecraft_version
|
||||
}
|
||||
|
||||
ext.archives_base_name = 'modernfix'
|
||||
|
||||
apply plugin: 'modernfix.common-conventions'
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
options.encoding = "UTF-8"
|
||||
|
||||
// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
|
||||
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
|
||||
// We'll use that if it's available, but otherwise we'll use the older option.
|
||||
def targetVersion = 8
|
||||
/*
|
||||
if (JavaVersion.current().isJava9Compatible()) {
|
||||
options.release = targetVersion
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
tasks.register('generateChangelog', se.bjurr.gitchangelog.plugin.gradle.GitChangelogTask) {
|
||||
def details = versionDetails();
|
||||
def theVersionRef
|
||||
if (details.commitDistance > 0) {
|
||||
theVersionRef = details.lastTag;
|
||||
} else {
|
||||
def secondLastTagCmd = "git describe --abbrev=0 " + details.lastTag + "^"
|
||||
def secondLastTag = secondLastTagCmd.execute().text.trim()
|
||||
theVersionRef = secondLastTag;
|
||||
}
|
||||
|
||||
fromRef = theVersionRef
|
||||
|
||||
file = new File("${rootDir}/CHANGELOG.md");
|
||||
templateContent = new File("${rootDir}/gradle/changelog.mustache").getText('UTF-8').replace("[[modernFixVersionRef]]", theVersionRef);
|
||||
toCommit = "HEAD";
|
||||
}
|
||||
|
||||
tasks.register('checkCleanTag') {
|
||||
doLast {
|
||||
def details = versionDetails()
|
||||
if (!details.isCleanTag || versionDetails().commitDistance != 0) {
|
||||
throw new GradleException('Not a clean tree.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println "ModernFix: " + version
|
||||
210
build.gradle.kts
Normal file
210
build.gradle.kts
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
plugins {
|
||||
id("net.neoforged.moddev.legacyforge") version("2.0.134")
|
||||
id("me.modmuss50.mod-publish-plugin") version("1.1.0")
|
||||
}
|
||||
|
||||
val minecraft_version = rootProject.properties["minecraft_version"].toString()
|
||||
|
||||
group = "org.embeddedt"
|
||||
|
||||
val gitVersion = providers.of(GitVersionSource::class) {
|
||||
parameters {
|
||||
minecraftVersion.set(minecraft_version)
|
||||
projectDir.set(rootProject.layout.projectDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
version = gitVersion.get()
|
||||
|
||||
base.archivesName = "modernfix-forge"
|
||||
|
||||
legacyForge {
|
||||
enable {
|
||||
forgeVersion = rootProject.properties["forge_version"].toString()
|
||||
isDisableRecompilation = System.getenv("CI") == "true"
|
||||
}
|
||||
|
||||
rootProject.properties["parchment_version"]?.let { parchmentVer ->
|
||||
parchment {
|
||||
minecraftVersion = minecraft_version
|
||||
mappingsVersion = parchmentVer.toString()
|
||||
}
|
||||
}
|
||||
|
||||
runs {
|
||||
create("client") {
|
||||
client()
|
||||
}
|
||||
create("server") {
|
||||
server()
|
||||
}
|
||||
create("auditClient") {
|
||||
client()
|
||||
jvmArguments.addAll("-Dmodernfix.auditAndExit=true", "-Djava.awt.headless=true")
|
||||
}
|
||||
}
|
||||
|
||||
mods {
|
||||
create("modernfix") {
|
||||
sourceSet(sourceSets.main.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin {
|
||||
add(sourceSets.main.get(), "modernfix.refmap.json")
|
||||
config("modernfix-modernfix.mixins.json")
|
||||
}
|
||||
|
||||
tasks.named<Jar>("jar") {
|
||||
manifest.attributes(mapOf(
|
||||
"MixinConfigs" to "modernfix-modernfix.mixins.json",
|
||||
"Specification-Version" to "1",
|
||||
"Implementation-Title" to project.name,
|
||||
"Implementation-Version" to version
|
||||
))
|
||||
}
|
||||
|
||||
java {
|
||||
val curSourceCompatLevel = JavaVersion.VERSION_17
|
||||
sourceCompatibility = curSourceCompatLevel
|
||||
targetCompatibility = curSourceCompatLevel
|
||||
}
|
||||
|
||||
repositories {
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
// location of the maven that hosts JEI files
|
||||
name = "Progwml6 maven"
|
||||
url = uri("https://dvs1.progwml6.com/files/maven/")
|
||||
}
|
||||
}
|
||||
forRepository {
|
||||
maven {
|
||||
name = "ModMaven"
|
||||
url = uri("https://modmaven.dev")
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup("mezz.jei")
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven("https://cursemaven.com")
|
||||
}
|
||||
filter {
|
||||
includeGroup("curse.maven")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val embed by configurations.creating {
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
isTransitive = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":annotations"))
|
||||
embed(project(":annotations"))
|
||||
"additionalRuntimeClasspath"(project(":annotations"))
|
||||
annotationProcessor(project(path = ":annotation-processor", configuration = "shadow"))
|
||||
|
||||
val mixinextrasVersion = rootProject.properties["mixinextras_version"].toString()
|
||||
implementation("io.github.llamalad7:mixinextras-common:${mixinextrasVersion}")
|
||||
annotationProcessor("net.fabricmc:sponge-mixin:0.12.5+mixin.0.8.5")
|
||||
annotationProcessor("io.github.llamalad7:mixinextras-common:${mixinextrasVersion}")
|
||||
implementation("io.github.llamalad7:mixinextras-forge:${mixinextrasVersion}")
|
||||
"jarJar"("io.github.llamalad7:mixinextras-forge:${mixinextrasVersion}")
|
||||
|
||||
val jei_version = rootProject.properties["jei_version"].toString()
|
||||
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
||||
modCompileOnly("curse.maven:spark-361579:${rootProject.properties["spark_version"].toString()}")
|
||||
modCompileOnly("curse.maven:ctm-267602:${rootProject.properties["ctm_version"].toString()}")
|
||||
modCompileOnly("curse.maven:ldlib-626676:${rootProject.properties["ldlib_version"].toString()}")
|
||||
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
|
||||
modCompileOnly("curse.maven:patchouli-306770:6164575")
|
||||
modCompileOnly("curse.maven:cofhcore-69162:5374122")
|
||||
modCompileOnly("curse.maven:resourcefullib-570073:5659871")
|
||||
modCompileOnly("curse.maven:kubejs-238086:5853326")
|
||||
modCompileOnly("curse.maven:terrablender-563928:6290448")
|
||||
}
|
||||
|
||||
tasks.named<Jar>("jar") {
|
||||
from(embed.map { if (it.isDirectory) it else zipTree(it) })
|
||||
}
|
||||
|
||||
// For the AP
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
if (!name.lowercase().contains("test")) {
|
||||
options.compilerArgs.addAll(
|
||||
listOf(
|
||||
"-ArootProject.name=${rootProject.name}",
|
||||
"-Aproject.name=${project.name}"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources.srcDir(
|
||||
layout.buildDirectory.dir("generated/sources/annotationProcessor/java/main/resources")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<ProcessResources>("processResources") {
|
||||
dependsOn(tasks.named("compileJava"))
|
||||
|
||||
inputs.property("version", project.version)
|
||||
|
||||
filesMatching("META-INF/mods.toml") {
|
||||
expand("version" to project.version)
|
||||
}
|
||||
}
|
||||
|
||||
val finalJarTask = "reobfJar"
|
||||
|
||||
tasks.register<Copy>("copyJarNameConsistent") {
|
||||
from(tasks.named<Jar>(finalJarTask).get().outputs.files)
|
||||
into(project.file("build/libs"))
|
||||
rename { _ -> "modernfix-" + project.name + "-latest.jar" }
|
||||
}
|
||||
|
||||
tasks.register<Copy>("copyJarToBin") {
|
||||
from(tasks.named<Jar>(finalJarTask).get().outputs.files)
|
||||
into(rootProject.file("bin"))
|
||||
mustRunAfter(tasks.named("copyJarNameConsistent"))
|
||||
}
|
||||
|
||||
tasks.named("build") {
|
||||
dependsOn("copyJarToBin", "copyJarNameConsistent")
|
||||
}
|
||||
|
||||
publishMods {
|
||||
file.set(tasks.named<Jar>(finalJarTask).flatMap { it.archiveFile })
|
||||
displayName.set(tasks.named<Jar>(finalJarTask).flatMap { it.archiveFileName })
|
||||
changelog = "Please check the [GitHub wiki](https://github.com/embeddedt/ModernFix/wiki/Changelog) for major changes."
|
||||
type = STABLE
|
||||
|
||||
modLoaders.add("forge")
|
||||
|
||||
curseforge {
|
||||
projectId = "790626"
|
||||
projectSlug = "modernfix"
|
||||
accessToken = providers.environmentVariable("CURSEFORGE_TOKEN")
|
||||
minecraftVersions.add(minecraft_version)
|
||||
}
|
||||
modrinth {
|
||||
projectId = "nmDcB62a"
|
||||
accessToken = providers.environmentVariable("MODRINTH_TOKEN")
|
||||
minecraftVersions.add(minecraft_version)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("publishMods") {
|
||||
dependsOn(finalJarTask)
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
}
|
||||
7
buildSrc/build.gradle.kts
Normal file
7
buildSrc/build.gradle.kts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'architectury-plugin'
|
||||
id 'maven-publish'
|
||||
id 'com.diffplug.spotless'
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
removeUnusedImports()
|
||||
}
|
||||
}
|
||||
|
||||
architectury {
|
||||
compileOnly()
|
||||
}
|
||||
|
||||
group = 'org.embeddedt'
|
||||
// extract base version from tag, generate other metadata ourselves
|
||||
def details = versionDetails()
|
||||
def plusIndex = details.lastTag.indexOf("+")
|
||||
if(plusIndex == -1) {
|
||||
plusIndex = details.lastTag.length()
|
||||
}
|
||||
def baseVersion = details.lastTag.substring(0, plusIndex)
|
||||
def dirtyMarker = grgit.status().clean ? "" : ".dirty"
|
||||
def commitHashMarker = details.commitDistance > 0 ? ("." + details.gitHash.substring(0, Math.min(4, details.gitHash.length()))) : ""
|
||||
def preMarker = (details.commitDistance > 0 || !details.isCleanTag) ? ("-beta." + details.commitDistance) : ""
|
||||
if(preMarker.length() > 0) {
|
||||
// bump to next patch release
|
||||
def versionParts = baseVersion.tokenize(".")
|
||||
baseVersion = "${versionParts[0]}.${versionParts[1]}.${versionParts[2].toInteger() + 1}"
|
||||
}
|
||||
def versionString = "${baseVersion}${preMarker}+mc${minecraft_version}${commitHashMarker}${dirtyMarker}"
|
||||
version = versionString
|
||||
archivesBaseName = rootProject.archives_base_name + '-' + project.name
|
||||
|
||||
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_21
|
||||
|
||||
repositories {
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
url "https://modmaven.dev"
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "appeng"
|
||||
includeGroup "vazkii.patchouli"
|
||||
includeGroup "mezz.jei"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
url "https://cursemaven.com"
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "curse.maven"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
name = 'ParchmentMC'
|
||||
url = 'https://maven.parchmentmc.org'
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "org.parchmentmc.data"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
url = 'https://maven.architectury.dev'
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "me.shedaniel"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
url = 'https://maven.latvian.dev/releases'
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "dev.latvian.mods"
|
||||
includeGroup "dev.latvian.apps"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
name = "Fuzs Mod Resources"
|
||||
url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/"
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "fuzs"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
name = "Fabric maven"
|
||||
url = "https://maven.fabricmc.net/"
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "net.fabricmc"
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
name = "Mod Menu"
|
||||
url = "https://maven.terraformersmc.com/releases/"
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup "com.terraformersmc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
plugins {
|
||||
id 'modernfix.common-conventions'
|
||||
id 'dev.architectury.loom'
|
||||
}
|
||||
|
||||
loom {
|
||||
silentMojangMappingsLicense()
|
||||
accessWidenerPath = file("${rootDir}/common/src/main/resources/modernfix.accesswidener")
|
||||
mixin {
|
||||
useLegacyMixinAp = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||
mappings loom.layered() {
|
||||
officialMojangMappings()
|
||||
if(rootProject.hasProperty("parchment_version")) {
|
||||
parchment("org.parchmentmc.data:parchment-${parchment_mc_version}:${parchment_version}@zip")
|
||||
}
|
||||
}
|
||||
implementation project(":annotations")
|
||||
annotationProcessor project(path: ":annotation-processor", configuration: 'shadow')
|
||||
}
|
||||
|
||||
project.sourceSets {
|
||||
main.resources.srcDirs += [layout.buildDirectory.dir("generated/sources/annotationProcessor/java/main/resources")]
|
||||
}
|
||||
// hack to shut up gradle about the hack to include generated resources
|
||||
tasks {
|
||||
processResources {
|
||||
dependsOn compileJava
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
configure(options) {
|
||||
if (!name.toLowerCase().contains('test')) {
|
||||
options.compilerArgs << "-ArootProject.name=${rootProject.name}" << "-Aproject.name=${project.name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
plugins {
|
||||
id 'com.matthewprenger.cursegradle'
|
||||
id 'com.modrinth.minotaur'
|
||||
}
|
||||
|
||||
loom {
|
||||
mods {
|
||||
main { // to match the default mod generated for Forge
|
||||
sourceSet project.sourceSets.main
|
||||
sourceSet project(':common').sourceSets.main
|
||||
}
|
||||
}
|
||||
runs {
|
||||
client {
|
||||
vmArgs "-Xmx1G"
|
||||
vmArgs "-Xms1G"
|
||||
property("mixin.debug.export", "true")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def copyJarNameConsistent = tasks.register('copyJarNameConsistent', Copy) {
|
||||
from remapJar // shortcut for createJar.outputs.files
|
||||
into project.file("build/libs")
|
||||
rename { name -> "modernfix-" + project.name + "-latest.jar" }
|
||||
}
|
||||
|
||||
def copyJarToBin = tasks.register('copyJarToBin', Copy) {
|
||||
from remapJar // shortcut for createJar.outputs.files
|
||||
into rootProject.file("bin")
|
||||
mustRunAfter "copyJarNameConsistent"
|
||||
}
|
||||
|
||||
tasks.build.dependsOn(copyJarToBin, copyJarNameConsistent)
|
||||
|
||||
def isBeta = project.version.toString().contains("beta")
|
||||
|
||||
curseforge {
|
||||
if (System.getenv("CURSEFORGE_TOKEN") != null) {
|
||||
apiKey = System.getenv("CURSEFORGE_TOKEN")
|
||||
project {
|
||||
id = "790626"
|
||||
changelog = file("${rootDir}/CHANGELOG.md")
|
||||
changelogType = "markdown"
|
||||
releaseType = isBeta ? "beta" : "release"
|
||||
addGameVersion (project.name.equals("neoforge") ? "NeoForge" : project.name.capitalize())
|
||||
gameVersionStrings.addAll(supported_minecraft_versions.tokenize(","))
|
||||
mainArtifact remapJar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
token = System.getenv("MODRINTH_TOKEN")
|
||||
projectId = "modernfix" // This can be the project ID or the slug. Either will work!
|
||||
versionType = isBeta ? "beta" : "release" // This is the default -- can also be `beta` or `alpha`
|
||||
uploadFile = remapJar
|
||||
gameVersions = supported_minecraft_versions.tokenize(",")
|
||||
loaders = [project.name]
|
||||
changelog.set(provider { file("${rootDir}/CHANGELOG.md").getText('UTF-8') })
|
||||
}
|
||||
|
||||
tasks.curseforge.dependsOn(rootProject.generateChangelog)
|
||||
tasks.modrinth.dependsOn(rootProject.generateChangelog)
|
||||
|
||||
tasks.register('publishToModSites') {
|
||||
publishToModSites.dependsOn(tasks.modrinth)
|
||||
publishToModSites.dependsOn(tasks.curseforge)
|
||||
}
|
||||
61
buildSrc/src/main/kotlin/GitVersionSource.kt
Normal file
61
buildSrc/src/main/kotlin/GitVersionSource.kt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.ValueSource
|
||||
import org.gradle.api.provider.ValueSourceParameters
|
||||
import org.gradle.process.ExecOperations
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class GitVersionSource : ValueSource<String, GitVersionSource.Parameters> {
|
||||
|
||||
interface Parameters : ValueSourceParameters {
|
||||
val minecraftVersion: Property<String>
|
||||
val projectDir: DirectoryProperty
|
||||
}
|
||||
|
||||
@get:Inject
|
||||
abstract val execOperations: ExecOperations
|
||||
|
||||
override fun obtain(): String {
|
||||
val minecraftVersion = parameters.minecraftVersion.get()
|
||||
val workDir = parameters.projectDir.get().asFile
|
||||
|
||||
val releaseLine = workDir.resolve("release_line.txt").readText().trim()
|
||||
|
||||
val patch = try {
|
||||
// Find the most recent first-parent commit that touched release_line.txt
|
||||
val lineStartCommit = git(workDir,
|
||||
"log", "--first-parent",
|
||||
"-n", "1",
|
||||
"--format=%H",
|
||||
"--",
|
||||
"release_line.txt"
|
||||
).trim()
|
||||
|
||||
if (lineStartCommit.isEmpty()) {
|
||||
// count all first-parent commits as a safe fallback
|
||||
git(workDir, "rev-list", "--count", "--first-parent", "HEAD")
|
||||
.trim().toIntOrNull() ?: 0
|
||||
} else {
|
||||
git(workDir, "rev-list", "--count", "--first-parent", "$lineStartCommit..HEAD")
|
||||
.trim().toIntOrNull() ?: 0
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
// Git is unavailable or this is not a git repository
|
||||
999
|
||||
}
|
||||
|
||||
return "$releaseLine.$patch+mc$minecraftVersion"
|
||||
}
|
||||
|
||||
private fun git(workDir: File, vararg args: String): String {
|
||||
val output = ByteArrayOutputStream()
|
||||
execOperations.exec {
|
||||
commandLine("git", *args)
|
||||
standardOutput = output
|
||||
workingDir(workDir)
|
||||
}
|
||||
return output.toString(Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
plugins {
|
||||
id "modernfix.mod-common-conventions"
|
||||
}
|
||||
|
||||
architectury {
|
||||
common(rootProject.enabled_platforms.split(","))
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||
// Do NOT use other classes from fabric loader
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixinextras_version}"))
|
||||
|
||||
modCompileOnly("dev.latvian.mods:kubejs-neoforge:${kubejs_version}") {
|
||||
transitive = false
|
||||
}
|
||||
modApi("dev.latvian.mods:rhino:${rhino_version}") {
|
||||
transitive = false
|
||||
}
|
||||
|
||||
modCompileOnly "curse.maven:spark-361579:${rootProject.spark_version}"
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
// modApi "me.shedaniel:architectury:${rootProject.architectury_version}"
|
||||
}
|
||||
|
||||
// don't need remapped common jar
|
||||
tasks.named('remapJar') { enabled = false }
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenCommon(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileWalker extends CacheLoader<Pair<Path, Integer>, List<Path>> {
|
||||
public static final FileWalker INSTANCE = new FileWalker();
|
||||
|
||||
@Override
|
||||
public List<Path> load(Pair<Path, Integer> key) throws Exception {
|
||||
try(Stream<Path> stream = Files.walk(key.getLeft(), key.getRight())) {
|
||||
return stream.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package org.embeddedt.modernfix.api.entrypoint;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
|
||||
/**
|
||||
* Implement this interface in a mod class and add it to "modernfix:integration_v1" in your mod metadata file
|
||||
* to integrate with ModernFix's features.
|
||||
*/
|
||||
public interface ModernFixClientIntegration {
|
||||
/**
|
||||
* Called when the dynamic resources status has changed during a model reload so mods know whether to run their
|
||||
* normal codepath or the dynamic version.
|
||||
*
|
||||
* @param enabled whether dynamic resources is enabled
|
||||
*/
|
||||
default void onDynamicResourcesStatusChange(boolean enabled) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to allow mods to observe the loading of a baked model and either make changes to it or wrap it with their
|
||||
* own instance.
|
||||
*
|
||||
* @param location the ResourceLocation of the model (this may be a ModelResourceLocation)
|
||||
* @param originalModel the original model
|
||||
* @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect
|
||||
* with dynamic resources on
|
||||
* @param textureGetter function to retrieve textures for this model
|
||||
* @return the model which should actually be loaded for this resource location
|
||||
*/
|
||||
default BakedModel onBakedModelLoad(ModelResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery, ModelBakery.TextureGetter textureGetter) {
|
||||
return originalModel;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package org.embeddedt.modernfix.blockstate;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class FerriteCorePostProcess {
|
||||
private static final boolean willPostProcess;
|
||||
|
||||
private static final MethodHandle theTable, toKeyIndex;
|
||||
|
||||
static {
|
||||
boolean success = true;
|
||||
MethodHandle table = null, keyIndex = null;
|
||||
try {
|
||||
Class<?> fastMap = Class.forName("malte0811.ferritecore.fastmap.FastMap");
|
||||
Field field = fastMap.getDeclaredField("toKeyIndex");
|
||||
field.setAccessible(true);
|
||||
keyIndex = MethodHandles.publicLookup().unreflectSetter(field);
|
||||
field = StateHolder.class.getDeclaredField("ferritecore_globalTable");
|
||||
field.setAccessible(true);
|
||||
table = MethodHandles.publicLookup().unreflectGetter(field);
|
||||
} catch(ReflectiveOperationException | RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
}
|
||||
willPostProcess = success;
|
||||
theTable = table;
|
||||
toKeyIndex = keyIndex;
|
||||
}
|
||||
|
||||
private static final Object2IntMap<?> EMPTY_MAP;
|
||||
|
||||
static {
|
||||
Object2IntArrayMap<?> map = new Object2IntArrayMap<>();
|
||||
map.defaultReturnValue(-1);
|
||||
EMPTY_MAP = Object2IntMaps.unmodifiable(map);
|
||||
}
|
||||
|
||||
public static <O, S extends StateHolder<O, S>> void postProcess(StateDefinition<O, S> state) {
|
||||
if(!willPostProcess)
|
||||
return;
|
||||
try {
|
||||
if(state.getProperties().size() == 0) {
|
||||
for(S holder : state.getPossibleStates()) {
|
||||
// deduplicate Object2IntMap objects from FerriteCore
|
||||
// will probably be fixed upstream at some point, but likely not for older versions
|
||||
Object table = theTable.invoke(holder);
|
||||
toKeyIndex.invoke(table, EMPTY_MAP);
|
||||
}
|
||||
}
|
||||
} catch(Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package org.embeddedt.modernfix.chunk;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SafeBlockGetter implements BlockGetter {
|
||||
private final ServerLevel wrapped;
|
||||
private final Thread mainThread;
|
||||
|
||||
public SafeBlockGetter(ServerLevel wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
this.mainThread = Thread.currentThread();
|
||||
}
|
||||
|
||||
public boolean shouldUse() {
|
||||
return Thread.currentThread() != this.mainThread;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BlockGetter getChunkSafe(BlockPos pos) {
|
||||
// can safely call getChunkForLighting off-thread
|
||||
BlockGetter access = this.wrapped.getChunkSource().getChunkForLighting(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
if(!(access instanceof ChunkAccess))
|
||||
return null;
|
||||
ChunkAccess chunk = (ChunkAccess)access;
|
||||
if(!chunk.getPersistedStatus().isOrAfter(ChunkStatus.FULL))
|
||||
return null;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight() {
|
||||
return this.wrapped.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLightLevel() {
|
||||
return this.wrapped.getMaxLightLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight() {
|
||||
return this.wrapped.getMinBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return this.wrapped.getHeight();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
BlockGetter g = getChunkSafe(pos);
|
||||
return g == null ? null : g.getBlockEntity(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
BlockGetter g = getChunkSafe(pos);
|
||||
return g == null ? Blocks.AIR.defaultBlockState() : g.getBlockState(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
BlockGetter g = getChunkSafe(pos);
|
||||
return g == null ? Fluids.EMPTY.defaultFluidState() : g.getFluidState(pos);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package org.embeddedt.modernfix.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.embeddedt.modernfix.duck.IProfilingServerFunctionManager;
|
||||
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class ModernFixCommands {
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
dispatcher.register(literal("modernfix")
|
||||
.then(literal("mcfunctions").requires(source -> source.hasPermission(3))
|
||||
.executes(context -> {
|
||||
ServerLevel level = context.getSource().getLevel();
|
||||
if(level == null) {
|
||||
context.getSource().sendFailure(Component.literal("Couldn't find server level"));
|
||||
return 0;
|
||||
}
|
||||
if (level.getServer().getFunctions() instanceof IProfilingServerFunctionManager profiler) {
|
||||
context.getSource().sendSuccess(() -> Component.literal("mcfunction runtime breakdown:"), false);
|
||||
for(String line : profiler.mfix$getProfilingResults().split("\n")) {
|
||||
context.getSource().sendSuccess(() -> Component.literal(line), false);
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
context.getSource().sendFailure(Component.literal("ModernFix mcfunction profiling is not enabled on this server."));
|
||||
return 0;
|
||||
}
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
||||
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 100)
|
||||
public class BlockStateBaseMixin {
|
||||
@ModifyVariable(method = "getOffset", at = @At("HEAD"), argsOnly = true, index = 1)
|
||||
private BlockGetter useSafeGetter(BlockGetter g) {
|
||||
if(g instanceof ISafeBlockGetter) {
|
||||
SafeBlockGetter replacement = ((ISafeBlockGetter) g).mfix$getSafeBlockGetter();
|
||||
if(replacement.shouldUse())
|
||||
return replacement;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public class ServerLevelMixin implements ISafeBlockGetter {
|
||||
@Unique
|
||||
private final SafeBlockGetter mfix$safeBlockGetter = new SafeBlockGetter((ServerLevel)(Object)this);
|
||||
|
||||
@Override
|
||||
public SafeBlockGetter mfix$getSafeBlockGetter() {
|
||||
return mfix$safeBlockGetter;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class MinecraftMixin<R extends Runnable> extends BlockableEventLoop<R> {
|
||||
|
||||
protected MinecraftMixin(String p_i50403_1_) {
|
||||
super(p_i50403_1_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void managedBlock(BooleanSupplier pIsDone) {
|
||||
if(!this.isSameThread()) {
|
||||
ModernFix.LOGGER.warn("A mod is calling Minecraft.managedBlock from the wrong thread. This is most likely related to one of our parallelizations.");
|
||||
ModernFix.LOGGER.warn("ModernFix will work around this, however ideally the issue should be patched in the other mod.");
|
||||
ModernFix.LOGGER.warn("Stacktrace", new IllegalThreadStateException());
|
||||
while(!pIsDone.getAsBoolean()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch(InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.managedBlock(pIsDone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.core;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.embeddedt.modernfix.duck.ITimeTrackingServer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin implements ITimeTrackingServer {
|
||||
private long mfix$lastTickStartTime = -1L;
|
||||
|
||||
@Override
|
||||
public long mfix$getLastTickStartTime() {
|
||||
return mfix$lastTickStartTime;
|
||||
}
|
||||
|
||||
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickServer(Ljava/util/function/BooleanSupplier;)V"))
|
||||
private void trackTickTime(CallbackInfo ci) {
|
||||
mfix$lastTickStartTime = Util.getMillis();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.devenv;
|
||||
|
||||
import com.mojang.text2speech.Narrator;
|
||||
import net.minecraft.client.GameNarrator;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(GameNarrator.class)
|
||||
@ClientOnlyMixin
|
||||
public class NarratorMixin {
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/text2speech/Narrator;getNarrator()Lcom/mojang/text2speech/Narrator;", remap = false))
|
||||
private Narrator useDummyNarrator() {
|
||||
return Narrator.EMPTY;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.feature.direct_stack_trace;
|
||||
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.CrashReportCategory;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(CrashReport.class)
|
||||
public class CrashReportMixin {
|
||||
@Shadow @Final private Throwable exception;
|
||||
|
||||
@Inject(method = "addCategory(Ljava/lang/String;I)Lnet/minecraft/CrashReportCategory;", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false))
|
||||
private void dumpStacktrace(String s, int i, CallbackInfoReturnable<CrashReportCategory> cir) {
|
||||
new Exception("ModernFix crash stacktrace").printStackTrace();
|
||||
if(this.exception != null)
|
||||
this.exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.feature.stalled_chunk_load_detection;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.server.level.ChunkResult;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.EmptyLevelChunk;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Mixin(value = ServerChunkCache.class, priority = 1100)
|
||||
public abstract class ServerChunkCacheMixin {
|
||||
@Shadow @Final private Thread mainThread;
|
||||
@Shadow @Final public ServerLevel level;
|
||||
|
||||
@Shadow protected abstract CompletableFuture<ChunkResult<ChunkAccess>> getChunkFutureMainThread(int k, int l, ChunkStatus arg, boolean bl);
|
||||
|
||||
@Shadow @Final private ServerChunkCache.MainThreadExecutor mainThreadProcessor;
|
||||
private final boolean debugDeadServerAccess = Boolean.getBoolean("modernfix.debugBadChunkloading");
|
||||
|
||||
@Inject(method = "getChunk", at = @At("HEAD"), cancellable = true)
|
||||
private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable<ChunkAccess> cir) {
|
||||
if(!this.level.getServer().isRunning() && !this.mainThread.isAlive()) {
|
||||
ModernFix.LOGGER.fatal("A mod is accessing chunks from a stopped server (this will also cause memory leaks)");
|
||||
if(debugDeadServerAccess) {
|
||||
new Exception().printStackTrace();
|
||||
}
|
||||
Holder<Biome> plains = this.level.registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.PLAINS);
|
||||
cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), plains));
|
||||
} else if(Thread.currentThread() != this.mainThread) {
|
||||
CompletableFuture<ChunkResult<ChunkAccess>> future = CompletableFuture.supplyAsync(() -> this.getChunkFutureMainThread(chunkX, chunkZ, requiredStatus, false), this.mainThreadProcessor).join();
|
||||
if(!future.isDone()) {
|
||||
// Wait at least 500 milliseconds before printing anything
|
||||
ChunkResult<ChunkAccess> resultingChunk = null;
|
||||
try {
|
||||
resultingChunk = future.get(500, TimeUnit.MILLISECONDS);
|
||||
} catch(InterruptedException | ExecutionException | TimeoutException ignored) {
|
||||
}
|
||||
if(resultingChunk != null && resultingChunk.isSuccess()) {
|
||||
cir.setReturnValue(resultingChunk.orElse(null));
|
||||
return;
|
||||
}
|
||||
if(debugDeadServerAccess)
|
||||
ModernFix.LOGGER.warn("Async loading of a chunk was requested, this might not be desirable", new Exception());
|
||||
try {
|
||||
resultingChunk = future.get(10, TimeUnit.SECONDS);
|
||||
if(resultingChunk.isSuccess()) {
|
||||
cir.setReturnValue(resultingChunk.orElse(null));
|
||||
return;
|
||||
}
|
||||
} catch(InterruptedException | ExecutionException | TimeoutException e) {
|
||||
ModernFix.LOGGER.error("Async chunk load took way too long, this needs to be reported to the appropriate mod.", e);
|
||||
}
|
||||
//cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.cache_model_materials;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@Mixin(MultiPart.class)
|
||||
@ClientOnlyMixin
|
||||
public class MultipartMixin {
|
||||
private Collection<ResourceLocation> dependencyCache = null;
|
||||
@Inject(method = "getDependencies", at = @At("HEAD"), cancellable = true)
|
||||
private void useDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
||||
if(dependencyCache != null)
|
||||
cir.setReturnValue(dependencyCache);
|
||||
}
|
||||
|
||||
@Inject(method = "getDependencies", at = @At("RETURN"))
|
||||
private void storeDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
||||
if(dependencyCache == null)
|
||||
dependencyCache = cir.getReturnValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.cache_strongholds;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.duck.IChunkGenerator;
|
||||
import org.embeddedt.modernfix.duck.IServerLevel;
|
||||
import org.embeddedt.modernfix.world.StrongholdLocationCache;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Mixin(ChunkGeneratorStructureState.class)
|
||||
public class ChunkGeneratorMixin implements IChunkGenerator {
|
||||
private WeakReference<ServerLevel> mfix$serverLevel;
|
||||
|
||||
@Override
|
||||
public void mfix$setAssociatedServerLevel(ServerLevel level) {
|
||||
mfix$serverLevel = new WeakReference<>(level);
|
||||
}
|
||||
|
||||
@Inject(method = "generateRingPositions", at = @At("HEAD"), cancellable = true)
|
||||
private void useCachedDataIfAvailable(Holder<StructureSet> structureSet, ConcentricRingsStructurePlacement placement, CallbackInfoReturnable<CompletableFuture<List<ChunkPos>>> cir) {
|
||||
if(placement.count() == 0)
|
||||
return;
|
||||
ServerLevel level = searchLevel();
|
||||
if(level == null)
|
||||
return;
|
||||
StrongholdLocationCache cache = ((IServerLevel)level).mfix$getStrongholdCache();
|
||||
List<ChunkPos> positions = cache.getChunkPosList();
|
||||
if(positions.isEmpty())
|
||||
return;
|
||||
ModernFix.LOGGER.debug("Loaded stronghold cache for dimension {} with {} positions", level.dimension().location(), positions.size());
|
||||
cir.setReturnValue(CompletableFuture.completedFuture(positions));
|
||||
}
|
||||
|
||||
private ServerLevel searchLevel() {
|
||||
if(mfix$serverLevel != null)
|
||||
return mfix$serverLevel.get();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Inject(method = "generateRingPositions", at = @At("RETURN"), cancellable = true)
|
||||
private void saveCachedData(Holder<StructureSet> structureSet, ConcentricRingsStructurePlacement placement, CallbackInfoReturnable<CompletableFuture<List<ChunkPos>>> cir) {
|
||||
cir.setReturnValue(cir.getReturnValue().thenApplyAsync(list -> {
|
||||
if(list.size() == 0)
|
||||
return list;
|
||||
ServerLevel level = searchLevel();
|
||||
if(level != null) {
|
||||
StrongholdLocationCache cache = ((IServerLevel)level).mfix$getStrongholdCache();
|
||||
cache.setChunkPosList(list);
|
||||
ModernFix.LOGGER.debug("Saved stronghold cache for dimension {}", level.dimension().location());
|
||||
}
|
||||
return list;
|
||||
}, Util.backgroundExecutor()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.cache_strongholds;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import net.minecraft.world.level.storage.WritableLevelData;
|
||||
import org.embeddedt.modernfix.duck.IChunkGenerator;
|
||||
import org.embeddedt.modernfix.duck.IServerLevel;
|
||||
import org.embeddedt.modernfix.world.StrongholdLocationCache;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
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;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class ServerLevelMixin extends Level implements IServerLevel {
|
||||
protected ServerLevelMixin(WritableLevelData arg, ResourceKey<Level> arg2, RegistryAccess arg3, Holder<DimensionType> arg4, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
|
||||
super(arg, arg2, arg3, arg4, supplier, bl, bl2, l, i);
|
||||
}
|
||||
|
||||
@Shadow public abstract DimensionDataStorage getDataStorage();
|
||||
|
||||
@Shadow @Final private ServerChunkCache chunkSource;
|
||||
private StrongholdLocationCache mfix$strongholdCache;
|
||||
|
||||
/**
|
||||
* Initialize the stronghold cache but don't force any structure generation yet.
|
||||
*/
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/ChunkGeneratorStructureState;ensureStructuresGenerated()V"))
|
||||
private void hookStrongholdCache(ChunkGeneratorStructureState generator) {
|
||||
((IChunkGenerator)generator).mfix$setAssociatedServerLevel((ServerLevel)(Object)this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Now start the stronghold generation process.
|
||||
*/
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void ensureGeneration(CallbackInfo ci) {
|
||||
mfix$strongholdCache = this.getDataStorage().computeIfAbsent(
|
||||
StrongholdLocationCache.factory((ServerLevel)(Object)this),
|
||||
StrongholdLocationCache.getFileId(this.dimensionTypeRegistration()));
|
||||
this.chunkSource.getGeneratorState().ensureStructuresGenerated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrongholdLocationCache mfix$getStrongholdCache() {
|
||||
return mfix$strongholdCache;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.deduplicate_climate_parameters;
|
||||
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
import org.embeddedt.modernfix.dedup.ClimateCache;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin({ Climate.Parameter.class, Climate.ParameterPoint.class })
|
||||
public class ParameterMixin {
|
||||
@Redirect(method = "*", at = @At(value = "NEW", target = "net/minecraft/world/level/biome/Climate$Parameter"), require = 0)
|
||||
private static Climate.Parameter internParameterStatic(long min, long max) {
|
||||
return ClimateCache.MFIX_INTERNER.intern(new Climate.Parameter(min, max));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.deduplicate_location;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.dedup.IdentifierCaches;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ResourceLocation.class)
|
||||
public class MixinResourceLocation {
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private String namespace;
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private String path;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void reinit(String string, String string2, CallbackInfo ci) {
|
||||
this.namespace = IdentifierCaches.NAMESPACES.deduplicate(this.namespace);
|
||||
this.path = IdentifierCaches.PATH.deduplicate(this.path);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_dfu;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import com.mojang.datafixers.DataFixerBuilder;
|
||||
import net.minecraft.util.datafix.DataFixers;
|
||||
import org.embeddedt.modernfix.dfu.DFUBlaster;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(DataFixers.class)
|
||||
public class DataFixersMixin {
|
||||
@ModifyReturnValue(method = "createFixerUpper", at = @At("RETURN"))
|
||||
private static DataFixerBuilder.Result setupMapBlasting(DataFixerBuilder.Result original) {
|
||||
DFUBlaster.blastMaps();
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_entity_renderers;
|
||||
|
||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.entity.EntityRendererMap;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
@ClientOnlyMixin
|
||||
public class EntityRenderDispatcherMixin {
|
||||
@Shadow private Map<EntityType<?>, EntityRenderer<?>> renderers;
|
||||
|
||||
private EntityRendererMap mfix$dynamicRenderers;
|
||||
|
||||
@Inject(method = "getRenderer", at = @At("RETURN"), cancellable = true)
|
||||
private <T extends Entity> void checkNullness(T entity, CallbackInfoReturnable<EntityRenderer<? super T>> cir) {
|
||||
// apparently some mods yeet the renderers map and cause issues
|
||||
if(cir.getReturnValue() == null)
|
||||
cir.setReturnValue((EntityRenderer<? super T>)mfix$dynamicRenderers.get(entity.getType()));
|
||||
}
|
||||
|
||||
@Redirect(method = "onResourceManagerReload", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/renderer/entity/EntityRenderDispatcher;renderers:Ljava/util/Map;"))
|
||||
private void setRendererField(EntityRenderDispatcher instance, Map<EntityType<?>, EntityRenderer<?>> incomingMap) {
|
||||
this.renderers = incomingMap;
|
||||
this.mfix$dynamicRenderers = (EntityRendererMap)incomingMap;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_entity_renderers;
|
||||
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderers;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.entity.EntityRendererMap;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(EntityRenderers.class)
|
||||
@ClientOnlyMixin
|
||||
public class EntityRenderersMixin {
|
||||
@Shadow @Final private static Map<EntityType<?>, EntityRendererProvider<?>> PROVIDERS;
|
||||
|
||||
@Inject(method = "createEntityRenderers", at = @At("HEAD"), cancellable = true)
|
||||
private static void createDynamicRendererLoader(EntityRendererProvider.Context context, CallbackInfoReturnable<Map<EntityType<?>, EntityRenderer<?>>> cir) {
|
||||
cir.setReturnValue(new EntityRendererMap(PROVIDERS, context));
|
||||
ModernFix.LOGGER.info("Dynamic entity renderer hook setup");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceObjectImmutablePair;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.renderer.block.model.BlockModelDefinition;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.core.DefaultedRegistry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IBlockStateModelLoader;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(BlockStateModelLoader.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class BlockStateModelLoaderMixin implements IBlockStateModelLoader {
|
||||
@Shadow protected abstract void loadBlockStateDefinitions(ResourceLocation resourceLocation, StateDefinition<Block, BlockState> stateDefinition);
|
||||
|
||||
@Shadow @Mutable @Final private Object2IntMap<BlockState> modelGroups;
|
||||
|
||||
private ImmutableList<BlockState> filteredStates;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void makeModelGroupsSynchronized(Map map, ProfilerFiller profilerFiller, UnbakedModel unbakedModel, BlockColors blockColors, BiConsumer biConsumer, CallbackInfo ci) {
|
||||
this.modelGroups = Object2IntMaps.synchronize(this.modelGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSpecificBlock(ModelResourceLocation location) {
|
||||
var optionalBlock = BuiltInRegistries.BLOCK.getOptional(location.id());
|
||||
if(optionalBlock.isPresent()) {
|
||||
// embeddedt note - filtering is currently disabled as it's quite inefficient to do vs. just loading
|
||||
// the extra models and letting LRU deal with it
|
||||
/*
|
||||
try {
|
||||
// Only filter states if we are in a world and not in the loading overlay
|
||||
filteredStates = (Minecraft.getInstance().getOverlay() == null && Minecraft.getInstance().level != null) ? ModelBakeryHelpers.getBlockStatesForMRL(optionalBlock.get().getStateDefinition(), location) : null;
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception filtering states on {}", location, e);
|
||||
filteredStates = null;
|
||||
}
|
||||
*/
|
||||
try {
|
||||
this.loadBlockStateDefinitions(location.id(), optionalBlock.get().getStateDefinition());
|
||||
} finally {
|
||||
filteredStates = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "loadAllBlockStates", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/DefaultedRegistry;iterator()Ljava/util/Iterator;"))
|
||||
private Iterator<?> skipIteratingBlocks(DefaultedRegistry instance) {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
@Redirect(method = "loadBlockStateDefinitions", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/StateDefinition;getPossibleStates()Lcom/google/common/collect/ImmutableList;"))
|
||||
private ImmutableList<BlockState> getFilteredStates(StateDefinition<Block, BlockState> instance) {
|
||||
return this.filteredStates != null ? this.filteredStates : instance.getPossibleStates();
|
||||
}
|
||||
|
||||
// Add some caching around key hot paths
|
||||
|
||||
private final Cache<ReferenceObjectImmutablePair<BlockStateModelLoader.LoadedJson, ResourceLocation>, BlockModelDefinition> cachedBlockModelDefs = CacheBuilder.newBuilder()
|
||||
.maximumSize(100)
|
||||
.build();
|
||||
|
||||
private static final Cache<Pair<StateDefinition<Block, BlockState>, String>, Predicate<BlockState>> cachedBlockStatePredicates = CacheBuilder.newBuilder()
|
||||
.maximumSize(100)
|
||||
.build();
|
||||
|
||||
@WrapOperation(method = "loadBlockStateDefinitions", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BlockStateModelLoader$LoadedJson;parse(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/renderer/block/model/BlockModelDefinition$Context;)Lnet/minecraft/client/renderer/block/model/BlockModelDefinition;"))
|
||||
private BlockModelDefinition avoidMultipleParses(BlockStateModelLoader.LoadedJson instance, ResourceLocation blockStateId, BlockModelDefinition.Context context, Operation<BlockModelDefinition> original) {
|
||||
try {
|
||||
return cachedBlockModelDefs.get(ReferenceObjectImmutablePair.of(instance, blockStateId), () -> original.call(instance, blockStateId, context));
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapMethod(method = "predicate")
|
||||
private static Predicate<BlockState> memoizePredicate(StateDefinition<Block, BlockState> stateDefentition, String properties, Operation<Predicate<BlockState>> original) {
|
||||
try {
|
||||
return cachedBlockStatePredicates.get(Pair.of(stateDefentition, properties), () -> original.call(stateDefentition, properties));
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class MinecraftMixin_ModelTicking {
|
||||
@Shadow public abstract ModelManager getModelManager();
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "RETURN"))
|
||||
private void tickModels(CallbackInfo ci) {
|
||||
((IExtendedModelManager)this.getModelManager()).mfix$tick();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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;
|
||||
|
||||
@Mixin(ModelBakery.ModelBakerImpl.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class ModelBakerImplMixin {
|
||||
@Shadow public abstract UnbakedModel getModel(ResourceLocation location);
|
||||
|
||||
@Shadow(aliases = {"this$0"}) @Final private ModelBakery field_40571;
|
||||
@Unique
|
||||
private int mfix$getDepth = 0;
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason force parent resolution to happen before model gets baked
|
||||
*/
|
||||
@ModifyReturnValue(method = "getModel", at = @At("RETURN"))
|
||||
private UnbakedModel resolveParents(UnbakedModel model) {
|
||||
mfix$getDepth++;
|
||||
if(mfix$getDepth == 1) {
|
||||
try {
|
||||
model.resolveParents(this::getModel);
|
||||
} catch(Exception e) {
|
||||
ModernFix.LOGGER.warn("Exception encountered resolving parents", e);
|
||||
}
|
||||
}
|
||||
mfix$getDepth--;
|
||||
return model;
|
||||
}
|
||||
|
||||
@WrapMethod(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;)Lnet/minecraft/client/resources/model/BakedModel;")
|
||||
private BakedModel mfix$lockWhenBaking(ResourceLocation location, ModelState transform, Operation<BakedModel> original) {
|
||||
var lock = ((IExtendedModelBakery)this.field_40571).mfix$getLock();
|
||||
lock.lock();
|
||||
try {
|
||||
return original.call(location, transform);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.core.DefaultedRegistry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.duck.IBlockStateModelLoader;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.util.DynamicOverridableMap;
|
||||
import org.embeddedt.modernfix.util.LRUMap;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@Mixin(ModelBakery.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||
@Unique
|
||||
private BlockStateModelLoader dynamicLoader;
|
||||
|
||||
@Unique
|
||||
private final ReentrantLock modelBakeryLock = new ReentrantLock();
|
||||
|
||||
@Unique
|
||||
private ModelBakery.TextureGetter textureGetter;
|
||||
|
||||
@Unique
|
||||
private BakedModel bakedMissingModel;
|
||||
|
||||
@Shadow abstract UnbakedModel getModel(ResourceLocation resourceLocation);
|
||||
|
||||
@Shadow @Final private UnbakedModel missingModel;
|
||||
|
||||
@Unique
|
||||
private static final boolean DEBUG_MODEL_LOADS = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
||||
|
||||
/**
|
||||
* Bake a model using the provided texture getter and location. The model is stored in {@link ModelBakeryMixin#bakedTopLevelModels}.
|
||||
*/
|
||||
@Shadow(aliases = "lambda$bakeModels$6") protected abstract void method_61072(ModelBakery.TextureGetter getter, ModelResourceLocation location, UnbakedModel model);
|
||||
|
||||
@Shadow @Mutable @Final private Map<ModelResourceLocation, BakedModel> bakedTopLevelModels;
|
||||
@Shadow @Mutable @Final public Map<ModelResourceLocation, UnbakedModel> topLevelModels;
|
||||
@Shadow @Mutable @Final private Map<ResourceLocation, UnbakedModel> unbakedCache;
|
||||
@Shadow @Mutable @Final public Map<ModelBakery.BakedCacheKey, BakedModel> bakedCache;
|
||||
|
||||
@Shadow protected abstract void loadItemModelAndDependencies(ResourceLocation resourceLocation);
|
||||
|
||||
|
||||
@Shadow @Final public static ModelResourceLocation MISSING_MODEL_VARIANT;
|
||||
|
||||
@Shadow protected abstract void registerModelAndLoadDependencies(ModelResourceLocation modelLocation, UnbakedModel model);
|
||||
|
||||
private final Map<ModelResourceLocation, BakedModel> mfix$emulatedBakedRegistry = new DynamicOverridableMap<>(ModelResourceLocation.class, this::loadBakedModelDynamic);
|
||||
|
||||
@Override
|
||||
public UnbakedModel mfix$loadUnbakedModelDynamic(ModelResourceLocation location) {
|
||||
if(location.equals(MISSING_MODEL_VARIANT)) {
|
||||
return missingModel;
|
||||
}
|
||||
modelBakeryLock.lock();
|
||||
try {
|
||||
UnbakedModel existing = this.topLevelModels.get(location);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
if(DEBUG_MODEL_LOADS) {
|
||||
ModernFix.LOGGER.info("Loading model {}", location);
|
||||
}
|
||||
if(location.variant().equals("inventory")) {
|
||||
this.loadItemModelAndDependencies(location.id());
|
||||
} else if (location.variant().equals("fabric_resource") || location.variant().equals("standalone")) {
|
||||
UnbakedModel unbakedModel = this.getModel(location.id());
|
||||
this.registerModelAndLoadDependencies(location, unbakedModel);
|
||||
} else {
|
||||
((IBlockStateModelLoader)dynamicLoader).loadSpecificBlock(location);
|
||||
}
|
||||
return this.topLevelModels.getOrDefault(location, this.missingModel);
|
||||
} finally {
|
||||
modelBakeryLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@WrapMethod(method = "getModel")
|
||||
private UnbakedModel mfix$lockWhenGettingModel(ResourceLocation modelLocation, Operation<UnbakedModel> original) {
|
||||
modelBakeryLock.lock();
|
||||
try {
|
||||
return original.call(modelLocation);
|
||||
} finally {
|
||||
modelBakeryLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel mfix$getMissingModel() {
|
||||
return missingModel;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private BakedModel loadBakedModelDynamic(ModelResourceLocation location) {
|
||||
if(location.equals(MISSING_MODEL_VARIANT)) {
|
||||
return bakedMissingModel;
|
||||
}
|
||||
BakedModel model;
|
||||
modelBakeryLock.lock();
|
||||
try {
|
||||
model = bakedTopLevelModels.get(location);
|
||||
if(model == null) {
|
||||
UnbakedModel prototype = mfix$loadUnbakedModelDynamic(location);
|
||||
if(prototype == missingModel) {
|
||||
model = bakedMissingModel;
|
||||
} else {
|
||||
prototype.resolveParents(this::getModel);
|
||||
if(DEBUG_MODEL_LOADS) {
|
||||
ModernFix.LOGGER.info("Baking model {}", location);
|
||||
}
|
||||
this.method_61072(this.textureGetter, location, prototype);
|
||||
model = bakedTopLevelModels.remove(location);
|
||||
if(model == null) {
|
||||
ModernFix.LOGGER.error("Failed to load model " + location);
|
||||
model = bakedMissingModel;
|
||||
}
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
model = integration.onBakedModelLoad(location, prototype, model, BlockModelRotation.X0_Y0, (ModelBakery)(Object)this, this.textureGetter);
|
||||
} catch (RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception encountered running dynamic resources integration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
modelBakeryLock.unlock();
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(method = "<init>", at = @At(value = "CONSTANT", args = "stringValue=missing_model"))
|
||||
private String replaceBackingMaps(String original) {
|
||||
this.unbakedCache = new LRUMap<>(this.unbakedCache);
|
||||
this.bakedCache = new LRUMap<>(this.bakedCache);
|
||||
this.topLevelModels = new LRUMap<>(this.topLevelModels);
|
||||
this.bakedTopLevelModels = new LRUMap<>(this.bakedTopLevelModels);
|
||||
return original;
|
||||
}
|
||||
|
||||
@WrapOperation(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BlockStateModelLoader;loadAllBlockStates()V"))
|
||||
private void noInitialBlockStateLoad(BlockStateModelLoader instance, Operation<Void> original) {
|
||||
dynamicLoader = instance;
|
||||
original.call(instance);
|
||||
}
|
||||
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/DefaultedRegistry;keySet()Ljava/util/Set;"))
|
||||
private Set<?> skipLoadingItems(DefaultedRegistry instance) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "bakeModels", at = @At("HEAD"))
|
||||
private void storeTextureGetterAndBakeMissing(ModelBakery.TextureGetter textureGetter, CallbackInfo ci) {
|
||||
this.textureGetter = textureGetter;
|
||||
this.method_61072(textureGetter, MISSING_MODEL_VARIANT, Objects.requireNonNull(this.topLevelModels.get(MISSING_MODEL_VARIANT)));
|
||||
this.bakedMissingModel = this.bakedTopLevelModels.get(MISSING_MODEL_VARIANT);
|
||||
}
|
||||
|
||||
private boolean inInitialLoad = true;
|
||||
|
||||
@Inject(method = "bakeModels", at = @At("RETURN"))
|
||||
private void onInitialBakeFinish(ModelBakery.TextureGetter textureGetter, CallbackInfo ci) {
|
||||
var permanentMRLs = new ObjectOpenHashSet<>(this.bakedTopLevelModels.keySet());
|
||||
((LRUMap<ModelResourceLocation, BakedModel>)this.bakedTopLevelModels).setPermanentEntries(permanentMRLs);
|
||||
ModernFix.LOGGER.info("Dynamic model bakery initial baking finished, with {} permanent top level baked models", this.bakedTopLevelModels.size());
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onInitialLoadFinish(BlockColors blockColors, ProfilerFiller profilerFiller, Map map, Map map2, CallbackInfo ci) {
|
||||
var permanentMRLs = new ObjectOpenHashSet<>(this.topLevelModels.keySet());
|
||||
((LRUMap<ModelResourceLocation, UnbakedModel>)this.topLevelModels).setPermanentEntries(permanentMRLs);
|
||||
ModernFix.LOGGER.info("Dynamic model bakery loading finished, with {} permanent top level models", this.topLevelModels.size());
|
||||
}
|
||||
|
||||
@Unique
|
||||
private int tickCount;
|
||||
|
||||
@Unique
|
||||
private static final int MAXIMUM_CACHE_SIZE = 1000;
|
||||
|
||||
private void runCleanup() {
|
||||
try {
|
||||
((LRUMap<?, ?>)this.unbakedCache).dropEntriesToMeetSize(MAXIMUM_CACHE_SIZE);
|
||||
} catch(RuntimeException e) {
|
||||
throw new IllegalStateException("Exception dropping entries in unbaked cache", e);
|
||||
}
|
||||
try {
|
||||
((LRUMap<?, ?>)this.bakedCache).dropEntriesToMeetSize(MAXIMUM_CACHE_SIZE);
|
||||
} catch(RuntimeException e) {
|
||||
throw new IllegalStateException("Exception dropping entries in baked cache", e);
|
||||
}
|
||||
try {
|
||||
((LRUMap<?, ?>)this.topLevelModels).dropEntriesToMeetSize(MAXIMUM_CACHE_SIZE);
|
||||
} catch(RuntimeException e) {
|
||||
throw new IllegalStateException("Exception dropping entries in top level models", e);
|
||||
}
|
||||
try {
|
||||
((LRUMap<?, ?>)this.bakedTopLevelModels).dropEntriesToMeetSize(MAXIMUM_CACHE_SIZE);
|
||||
} catch(RuntimeException e) {
|
||||
throw new IllegalStateException("Exception dropping entries in baked top level models", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mfix$finishLoading() {
|
||||
inInitialLoad = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mfix$tick() {
|
||||
if(inInitialLoad) {
|
||||
return;
|
||||
}
|
||||
tickCount++;
|
||||
if((tickCount % 200) == 0) {
|
||||
if(modelBakeryLock.tryLock()) {
|
||||
try {
|
||||
runCleanup();
|
||||
} finally {
|
||||
modelBakeryLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason We provide a fake baked registry to the rest of Minecraft, that dynamically loads models.
|
||||
*/
|
||||
@Overwrite
|
||||
public Map<ModelResourceLocation, BakedModel> getBakedTopLevelModels() {
|
||||
return this.mfix$emulatedBakedRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReentrantLock mfix$getLock() {
|
||||
return this.modelBakeryLock;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_sounds;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.RemovalCause;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import com.mojang.blaze3d.audio.SoundBuffer;
|
||||
import net.minecraft.client.sounds.SoundBufferLibrary;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicSoundHelpers;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(SoundBufferLibrary.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class SoundBufferLibraryMixin {
|
||||
|
||||
private static final boolean debugDynamicSoundLoading = Boolean.getBoolean("modernfix.debugDynamicSoundLoading");
|
||||
|
||||
@Shadow @Final @Mutable
|
||||
private Map<ResourceLocation, CompletableFuture<SoundBuffer>> cache = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(DynamicSoundHelpers.MAX_SOUND_LIFETIME_SECS, TimeUnit.SECONDS)
|
||||
.concurrencyLevel(1)
|
||||
// Excessive use of type hinting due to it assuming Object as the broadest correct type
|
||||
.<ResourceLocation, CompletableFuture<SoundBuffer>>removalListener(this::onSoundRemoval)
|
||||
.build()
|
||||
.asMap();
|
||||
|
||||
private <K extends ResourceLocation, V extends CompletableFuture<SoundBuffer>> void onSoundRemoval(RemovalNotification<K, V> notification) {
|
||||
if(notification.getCause() == RemovalCause.REPLACED && notification.getValue() == cache.get(notification.getKey()))
|
||||
return;
|
||||
notification.getValue().thenAccept(SoundBuffer::discardAlBuffer);
|
||||
if(!debugDynamicSoundLoading)
|
||||
return;
|
||||
K k = notification.getKey();
|
||||
if(k == null)
|
||||
return;
|
||||
ModernFix.LOGGER.warn("Evicted sound {}", k);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.lazy_search_tree_registry;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import net.minecraft.client.multiplayer.SessionSearchTrees;
|
||||
import net.minecraft.client.searchtree.SearchTree;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(SessionSearchTrees.class)
|
||||
@ClientOnlyMixin
|
||||
public class SessionSearchTreesMixin {
|
||||
@Shadow private CompletableFuture<SearchTree<RecipeCollection>> recipeSearch;
|
||||
private Supplier<SearchTree<RecipeCollection>> mfix$deferredSearchTreeSupplier;
|
||||
|
||||
@ModifyArg(method = { "method_60367", "lambda$updateRecipes$8" }, at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;supplyAsync(Ljava/util/function/Supplier;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
|
||||
private Supplier<SearchTree<RecipeCollection>> mfix$deferProcessing(Supplier<SearchTree<RecipeCollection>> supplier) {
|
||||
this.mfix$deferredSearchTreeSupplier = supplier;
|
||||
return SearchTree::empty;
|
||||
}
|
||||
|
||||
@WrapMethod(method = "recipes")
|
||||
private SearchTree<RecipeCollection> mfix$processDeferredBuild(Operation<SearchTree<RecipeCollection>> original) {
|
||||
synchronized (this) {
|
||||
if (mfix$deferredSearchTreeSupplier != null) {
|
||||
Stopwatch watch = Stopwatch.createStarted();
|
||||
this.recipeSearch = CompletableFuture.completedFuture(mfix$deferredSearchTreeSupplier.get());
|
||||
watch.stop();
|
||||
ModernFix.LOGGER.info("Building recipe book search tree took {}", watch);
|
||||
mfix$deferredSearchTreeSupplier = null;
|
||||
}
|
||||
return original.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.mojang_registry_size;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ResourceKey.class)
|
||||
public class ResourceKeyMixin<T> {
|
||||
private static final Map<ResourceLocation, Map<ResourceLocation, ResourceKey<?>>> INTERNING_MAP = new Object2ObjectOpenHashMap<>();
|
||||
@Inject(method = "create(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceKey;", at = @At("HEAD"), cancellable = true)
|
||||
private static <T> void createEfficient(ResourceLocation parent, ResourceLocation location, CallbackInfoReturnable<ResourceKey<T>> cir) {
|
||||
synchronized (ResourceKey.class) {
|
||||
Map<ResourceLocation, ResourceKey<?>> keys = INTERNING_MAP.computeIfAbsent(parent, k -> new Object2ObjectOpenHashMap<>());
|
||||
ResourceKey<?> key = keys.get(location);
|
||||
if(key == null) {
|
||||
key = new ResourceKey<>(parent, location);
|
||||
keys.put(location, key);
|
||||
}
|
||||
cir.setReturnValue((ResourceKey<T>)key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(BlockBehaviour.class)
|
||||
public interface BlockBehaviourInvoker {
|
||||
@Invoker
|
||||
FluidState invokeGetFluidState(BlockState blockState);
|
||||
@Invoker
|
||||
boolean invokeIsRandomlyTicking(BlockState blockState);
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.resourcepacks;
|
||||
|
||||
import net.minecraft.server.packs.PackLocationInfo;
|
||||
import net.minecraft.server.packs.PathPackResources;
|
||||
import org.embeddedt.modernfix.resources.ICachingResourcePack;
|
||||
import org.embeddedt.modernfix.resources.PackResourcesCacheEngine;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Mixin(value = PathPackResources.class, priority = 1100)
|
||||
public abstract class PathPackResourcesMixin implements ICachingResourcePack {
|
||||
|
||||
@Shadow @Final private Path root;
|
||||
private PackResourcesCacheEngine cacheEngine;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void cacheResources(PackLocationInfo location, Path root, CallbackInfo ci) {
|
||||
invalidateCache();
|
||||
}
|
||||
|
||||
private PackResourcesCacheEngine generateResourceCache() {
|
||||
synchronized (this) {
|
||||
PackResourcesCacheEngine engine = this.cacheEngine;
|
||||
if(engine != null)
|
||||
return engine;
|
||||
this.cacheEngine = engine = new PackResourcesCacheEngine((type) -> this.root.resolve(type.getDirectory()));
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache() {
|
||||
this.cacheEngine = null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@Inject(method = "getNamespaces", at = @At("HEAD"), cancellable = true)
|
||||
private void useCacheForNamespaces(PackType type, CallbackInfoReturnable<Set<String>> cir) {
|
||||
PackResourcesCacheEngine engine = cacheEngine;
|
||||
if(engine != null) {
|
||||
Set<String> namespaces = engine.getNamespaces(type);
|
||||
if(namespaces != null)
|
||||
cir.setReturnValue(namespaces);
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "getRootResource", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;exists(Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Z"))
|
||||
private boolean useCacheForExistence(Path path, LinkOption[] options, String[] originalPaths) {
|
||||
// the cache only stores things with a namespace and pack type
|
||||
if(originalPaths.length < 3 || (!Objects.equals(originalPaths[0], "assets") && !Objects.equals(originalPaths[0], "data")))
|
||||
return Files.exists(path, options);
|
||||
else
|
||||
return this.generateResourceCache().hasResource(originalPaths);
|
||||
}
|
||||
|
||||
@Inject(method = "listResources", at = @At("HEAD"), cancellable = true)
|
||||
private void fastGetResources(PackType type, String namespace, String path, PackResources.ResourceOutput resourceOutput, CallbackInfo ci)
|
||||
{
|
||||
if(!PackTypeHelper.isVanillaPackType(type))
|
||||
return;
|
||||
ci.cancel();
|
||||
this.generateResourceCache().collectResources(type, namespace, path.split("/"), Integer.MAX_VALUE, resourceOutput);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.safety;
|
||||
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
@ClientOnlyMixin
|
||||
public class LivingEntityRendererMixin {
|
||||
@Shadow @Final @Mutable
|
||||
protected List<RenderLayer<?, ?>> layers;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void synchronizeLayerList(CallbackInfo ci) {
|
||||
/* allows buggy mods to call addLayer concurrently, order is not deterministic but can't fix that */
|
||||
this.layers = Collections.synchronizedList(layers);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package org.embeddedt.modernfix.dedup;
|
||||
|
||||
import com.google.common.collect.Interner;
|
||||
import com.google.common.collect.Interners;
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
|
||||
public class ClimateCache {
|
||||
public static final Interner<Climate.Parameter> MFIX_INTERNER = Interners.newStrongInterner();
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package org.embeddedt.modernfix.dedup;
|
||||
|
||||
import it.unimi.dsi.fastutil.Hash;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DeduplicationCache<T> {
|
||||
private final ObjectOpenCustomHashSet<T> pool;
|
||||
|
||||
private int attemptedInsertions = 0;
|
||||
private int deduplicated = 0;
|
||||
|
||||
public DeduplicationCache(Hash.Strategy<T> strategy) {
|
||||
this.pool = new ObjectOpenCustomHashSet<>(strategy);
|
||||
}
|
||||
|
||||
public DeduplicationCache() {
|
||||
this.pool = new ObjectOpenCustomHashSet<>(new Hash.Strategy<T>() {
|
||||
@Override
|
||||
public int hashCode(T o) {
|
||||
return Objects.hashCode(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(T a, T b) {
|
||||
return Objects.equals(a, b);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized T deduplicate(T item) {
|
||||
this.attemptedInsertions++;
|
||||
|
||||
T result = this.pool.addOrGet(item);
|
||||
|
||||
if (result != item) {
|
||||
this.deduplicated++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public synchronized void clearCache() {
|
||||
this.attemptedInsertions = 0;
|
||||
this.deduplicated = 0;
|
||||
|
||||
this.pool.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return String.format("DeduplicationCache ( %d/%d de-duplicated, %d pooled )",
|
||||
this.deduplicated, this.attemptedInsertions, this.pool.size());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package org.embeddedt.modernfix.dedup;
|
||||
|
||||
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
public class IdentifierCaches {
|
||||
public static final DeduplicationCache<String> NAMESPACES = new DeduplicationCache<>();
|
||||
public static final DeduplicationCache<String> PATH = new DeduplicationCache<>();
|
||||
public static final DeduplicationCache<String> PROPERTY = new DeduplicationCache<>();
|
||||
|
||||
public static void printDebug() {
|
||||
ModernFix.LOGGER.info("[[[ Identifier de-duplication statistics ]]]");
|
||||
ModernFix.LOGGER.info("Namespace cache: {}", NAMESPACES);
|
||||
ModernFix.LOGGER.info("Path cache: {}", PATH);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
|
||||
public interface IBlockStateModelLoader {
|
||||
void loadSpecificBlock(ModelResourceLocation location);
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
public interface ICachedMaterialsModel {
|
||||
public void clearMaterialsCache();
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
||||
public interface IChunkGenerator {
|
||||
void mfix$setAssociatedServerLevel(ServerLevel level);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public interface IExtendedModelBakery {
|
||||
void mfix$tick();
|
||||
void mfix$finishLoading();
|
||||
UnbakedModel mfix$loadUnbakedModelDynamic(ModelResourceLocation location);
|
||||
UnbakedModel mfix$getMissingModel();
|
||||
ReentrantLock mfix$getLock();
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
public interface IExtendedModelManager {
|
||||
void mfix$tick();
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
|
||||
public interface ILevelSave {
|
||||
public void runWorldPersistenceHooks(LevelStorageSource format);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
|
||||
public interface ISafeBlockGetter {
|
||||
SafeBlockGetter mfix$getSafeBlockGetter();
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import org.embeddedt.modernfix.world.StrongholdLocationCache;
|
||||
|
||||
public interface IServerLevel {
|
||||
StrongholdLocationCache mfix$getStrongholdCache();
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck.reuse_datapacks;
|
||||
|
||||
import net.minecraft.server.ReloadableServerResources;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ICachingResourceClient {
|
||||
void setCachedResources(ReloadableServerResources r);
|
||||
void setCachedDataPackConfig(Collection<String> c);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
public class DynamicSoundHelpers {
|
||||
/**
|
||||
* The duration until a sound is eligible for eviction if unused.
|
||||
*/
|
||||
public static final int MAX_SOUND_LIFETIME_SECS = 300;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BlockFaceUV;
|
||||
|
||||
public class UVController {
|
||||
public static final ThreadLocal<Boolean> useDummyUv = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
public static final BlockFaceUV dummyUv = new BlockFaceUV(new float[4], 0);
|
||||
}
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
package org.embeddedt.modernfix.entity;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderers;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@SuppressWarnings("OptionalAssignedToNull")
|
||||
public class EntityRendererMap implements Map<EntityType<?>, EntityRenderer<?>> {
|
||||
private final Map<EntityType<?>, EntityRendererProvider<?>> rendererProviders;
|
||||
private final LoadingCache<EntityType<?>, Optional<EntityRenderer<?>>> rendererMap;
|
||||
private final EntityRendererProvider.Context context;
|
||||
|
||||
public EntityRendererMap(Map<EntityType<?>, EntityRendererProvider<?>> rendererProviders, EntityRendererProvider.Context context) {
|
||||
this.rendererProviders = rendererProviders;
|
||||
this.context = context;
|
||||
this.rendererMap = CacheBuilder.newBuilder().build(new RenderConstructor());
|
||||
}
|
||||
|
||||
class RenderConstructor extends CacheLoader<EntityType<?>, Optional<EntityRenderer<?>>> {
|
||||
@Override
|
||||
public Optional<EntityRenderer<?>> load(EntityType<?> key) throws Exception {
|
||||
EntityRendererProvider<?> provider = rendererProviders.get(key);
|
||||
if(provider == null)
|
||||
return Optional.empty();
|
||||
synchronized(EntityRenderers.class) {
|
||||
EntityRenderer<?> renderer;
|
||||
try {
|
||||
renderer = provider.create(context);
|
||||
ModernFix.LOGGER.info("Loaded entity {}", BuiltInRegistries.ENTITY_TYPE.getKey(key));
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Failed to create entity model for " + BuiltInRegistries.ENTITY_TYPE.getKey(key) + ":", e);
|
||||
renderer = new ErroredEntityRenderer<>(context);
|
||||
}
|
||||
return Optional.ofNullable(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rendererProviders.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return rendererProviders.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return rendererProviders.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> get(Object o) {
|
||||
try {
|
||||
Optional<EntityRenderer<?>> renderer = rendererMap.get((EntityType<?>)o);
|
||||
return renderer.orElse(null);
|
||||
} catch (IllegalStateException e) {
|
||||
return null; /* emulate value not being present if recursive load occurs */
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EntityRenderer<?> put(EntityType<?> entityType, EntityRenderer<?> entityRenderer) {
|
||||
Optional<EntityRenderer<?>> old = rendererMap.getIfPresent(entityType);
|
||||
rendererMap.put(entityType, Optional.ofNullable(entityRenderer));
|
||||
return old != null ? old.orElse(null) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> remove(Object o) {
|
||||
Optional<EntityRenderer<?>> old = rendererMap.getIfPresent(o);
|
||||
rendererMap.invalidate(o);
|
||||
return old != null ? old.orElse(null) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends EntityType<?>, ? extends EntityRenderer<?>> map) {
|
||||
rendererMap.putAll(Maps.transformValues(map, Optional::ofNullable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
rendererMap.invalidateAll();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<EntityType<?>> keySet() {
|
||||
return rendererProviders.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<EntityRenderer<?>> values() {
|
||||
return new AbstractCollection<>() {
|
||||
@Override
|
||||
public Iterator<EntityRenderer<?>> iterator() {
|
||||
return Iterators.transform(Iterators.unmodifiableIterator(rendererProviders.keySet().iterator()), EntityRendererMap.this::get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rendererProviders.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class Entry implements Map.Entry<EntityType<?>, EntityRenderer<?>> {
|
||||
private final EntityType<?> key;
|
||||
|
||||
private Entry(EntityType<?> key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType<?> getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> getValue() {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> setValue(EntityRenderer<?> value) {
|
||||
return put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Map.Entry<EntityType<?>, EntityRenderer<?>>> entrySet() {
|
||||
return new AbstractSet<>() {
|
||||
@Override
|
||||
public Iterator<Map.Entry<EntityType<?>, EntityRenderer<?>>> iterator() {
|
||||
return Iterators.transform(Iterators.unmodifiableIterator(rendererProviders.keySet().iterator()), Entry::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof Map.Entry<?,?> e) {
|
||||
return rendererProviders.containsKey(e.getKey()) && Objects.equals(get(e.getKey()), e.getValue());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rendererProviders.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.embeddedt.modernfix.entity;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.culling.Frustum;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
public class ErroredEntityRenderer<T extends Entity> extends EntityRenderer<T> {
|
||||
public ErroredEntityRenderer(EntityRendererProvider.Context arg) {
|
||||
super(arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureLocation(T entity) {
|
||||
return TextureAtlas.LOCATION_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRender(T livingEntity, Frustum camera, double camX, double camY, double camZ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(T entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package org.embeddedt.modernfix.tickables;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LoadableTickableObject<T> implements TickableObject {
|
||||
private volatile int ticksInactive = 0;
|
||||
private final int timeout;
|
||||
private final Supplier<T> loader;
|
||||
private final Consumer<T> finalizer;
|
||||
private volatile T theObject = null;
|
||||
|
||||
public LoadableTickableObject(int timeout, Supplier<T> loader, Consumer<T> finalizer) {
|
||||
this(timeout, loader, finalizer, null);
|
||||
}
|
||||
|
||||
public LoadableTickableObject(int timeout, Supplier<T> loader, Consumer<T> finalizer, @Nullable T initialValue) {
|
||||
this.timeout = timeout;
|
||||
this.loader = loader;
|
||||
this.finalizer = finalizer;
|
||||
this.theObject = initialValue;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
synchronized (this) {
|
||||
ticksInactive++;
|
||||
T obj = theObject;
|
||||
if(obj == null) {
|
||||
obj = loader.get();
|
||||
theObject = obj;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public final void tick() {
|
||||
synchronized (this) {
|
||||
ticksInactive++;
|
||||
if(ticksInactive >= this.timeout) {
|
||||
finalizer.accept(theObject);
|
||||
theObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package org.embeddedt.modernfix.tickables;
|
||||
|
||||
public interface TickableObject {
|
||||
void tick();
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.tickables;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class TickableObjectManager {
|
||||
private static final List<TickableObject> TICKABLE_OBJECT_LIST = new CopyOnWriteArrayList<>();
|
||||
|
||||
public static void register(TickableObject object) {
|
||||
TICKABLE_OBJECT_LIST.add(object);
|
||||
}
|
||||
|
||||
public static void runTick() {
|
||||
for(TickableObject o : TICKABLE_OBJECT_LIST) {
|
||||
o.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Interner;
|
||||
import com.google.common.collect.Interners;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Replacement backing map for CompoundTags that interns keys.
|
||||
*/
|
||||
public class CanonizingStringMap<T> extends HashMap<String, T> {
|
||||
private static final Interner<String> KEY_INTERNER = Interners.newWeakInterner();
|
||||
|
||||
private static String intern(String key) {
|
||||
return key != null ? KEY_INTERNER.intern(key) : null;
|
||||
}
|
||||
|
||||
public CanonizingStringMap() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T put(String key, T value) {
|
||||
return super.put(intern(key), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends T> m) {
|
||||
if(m.isEmpty())
|
||||
return;
|
||||
HashMap<String, T> tmp = new HashMap<>();
|
||||
m.forEach((k, v) -> tmp.put(intern(k), v));
|
||||
super.putAll(tmp);
|
||||
}
|
||||
|
||||
private void putAllWithoutInterning(Map<? extends String, ? extends T> m) {
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
public static <T> CanonizingStringMap<T> deepCopy(CanonizingStringMap<T> incomingMap, Function<T, T> deepCopier) {
|
||||
CanonizingStringMap<T> newMap = new CanonizingStringMap<>();
|
||||
newMap.putAllWithoutInterning(Maps.transformValues(incomingMap, deepCopier));
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.AbstractExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DirectExecutorService extends AbstractExecutorService {
|
||||
private boolean isShutdown;
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
isShutdown = true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Runnable> shutdownNow() {
|
||||
isShutdown = true;
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown() {
|
||||
return isShutdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminated() {
|
||||
return isShutdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean awaitTermination(long timeout, @NotNull TimeUnit unit) throws InterruptedException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull Runnable command) {
|
||||
command.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.world.Difficulty;
|
||||
import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||
import net.minecraft.world.level.storage.WorldData;
|
||||
import net.minecraft.world.level.storage.ServerLevelData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class DummyServerConfiguration implements WorldData {
|
||||
@Override
|
||||
public WorldDataConfiguration getDataConfiguration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataConfiguration(WorldDataConfiguration arg) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRemovedFeatureFlags() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wasModded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKnownServerBrands() {
|
||||
return ImmutableSet.of("forge");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModdedInfo(String name, boolean isModded) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getCustomBossEvents() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomBossEvents(CompoundTag nbt) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevelData overworldData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelSettings getLevelSettings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag createTag(RegistryAccess registries, CompoundTag hostPlayerNBT) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHardcore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevelName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameType getGameType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameType(GameType type) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowCommands() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Difficulty getDifficulty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDifficulty(Difficulty difficulty) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDifficultyLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDifficultyLocked(boolean locked) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameRules getGameRules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getLoadedPlayerTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndDragonFight.Data endDragonFightData() {
|
||||
return EndDragonFight.Data.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEndDragonFightData(EndDragonFight.Data data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldOptions worldGenOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlatWorld() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugWorld() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle worldGenSettingsLifecycle() {
|
||||
return Lifecycle.stable();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class LRUMap<K, V> extends Object2ObjectLinkedOpenHashMap<K, V> {
|
||||
private Set<K> permanentEntries = Set.of();
|
||||
public LRUMap(Map<K, V> map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K k, V v) {
|
||||
return putAndMoveToLast(k, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object k) {
|
||||
return getAndMoveToLast((K)k);
|
||||
}
|
||||
|
||||
public void setPermanentEntries(Set<K> permanentEntries) {
|
||||
this.permanentEntries = permanentEntries;
|
||||
}
|
||||
|
||||
public void dropEntriesToMeetSize(int size) {
|
||||
int expectedQuota = size;
|
||||
// Increase allowed size quota to include permanent entries
|
||||
size += permanentEntries.size();
|
||||
int prevSize = size();
|
||||
if(size() > size) {
|
||||
var iterator = entrySet().iterator();
|
||||
while(size() > size && iterator.hasNext()) {
|
||||
var entry = iterator.next();
|
||||
var key = entry.getKey();
|
||||
if(key != null && !this.permanentEntries.contains(key)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
trim(size() + expectedQuota);
|
||||
if(ModernFixPlatformHooks.INSTANCE.isDevEnv()) {
|
||||
ModernFix.LOGGER.warn("Trimmed map from {} to {} entries", prevSize, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Simple forwarding map implementation that allows layering multiple maps together.
|
||||
*/
|
||||
public class LayeredForwardingMap<K, V> implements Map<K, V> {
|
||||
private final Map<K, V>[] layers;
|
||||
|
||||
public LayeredForwardingMap(Map<K, V>[] layers) {
|
||||
if(layers.length < 1)
|
||||
throw new IllegalArgumentException();
|
||||
for(Map<K, V> layer : layers) {
|
||||
if(layer == null)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for(Map<K, V> map : layers) {
|
||||
if(!map.isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
for(Map<K, V> map : layers) {
|
||||
if(map.containsKey(key))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
for(Map<K, V> map : layers) {
|
||||
if(map.containsValue(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
for(Map<K, V> map : layers) {
|
||||
V value = map.get(key);
|
||||
if(value != null)
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if(value == null)
|
||||
throw new IllegalArgumentException();
|
||||
V originalValue = null;
|
||||
for(Map<K, V> map : layers) {
|
||||
V oldVal = map.remove(key);
|
||||
if(originalValue == null)
|
||||
originalValue = oldVal;
|
||||
map.put(key, value);
|
||||
}
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
for(Map<K, V> map : layers) {
|
||||
map.remove(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
|
||||
for(V value : m.values()) {
|
||||
if(value == null)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for(Map<K, V> map : layers) {
|
||||
map.putAll(m);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
Set<K> keys = new ObjectOpenHashSet<>();
|
||||
for(Map<K, V> map : layers) {
|
||||
keys.addAll(map.keySet());
|
||||
}
|
||||
return Collections.unmodifiableSet(keys);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
Set<K> keys = keySet();
|
||||
List<V> vals = new ArrayList<>();
|
||||
for(K key : keys) {
|
||||
vals.add(get(key));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package org.embeddedt.modernfix.world;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.datafix.DataFixTypes;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class StrongholdLocationCache extends SavedData {
|
||||
private List<ChunkPos> chunkPosList;
|
||||
public StrongholdLocationCache() {
|
||||
super();
|
||||
chunkPosList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static SavedData.Factory<StrongholdLocationCache> factory(ServerLevel serverLevel) {
|
||||
// FIXME datafixer will probably throw on update
|
||||
return new SavedData.Factory<>(StrongholdLocationCache::new, StrongholdLocationCache::load, DataFixTypes.SAVED_DATA_FORCED_CHUNKS);
|
||||
}
|
||||
|
||||
public List<ChunkPos> getChunkPosList() {
|
||||
return new ArrayList<>(chunkPosList);
|
||||
}
|
||||
|
||||
public void setChunkPosList(List<ChunkPos> positions) {
|
||||
this.chunkPosList = new ArrayList<>(positions);
|
||||
this.setDirty();
|
||||
}
|
||||
|
||||
public static StrongholdLocationCache load(CompoundTag arg, HolderLookup.Provider provider) {
|
||||
StrongholdLocationCache cache = new StrongholdLocationCache();
|
||||
if(arg.contains("Positions", Tag.TAG_LONG_ARRAY)) {
|
||||
long[] positions = arg.getLongArray("Positions");
|
||||
for(long position : positions) {
|
||||
cache.chunkPosList.add(new ChunkPos(position));
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag compoundTag, HolderLookup.Provider provider) {
|
||||
long[] serialized = new long[chunkPosList.size()];
|
||||
for(int i = 0; i < chunkPosList.size(); i++) {
|
||||
ChunkPos thePos = chunkPosList.get(i);
|
||||
serialized[i] = thePos.toLong();
|
||||
}
|
||||
compoundTag.putLongArray("Positions", serialized);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
public static String getFileId(Holder<DimensionType> dimensionType) {
|
||||
return "mfix_strongholds";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
accessWidener v2 named
|
||||
|
||||
accessible field net/minecraft/client/multiplayer/ClientChunkCache storage Lnet/minecraft/client/multiplayer/ClientChunkCache$Storage;
|
||||
accessible field net/minecraft/client/multiplayer/ClientChunkCache lightEngine Lnet/minecraft/world/level/lighting/LevelLightEngine;
|
||||
mutable field net/minecraft/client/multiplayer/ClientChunkCache lightEngine Lnet/minecraft/world/level/lighting/LevelLightEngine;
|
||||
accessible class net/minecraft/client/multiplayer/ClientChunkCache$Storage
|
||||
accessible field net/minecraft/client/multiplayer/ClientChunkCache$Storage chunks Ljava/util/concurrent/atomic/AtomicReferenceArray;
|
||||
|
||||
accessible field net/minecraft/world/level/Level blockEntityTickers Ljava/util/List;
|
||||
|
||||
accessible class net/minecraft/client/renderer/RenderType$CompositeRenderType
|
||||
accessible method net/minecraft/nbt/CompoundTag <init> (Ljava/util/Map;)V
|
||||
|
||||
accessible class net/minecraft/world/level/levelgen/SurfaceRules$SequenceRule
|
||||
accessible class net/minecraft/world/level/levelgen/SurfaceRules$SurfaceRule
|
||||
accessible class net/minecraft/world/level/levelgen/DensityFunctions$Marker
|
||||
accessible class net/minecraft/world/level/levelgen/DensityFunctions$Marker$Type
|
||||
accessible method net/minecraft/world/level/levelgen/DensityFunctions$Marker <init> (Lnet/minecraft/world/level/levelgen/DensityFunctions$Marker$Type;Lnet/minecraft/world/level/levelgen/DensityFunction;)V
|
||||
accessible class net/minecraft/world/level/levelgen/DensityFunctions$Mapped
|
||||
accessible class net/minecraft/world/level/levelgen/DensityFunctions$Mapped$Type
|
||||
accessible method net/minecraft/world/level/levelgen/DensityFunctions$Mapped <init> (Lnet/minecraft/world/level/levelgen/DensityFunctions$Mapped$Type;Lnet/minecraft/world/level/levelgen/DensityFunction;DD)V
|
||||
accessible class net/minecraft/world/level/levelgen/DensityFunctions$MulOrAdd
|
||||
accessible class net/minecraft/world/level/levelgen/DensityFunctions$MulOrAdd$Type
|
||||
accessible method net/minecraft/world/level/levelgen/DensityFunctions$MulOrAdd <init> (Lnet/minecraft/world/level/levelgen/DensityFunctions$MulOrAdd$Type;Lnet/minecraft/world/level/levelgen/DensityFunction;DDD)V
|
||||
|
||||
accessible class net/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase$Cache
|
||||
accessible class net/minecraft/server/level/ServerChunkCache$MainThreadExecutor
|
||||
accessible field net/minecraft/world/level/block/state/BlockBehaviour properties Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;
|
||||
accessible class net/minecraft/client/renderer/block/model/BlockElementFace$Deserializer
|
||||
accessible class net/minecraft/client/renderer/texture/Stitcher$Holder
|
||||
accessible field net/minecraft/client/renderer/texture/Stitcher$Holder width I
|
||||
accessible field net/minecraft/client/renderer/texture/Stitcher$Holder height I
|
||||
accessible field net/minecraft/network/syncher/EntityDataAccessor id I
|
||||
mutable field net/minecraft/network/syncher/EntityDataAccessor id I
|
||||
accessible method net/minecraft/Util makeExecutor (Ljava/lang/String;)Ljava/util/concurrent/ExecutorService;
|
||||
accessible field net/minecraft/server/level/ChunkMap updatingChunkMap Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
|
||||
accessible field net/minecraft/server/level/ChunkMap visibleChunkMap Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
|
||||
accessible field net/minecraft/server/level/ChunkMap pendingUnloads Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
|
||||
accessible method net/minecraft/resources/ResourceKey <init> (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)V
|
||||
accessible field net/minecraft/client/renderer/block/model/BlockModel GSON Lcom/google/gson/Gson;
|
||||
accessible class net/minecraft/server/level/ChunkMap$DistanceManager
|
||||
accessible class net/minecraft/client/resources/model/ModelBakery$BakedCacheKey
|
||||
accessible method net/minecraft/client/resources/model/ModelBakery$BakedCacheKey <init> (Lnet/minecraft/resources/ResourceLocation;Lcom/mojang/math/Transformation;Z)V
|
||||
accessible class net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl
|
||||
accessible method net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl <init> (Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/resources/model/ModelBakery$TextureGetter;Lnet/minecraft/client/resources/model/ModelResourceLocation;)V
|
||||
accessible method net/minecraft/client/resources/model/ModelBakery getModel (Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/UnbakedModel;
|
||||
accessible class net/minecraft/world/level/chunk/PalettedContainer$Data
|
||||
accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/MinecraftServer$ReloadableResources;
|
||||
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
|
||||
accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;
|
||||
accessible field net/minecraft/client/KeyMapping ALL Ljava/util/Map;
|
||||
accessible field net/minecraft/client/renderer/block/model/multipart/MultiPart definition Lnet/minecraft/world/level/block/state/StateDefinition;
|
||||
accessible field net/minecraft/client/renderer/block/model/ItemOverrides$BakedOverride model Lnet/minecraft/client/resources/model/BakedModel;
|
||||
mutable field net/minecraft/client/renderer/block/model/ItemOverrides$BakedOverride model Lnet/minecraft/client/resources/model/BakedModel;
|
||||
accessible field net/minecraft/client/renderer/entity/EnderDragonRenderer$DragonModel entity Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;
|
||||
accessible method net/minecraft/world/level/block/state/StateDefinition appendPropertyCodec (Lcom/mojang/serialization/MapCodec;Ljava/util/function/Supplier;Ljava/lang/String;Lnet/minecraft/world/level/block/state/properties/Property;)Lcom/mojang/serialization/MapCodec;
|
||||
accessible class net/minecraft/client/multiplayer/SessionSearchTrees$Key
|
||||
|
||||
accessible field net/minecraft/server/packs/resources/ProfiledReloadInstance$State preparationNanos Ljava/util/concurrent/atomic/AtomicLong;
|
||||
accessible field net/minecraft/server/packs/resources/ProfiledReloadInstance$State reloadNanos Ljava/util/concurrent/atomic/AtomicLong;
|
||||
|
||||
accessible class net/minecraft/world/item/crafting/Ingredient$Value
|
||||
accessible class net/minecraft/world/item/crafting/Ingredient$ItemValue
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
plugins {
|
||||
id "com.github.johnrengelman.shadow"
|
||||
id 'com.adarshr.test-logger' version '3.2.0'
|
||||
id "modernfix.mod-common-conventions"
|
||||
id "modernfix.platform-conventions"
|
||||
}
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
fabric()
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
|
||||
modIncludeImplementation
|
||||
|
||||
include.extendsFrom modIncludeImplementation
|
||||
modImplementation.extendsFrom modIncludeImplementation
|
||||
|
||||
testAgent {
|
||||
canBeConsumed = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
testImplementation "net.fabricmc:fabric-loader-junit:${rootProject.fabric_loader_version}"
|
||||
|
||||
modCompileOnly(fabricApi.module("fabric-api-base", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-model-loading-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-data-generation-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
if(project.use_fabric_api_at_runtime.toBoolean()) {
|
||||
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
||||
modImplementation "curse.maven:spark-361579:${rootProject.spark_version}"
|
||||
modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}") { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
} else {
|
||||
modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
||||
modCompileOnly "curse.maven:spark-361579:${rootProject.spark_version}"
|
||||
}
|
||||
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
// modApi "me.shedaniel:architectury-fabric:${rootProject.architectury_version}"
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
testImplementation(shadowCommon(project(path: ":common", configuration: "transformProductionFabric"))) { transitive false }
|
||||
shadowCommon(project(path: ":annotations"))
|
||||
|
||||
testImplementation(platform("org.junit:junit-bom:${project.junit_version}"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-params")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
|
||||
testImplementation("org.junit.platform:junit-platform-launcher")
|
||||
testImplementation("org.assertj:assertj-core:3.19.0")
|
||||
testImplementation("com.google.guava:guava-testlib:21.0")
|
||||
testImplementation("org.mockito:mockito-junit-jupiter:5.3.1")
|
||||
|
||||
testAgent(project("path": ":test_agent", "configuration": "agentJar"))
|
||||
}
|
||||
|
||||
tasks.named("test") {
|
||||
useJUnitPlatform()
|
||||
def runDir = file('test_run')
|
||||
doFirst() {
|
||||
runDir.mkdir()
|
||||
}
|
||||
workingDir = runDir
|
||||
systemProperty 'modernfix.ignoreConfigForTesting', 'true'
|
||||
|
||||
// inject our custom agent to fix #817
|
||||
FileCollection agentFile = configurations.getByName("testAgent")
|
||||
jvmArgs "-javaagent:${agentFile.singleFile.absolutePath}"
|
||||
dependsOn(agentFile)
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude "architectury.common.json"
|
||||
|
||||
configurations = [project.configurations.shadowCommon]
|
||||
archiveClassifier.set("dev-shadow")
|
||||
}
|
||||
|
||||
remapJar {
|
||||
injectAccessWidener = true
|
||||
input.set shadowJar.archiveFile
|
||||
dependsOn shadowJar
|
||||
archiveClassifier.set(null)
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveClassifier.set("dev")
|
||||
}
|
||||
|
||||
components.java {
|
||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenFabric(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name + "-" + project.name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import org.embeddedt.modernfix.fabric.datagen.RuntimeDatagen;
|
||||
|
||||
public class ModernFixClientFabric implements ClientModInitializer {
|
||||
public static ModernFixClient commonMod;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
commonMod = new ModernFixClient();
|
||||
|
||||
if(FabricLoader.getInstance().isModLoaded("fabric-data-generation-api-v1")) {
|
||||
RuntimeDatagen.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class ModernFixFabric implements ModInitializer {
|
||||
public static ModernFix commonMod;
|
||||
public static WeakReference<MinecraftServer> theServer = new WeakReference<>(null);
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
commonMod = new ModernFix();
|
||||
|
||||
// TODO: implement entity ID desync
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
|
||||
import net.fabricmc.loader.impl.gui.FabricGuiEntry;
|
||||
import net.fabricmc.loader.impl.gui.FabricStatusTree;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
|
||||
import org.embeddedt.modernfix.util.CommonModUtil;
|
||||
|
||||
public class ModernFixPreLaunchFabric implements PreLaunchEntrypoint {
|
||||
@Override
|
||||
public void onPreLaunch() {
|
||||
if(ModernFixMixinPlugin.instance == null) {
|
||||
System.err.println("Mixin plugin not loaded yet");
|
||||
return;
|
||||
}
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_launch.OnFabric")) {
|
||||
CommonModUtil.runWithoutCrash(() -> SparkLaunchProfiler.start("launch"), "Failed to start profiler");
|
||||
}
|
||||
|
||||
// Prevent launching with Continuity when dynamic resources is on
|
||||
if(false && ModernFixMixinPlugin.instance.isOptionEnabled("perf.dynamic_resources.ContinuityCheck")
|
||||
&& FabricLoader.getInstance().isModLoaded("continuity")) {
|
||||
CommonModUtil.runWithoutCrash(() -> {
|
||||
FabricGuiEntry.displayError("Compatibility warning", null, tree -> {
|
||||
FabricStatusTree.FabricStatusTab crashTab = tree.addTab("Warning");
|
||||
crashTab.node.addMessage("Continuity and ModernFix's dynamic resources option are not compatible before Minecraft 1.19.4.", FabricStatusTree.FabricTreeWarningLevel.ERROR);
|
||||
crashTab.node.addMessage("Remove Continuity or disable dynamic resources in the ModernFix config.", FabricStatusTree.FabricTreeWarningLevel.ERROR);
|
||||
tree.tabs.removeIf(tab -> tab != crashTab);
|
||||
}, true);
|
||||
}, "display Continuity warning");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.api.dynresources;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ModelScanController {
|
||||
public static final List<Predicate<ResourceLocation>> SCAN_PREDICATES = new ArrayList<>();
|
||||
public static boolean shouldScanAndTestWrapping(ResourceLocation location) {
|
||||
if(SCAN_PREDICATES.size() > 0) {
|
||||
for(Predicate<ResourceLocation> predicate : SCAN_PREDICATES) {
|
||||
if(!predicate.test(location))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.datagen;
|
||||
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.fabricmc.fabric.impl.datagen.FabricDataGenHelper;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.screens.TitleScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class RuntimeDatagen {
|
||||
private static final boolean SHOULD_RUNTIME_DATAGEN = System.getProperty("fabric-api.datagen.output-dir") != null;
|
||||
|
||||
private static void runRuntimeDatagen() {
|
||||
// call runInternal directly to avoid exiting immediately
|
||||
try {
|
||||
System.setProperty("fabric-api.datagen", "true");
|
||||
Method method = FabricDataGenHelper.class.getDeclaredMethod("runInternal");
|
||||
method.setAccessible(true);
|
||||
method.invoke(null);
|
||||
} catch(Throwable e) {
|
||||
ModernFix.LOGGER.error("Error running datagen", e);
|
||||
} finally {
|
||||
System.clearProperty("fabric-api.datagen");
|
||||
}
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if(!SHOULD_RUNTIME_DATAGEN)
|
||||
return;
|
||||
ScreenEvents.AFTER_INIT.register(((client, s, scaledWidth, scaledHeight) -> {
|
||||
if(s instanceof TitleScreen screen) {
|
||||
screen.addRenderableWidget(Button.builder(Component.literal("DG"), (arg) -> {
|
||||
runRuntimeDatagen();
|
||||
}).pos(screen.width / 2 - 100 - 50, screen.height / 4 + 48).size(50, 20).build());
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.core;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientConfigurationPacketListenerImpl;
|
||||
import org.embeddedt.modernfix.ModernFixClientFabric;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientConfigurationPacketListenerImpl.class)
|
||||
@ClientOnlyMixin
|
||||
public class ClientCommonPacketListenerImplMixin {
|
||||
@Inject(method = "handleUpdateTags", at = @At("RETURN"))
|
||||
private void signalTags(CallbackInfo ci) {
|
||||
ModernFixClientFabric.commonMod.onTagsUpdated();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.core;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
@ClientOnlyMixin
|
||||
public class ClientMinecraftServerMixin {
|
||||
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getNanos()J", ordinal = 0))
|
||||
private void markServerStarted(CallbackInfo ci) {
|
||||
ModernFixClient.INSTANCE.onServerStarted((MinecraftServer)(Object)this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.core;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import org.embeddedt.modernfix.ModernFixClientFabric;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = ClientPacketListener.class, priority = 1500)
|
||||
@ClientOnlyMixin
|
||||
public class ClientPlayNetHandlerMixin {
|
||||
@Inject(method = "handleUpdateRecipes", at = @At("RETURN"))
|
||||
private void signalRecipes(CallbackInfo ci) {
|
||||
ModernFixClientFabric.commonMod.onRecipesUpdated();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.core;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
@ClientOnlyMixin
|
||||
public class MCMixin_Fabric {
|
||||
@Inject(method = "tick", at = @At("RETURN"))
|
||||
private void onRenderTickEnd(CallbackInfo ci) {
|
||||
ModernFixClient.INSTANCE.onRenderTickEnd();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.core;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixFabric;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin {
|
||||
@Inject(method = "runServer", at = @At("HEAD"))
|
||||
private void changeServerReference(CallbackInfo ci) {
|
||||
ModernFixFabric.theServer = new WeakReference<>((MinecraftServer)(Object)this);
|
||||
}
|
||||
|
||||
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getNanos()J", ordinal = 0))
|
||||
private void hookServerStarted(CallbackInfo ci) {
|
||||
ModernFix.INSTANCE.onServerStarted();
|
||||
}
|
||||
|
||||
@Inject(method = "stopServer", at = @At("RETURN"))
|
||||
private void hookServerShutdown(CallbackInfo ci) {
|
||||
ModernFix.INSTANCE.onServerDead((MinecraftServer)(Object)this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.feature.branding;
|
||||
|
||||
import net.minecraft.client.gui.components.DebugScreenOverlay;
|
||||
import org.embeddedt.modernfix.ModernFixClientFabric;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(DebugScreenOverlay.class)
|
||||
@ClientOnlyMixin
|
||||
public class GuiMixin {
|
||||
@ModifyVariable(method = "getSystemInformation", at = @At("STORE"), ordinal = 0, require = 0)
|
||||
private List<String> addModernFix(List<String> list) {
|
||||
list.add("");
|
||||
list.add(ModernFixClientFabric.commonMod.brandingString);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.feature.measure_time;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
@ClientOnlyMixin
|
||||
public class MinecraftMixin_Fabric {
|
||||
@Inject(method = "doWorldLoad", at = @At("HEAD"))
|
||||
private void recordWorldLoadStart(CallbackInfo ci) {
|
||||
ModernFixClient.worldLoadStartTime = System.nanoTime();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.perf.faster_command_suggestions;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Simple hack-fix to limit the number of suggestions being processed. Not a perfect fix but mitigates lag decently
|
||||
* on an i3-4150.
|
||||
*/
|
||||
@Mixin(SuggestionsBuilder.class)
|
||||
public class SuggestionsBuilderMixin {
|
||||
@Unique
|
||||
private static final int MAX_SUGGESTIONS = 10000;
|
||||
|
||||
@Shadow(remap = false) @Final @Mutable
|
||||
private List<Suggestion> result;
|
||||
|
||||
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z"), require = 0)
|
||||
private <T> boolean addIfFits(List<T> list, T entry) {
|
||||
if(list != result || list.size() < MAX_SUGGESTIONS) {
|
||||
return list.add(entry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.safety;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(DynamicTexture.class)
|
||||
@ClientOnlyMixin
|
||||
public class DynamicTextureMixin {
|
||||
@Shadow @Nullable private NativeImage pixels;
|
||||
|
||||
private Exception closeTrace;
|
||||
|
||||
@Inject(method = "method_22793", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/texture/DynamicTexture;pixels:Lcom/mojang/blaze3d/platform/NativeImage;", ordinal = 0))
|
||||
private void checkNullPixels(CallbackInfo ci) {
|
||||
if(pixels == null) {
|
||||
ModernFix.LOGGER.error("Attempted to upload null texture! This is not allowed, closed here", closeTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "close", at = @At("HEAD"))
|
||||
private void storeCloseTrace(CallbackInfo ci) {
|
||||
closeTrace = new Exception();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.modmenu;
|
||||
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
import org.embeddedt.modernfix.screen.ModernFixConfigScreen;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ModernFixModMenuApiImpl implements ModMenuApi {
|
||||
@Override
|
||||
public ConfigScreenFactory<ModernFixConfigScreen> getModConfigScreenFactory() {
|
||||
return ModernFixConfigScreen::new;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
package org.embeddedt.modernfix.platform.fabric;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.loader.api.metadata.CustomValue;
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.embeddedt.modernfix.ModernFixFabric;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
|
||||
import org.embeddedt.modernfix.util.CommonModUtil;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks {
|
||||
public boolean isClient() {
|
||||
return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT;
|
||||
}
|
||||
|
||||
public boolean isDedicatedServer() {
|
||||
return FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER;
|
||||
}
|
||||
|
||||
private static final String verString = FabricLoader.getInstance().getModContainer("modernfix")
|
||||
.map(mfModContainer -> mfModContainer.getMetadata().getVersion().getFriendlyString())
|
||||
.orElse("[unknown]");
|
||||
|
||||
public String getVersionString() {
|
||||
return verString;
|
||||
}
|
||||
|
||||
public boolean modPresent(String modId) {
|
||||
return FabricLoader.getInstance().getModContainer(modId).isPresent();
|
||||
}
|
||||
|
||||
public boolean isDevEnv() {
|
||||
return FabricLoader.getInstance().isDevelopmentEnvironment();
|
||||
}
|
||||
|
||||
public MinecraftServer getCurrentServer() {
|
||||
return ModernFixFabric.theServer.get();
|
||||
}
|
||||
|
||||
public boolean isEarlyLoadingNormally() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isLoadingNormally() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Path getGameDirectory() {
|
||||
return FabricLoader.getInstance().getGameDir();
|
||||
}
|
||||
|
||||
public void sendPacket(ServerPlayer player, CustomPacketPayload packet) {
|
||||
//PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
||||
}
|
||||
|
||||
public void injectPlatformSpecificHacks() {
|
||||
}
|
||||
|
||||
public void applyASMTransformers(String mixinClassName, ClassNode targetClass) {
|
||||
|
||||
}
|
||||
|
||||
public void onServerCommandRegister(Consumer<CommandDispatcher<CommandSourceStack>> handler) {
|
||||
if(FabricLoader.getInstance().isModLoaded("fabric-command-api-v2"))
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, arg, env) -> handler.accept(dispatcher));
|
||||
}
|
||||
|
||||
private static Multimap<String, String> modOptions;
|
||||
public Multimap<String, String> getCustomModOptions() {
|
||||
if(modOptions == null) {
|
||||
modOptions = ArrayListMultimap.create();
|
||||
for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
|
||||
ModMetadata meta = container.getMetadata();
|
||||
if (meta.containsCustomValue(IntegrationConstants.INTEGRATIONS_KEY)) {
|
||||
CustomValue integrations = meta.getCustomValue(IntegrationConstants.INTEGRATIONS_KEY);
|
||||
if (integrations.getType() != CustomValue.CvType.OBJECT) {
|
||||
continue;
|
||||
}
|
||||
for (Map.Entry<String, CustomValue> entry : integrations.getAsObject()) {
|
||||
if(entry.getValue().getType() != CustomValue.CvType.STRING)
|
||||
continue;
|
||||
modOptions.put(entry.getKey(), entry.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return modOptions;
|
||||
}
|
||||
|
||||
public void onLaunchComplete() {
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_launch.OnFabric")) {
|
||||
CommonModUtil.runWithoutCrash(() -> SparkLaunchProfiler.stop("launch"), "Failed to stop profiler");
|
||||
}
|
||||
}
|
||||
|
||||
public String getPlatformName() {
|
||||
return "Fabric";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "modernfix",
|
||||
"version": "${version}",
|
||||
"name": "ModernFix",
|
||||
"description": "Egregious, yet effective performance improvements for modern Minecraft",
|
||||
"authors": [
|
||||
"embeddedt"
|
||||
],
|
||||
"contact": {
|
||||
"sources": "https://github.com/embeddedt/ModernFix",
|
||||
"homepage": "https://modrinth.com/mod/modernfix",
|
||||
"issues": "https://github.com/embeddedt/ModernFix/issues"
|
||||
},
|
||||
"license": "LGPL-3.0",
|
||||
"icon": "icon.png",
|
||||
"custom": {
|
||||
"modmenu": {
|
||||
"links": {
|
||||
"modmenu.kofi": "https://ko-fi.com/embeddedt",
|
||||
"modmenu.github_releases": "https://github.com/embeddedt/ModernFix/releases",
|
||||
"modmenu.curseforge": "https://www.curseforge.com/minecraft/mc-mods/modernfix"
|
||||
}
|
||||
}
|
||||
},
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"org.embeddedt.modernfix.ModernFixFabric"
|
||||
],
|
||||
"client": [
|
||||
"org.embeddedt.modernfix.ModernFixClientFabric"
|
||||
],
|
||||
"modmenu": [ "org.embeddedt.modernfix.fabric.modmenu.ModernFixModMenuApiImpl" ],
|
||||
"preLaunch": [
|
||||
"org.embeddedt.modernfix.ModernFixPreLaunchFabric"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"modernfix-fabric.mixins.json",
|
||||
"modernfix-common.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"minecraft": ">=1.16.2",
|
||||
"fabricloader": ">=0.16.10"
|
||||
},
|
||||
"breaks": {
|
||||
"dashloader": "<5.0.0-beta.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
package net.minecraft.world.level.block.state;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.embeddedt.modernfix.testing.util.BootstrapMinecraft;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@BootstrapMinecraft
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class BlockStateCacheTest {
|
||||
@BeforeEach
|
||||
public void rebuildCache() {
|
||||
Blocks.rebuildCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initially, the cache should be invalid, and null.
|
||||
*/
|
||||
@Test
|
||||
@Order(1)
|
||||
public void testCacheNullInitially() {
|
||||
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
|
||||
assertTrue(((IBlockState)stoneBlock).isCacheInvalid());
|
||||
assertNull(stoneBlock.cache);
|
||||
|
||||
// make sure lazy cache correctly handles solid
|
||||
assertTrue(stoneBlock.isSolid());
|
||||
}
|
||||
|
||||
/**
|
||||
* When an API that needs the cache is called, it should be built and the invalid flag
|
||||
* becomes false.
|
||||
*/
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testCacheBuiltByRequest() {
|
||||
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
|
||||
stoneBlock.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
||||
assertFalse(((IBlockState)stoneBlock).isCacheInvalid());
|
||||
assertNotNull(stoneBlock.cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a second rebuild occurs, the invalid flag should be set to true, but the old cache
|
||||
* is not set to null, in order to prevent NPEs if a second thread is accessing the cache
|
||||
* when this takes place.
|
||||
*/
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testCacheInvalidatedByLateRebuild() {
|
||||
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
|
||||
stoneBlock.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
||||
Blocks.rebuildCache();
|
||||
assertTrue(((IBlockState)stoneBlock).isCacheInvalid());
|
||||
assertNotNull(stoneBlock.cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the fluidState and isRandomlyTicking caching fields added by Mojang to blockstates are correctly
|
||||
* handled by the dynamic cache system.
|
||||
*/
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testExtraFieldCachingCorrect() {
|
||||
Block[] blocksToCheck = new Block[] { Blocks.WATER, Blocks.FARMLAND };
|
||||
for(Block block : blocksToCheck) {
|
||||
for(BlockState state : block.getStateDefinition().getPossibleStates()) {
|
||||
// check that the fluid states match
|
||||
assertEquals(block.getFluidState(state), state.getFluidState(), "mismatched fluid state on " + state);
|
||||
// check that random ticking flag matches
|
||||
assertEquals(block.isRandomlyTicking(state), state.isRandomlyTicking(), "mismatched random tick state on " + state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
@Order(5)
|
||||
public void checkRecursiveFluidState() {
|
||||
Block b = new Block(BlockBehaviour.Properties.copy(Blocks.STONE)) {
|
||||
@Override
|
||||
public FluidState getFluidState(BlockState state) {
|
||||
return state.getFluidState();
|
||||
}
|
||||
};
|
||||
BlockState state = b.getStateDefinition().any();
|
||||
((IBlockState)state).clearCache();
|
||||
// this should not throw
|
||||
state.getFluidState();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.BuiltInModel;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.embeddedt.modernfix.testing.util.BootstrapMinecraft;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@BootstrapMinecraft
|
||||
public class DynamicModelCacheTest {
|
||||
@Test
|
||||
public void testCacheReturnsNullForNullGetter() {
|
||||
DynamicModelCache<Item> cache = new DynamicModelCache(k -> null, true);
|
||||
assertNull(cache.get(Items.STONE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheFunctions() {
|
||||
BakedModel model = new BuiltInModel(null, null, null, false);
|
||||
DynamicModelCache<Item> cache = new DynamicModelCache(k -> model, true);
|
||||
assertEquals(model, cache.get(Items.STONE));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package org.embeddedt.modernfix.testing.util;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@ExtendWith({ BootstrapMinecraftExtension.class })
|
||||
public @interface BootstrapMinecraft {
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.embeddedt.modernfix.testing.util;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.IdentityHashMap;
|
||||
|
||||
/**
|
||||
* Simple extension to run vanilla bootstrap, inspired by AE2.
|
||||
*/
|
||||
public class BootstrapMinecraftExtension implements Extension, BeforeAllCallback, AfterAllCallback {
|
||||
@Override
|
||||
public void beforeAll(ExtensionContext context) throws Exception {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
// Allow blocks to be created in tests
|
||||
Field field = MappedRegistry.class.getDeclaredField("unregisteredIntrusiveHolders");
|
||||
field.setAccessible(true);
|
||||
if(field.get(BuiltInRegistries.BLOCK) == null) {
|
||||
field.set(BuiltInRegistries.BLOCK, new IdentityHashMap<>());
|
||||
field = MappedRegistry.class.getDeclaredField("frozen");
|
||||
field.setAccessible(true);
|
||||
field.setBoolean(BuiltInRegistries.BLOCK, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll(ExtensionContext context) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
plugins {
|
||||
id 'dev.architectury.loom'
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = project(":common").loom.accessWidenerPath
|
||||
runs {
|
||||
client {
|
||||
vmArgs "-Xmx8G"
|
||||
property("modernfix.config.mixin.perf.blast_search_trees", "true")
|
||||
property("modernfix.config.mixin.perf.dynamic_resources", "true")
|
||||
property("modernfix.config.mixin.perf.dynamic_block_codecs", "true")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||
mappings loom.layered() {
|
||||
officialMojangMappings()
|
||||
}
|
||||
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation(fabricApi.module("fabric-models-v0", "0.84.0+1.20.1")) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation(fabricApi.module("fabric-registry-sync-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation(fabricApi.module("fabric-renderer-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation("net.fabricmc.fabric-api:fabric-rendering-data-attachment-v1:0.3.36+92a0d36777") { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modRuntimeOnly(fabricApi.module("fabric-renderer-indigo", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
|
||||
implementation project(path: ":common", configuration: "namedElements")
|
||||
implementation project(path: ":fabric", configuration: "namedElements")
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
// Make genSources do nothing in this project
|
||||
project.gradle.startParameter.excludedTaskNames.add("genSources")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user