Skip to content

Commit 70a762d

Browse files
committed
重要兼容性修复、修复咒法学的粒子渲染问题
1 parent 37c9acb commit 70a762d

18 files changed

+105
-32
lines changed

build.gradle

+5-5
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,10 @@ dependencies {
108108
runtimeOnly("io.github.douira:glsl-transformer:2.0.1")
109109
runtimeOnly("org.anarres:jcpp:1.4.14")
110110

111-
// modRuntimeOnly("maven.modrinth:create-fabric:0.5.1-j-build.1631+mc1.20.1")
112111
// modRuntimeOnly("maven.modrinth:brute-force-rendering-culling:F6dedvxg")
113112
modRuntimeOnly("maven.modrinth:indium:1.0.34+mc1.20.1")
114-
115-
modRuntimeOnly("maven.modrinth:indium:1.0.34+mc1.20.1")
113+
// modRuntimeOnly("maven.modrinth:ebe:0.9+1.20")
114+
modCompileOnly("maven.modrinth:ebe:0.9+1.20")
116115

117116
modCompileOnly "net.minecraftforge:forge:1.20.1-47.3.0:universal"
118117

@@ -123,11 +122,12 @@ dependencies {
123122

124123
modCompileOnly("curse.maven:lodestone-616457:6070172")
125124
modCompileOnly("maven.modrinth:effective:2.3.2-1.20.1")
125+
modCompileOnly("maven.modrinth:hex-casting:0.11.2")
126126

127127
// modImplementation("maven.modrinth:effective:2.3.2-1.20.1") // put into /libs and unzip all jarinjars
128128
// modImplementation 'maven.modrinth:c2me-fabric:0.2.0+alpha.11.16+1.20.1' // put into /libs and unzip all jarinjars
129-
modRuntimeOnly fileTree(dir: 'libs', include: '*.jar', exclude: 'effective-1.0.2-all.jar')
130-
modCompileOnly fileTree(dir: 'libs', include: ['c2me-*.jar', 'effective-1.0.2-all.jar', 'tombstone-1.20.1-8.9.0.jar'])
129+
modLocalRuntime(fileTree(dir: 'libs', include: '*.jar', exclude: 'effective-1.0.2-all.jar'))
130+
modCompileOnly fileTree(dir: 'libs', include: ['effective-1.0.2-all.jar', 'tombstone-1.20.1-8.9.0.jar'])
131131
}
132132

133133
processResources {

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ loader_version=0.16.10
1111
fabric_version=0.92.3+1.20.1
1212

1313
# Mod Properties
14-
mod_version=1.4.8+1.20.1
14+
mod_version=1.4.10+1.20.1
1515
maven_group=fun.qu_an.minecraft
1616
archives_base_name=asyncparticles

src/main/java/fun/qu_an/minecraft/asyncparticles/client/APMixinPlugin.java

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ yield switch (split[1]) {
6363
case "sodium" -> ModListHelper.SODIUM_LOADED;
6464
case "flerovium" -> ModListHelper.FORGE_FLEROVIUM_LOADED;
6565
case "lodestone" -> ModListHelper.LODESTONE_LOADED;
66+
case "hexcasting" -> ModListHelper.HEXCASTING_LOADED;
6667
default -> true;
6768
};
6869
}

src/main/java/fun/qu_an/minecraft/asyncparticles/client/AsyncRenderer.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class AsyncRenderer {
6565

6666
static {
6767
AtomicInteger workerCount = new AtomicInteger(1);
68-
int clamp = Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, 5);
68+
int clamp = Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, 6);
6969
EXECUTOR = new ForkJoinPool(clamp, (forkJoinPool) -> {
7070
ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(forkJoinPool) {
7171
protected void onTermination(Throwable throwable) {
@@ -211,6 +211,9 @@ private static ParticleRenderingSettings getRenderingSettings() {
211211
}
212212

213213
public static BufferBuilder getBufferBuilder(ParticleRenderType particleRenderType) {
214+
// System.out.println(particleRenderType.getClass());
215+
// System.out.println(particleRenderType.hashCode());
216+
// FIXME: Some mod use record class as render type, FUCK
214217
return BUFFER_BUILDERS.computeIfAbsent(particleRenderType,
215218
k -> {
216219
// if (k != ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT) {

src/main/java/fun/qu_an/minecraft/asyncparticles/client/AsyncTicker.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
55
import fun.qu_an.minecraft.asyncparticles.client.config.SimplePropertiesConfig;
66
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
7-
import net.lointain.cosmos.procedures.SkyboxshapeProcedure;
87
import net.minecraft.Util;
98
import net.minecraft.client.Minecraft;
109
import net.minecraft.client.particle.Particle;
@@ -53,7 +52,7 @@ public class AsyncTicker {
5352

5453
static {
5554
AtomicInteger workerCount = new AtomicInteger(1);
56-
int clamp = Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, 5);
55+
int clamp = Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, 6);
5756
EXECUTOR = new ForkJoinPool(clamp, (forkJoinPool) -> {
5857
ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(forkJoinPool) {
5958
protected void onTermination(Throwable throwable) {
@@ -276,6 +275,10 @@ public static void registerEndTickEvent(Runnable operation) {
276275

277276
public static void destroy() {
278277
cancelled = true;
278+
if (particleCleanup != null) {
279+
particleCleanup.join();
280+
particleCleanup = null;
281+
}
279282
if (blockEntityTickFuture != null) {
280283
blockEntityTickFuture.join();
281284
blockEntityTickFuture = null;

src/main/java/fun/qu_an/minecraft/asyncparticles/client/ModListHelper.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ public class ModListHelper {
1818
public static final boolean FORGE_EFFECTIVE_LOADED = isForgeModLoaded("effective");
1919
public static final boolean FABRIC_EFFECTIVE_LOADED = isFabricModLoaded("effective");
2020
public static final boolean LODESTONE_LOADED = isModLoaded("lodestone");
21-
public static final boolean TOMBSTONE_LOADED = isModLoaded("tombstone");
2221
public static final boolean FORGE_LODESTONE_LOADED = isForgeModLoaded("lodestone");
2322
public static final boolean FABRIC_LODESTONE_LOADED = isFabricModLoaded("lodestone");
2423
public static final boolean FABRIC_PARTICLERAIN_LOADED = isFabricModLoaded("particlerain");
2524
public static final boolean FORGE_PARTICLERAIN_LOADED = isForgeModLoaded("particlerain");
2625
public static final boolean FABRIC_CREATE_LOADED = isFabricModLoaded("create");
2726
public static final boolean FORGE_CREATE_LOADED = isForgeModLoaded("create");
2827
public static final boolean FABRIC_EFFECTUAL_LOADED = isFabricModLoaded("effectual");
28+
public static final boolean TOMBSTONE_LOADED = isModLoaded("tombstone");
29+
public static final boolean HEXCASTING_LOADED = isModLoaded("hexcasting");
2930

3031
private static boolean isModLoaded(String modId) {
3132
return FabricLoader.getInstance().isModLoaded(modId);

src/main/java/fun/qu_an/minecraft/asyncparticles/client/config/SimplePropertiesConfig.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,12 @@ public static void load() throws IOException {
5252
private static boolean getBoolean(Properties properties, String key, boolean defaultValue) {
5353
String b = properties.getProperty(key);
5454
if (b != null) {
55-
return !Boolean.toString(!defaultValue).equalsIgnoreCase(b);
55+
// !Boolean.toString(!defaultValue).equalsIgnoreCase(b) ? defaultValue : !defaultValue;
56+
return Boolean.toString(!defaultValue).equalsIgnoreCase(b) != defaultValue;
5657
} else {
5758
properties.setProperty(key, String.valueOf(defaultValue));
5859
shouldSave = true;
5960
return defaultValue;
6061
}
6162
}
62-
63-
@FunctionalInterface
64-
private interface BooleanPropertyConsumer<T> {
65-
void accept(T value, boolean shouldSave);
66-
}
6763
}

src/main/java/fun/qu_an/minecraft/asyncparticles/client/mixin/MixinLevelRenderer.java

+1-6
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@
2323

2424
@Mixin(value = LevelRenderer.class, priority = 499)
2525
public abstract class MixinLevelRenderer {
26-
27-
@Shadow
28-
@Nullable
29-
private RenderTarget particlesTarget;
30-
3126
@Inject(method = "renderLevel", at = @At(value = "HEAD"))
3227
private void onRenderLevelHead(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) {
3328
AsyncRenderer.start(poseStack, f, camera, lightTexture);
@@ -36,7 +31,7 @@ private void onRenderLevelHead(PoseStack poseStack, float f, long l, boolean bl,
3631
@Inject(method = "renderLevel",
3732
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;renderWorldBorder(Lnet/minecraft/client/Camera;)V")),
3833
at = @At(value = "INVOKE", shift = At.Shift.AFTER, remap = false, target = "Lcom/mojang/blaze3d/systems/RenderSystem;applyModelViewMatrix()V"))
39-
private void onRenderLevelReturn(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) {
34+
private void onRenderLevelTail(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) {
4035
AsyncRenderer.join(poseStack, f, camera, lightTexture);
4136
}
4237

src/main/java/fun/qu_an/minecraft/asyncparticles/client/mixin/MixinParticleEngine.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ public void render(PoseStack poseStack, MultiBufferSource.BufferSource bufferSou
9797
poseStack2.mulPoseMatrix(poseStack.last().pose());
9898
RenderSystem.applyModelViewMatrix();
9999
}
100-
100+
// System.out.println(RENDER_ORDER);
101+
// System.out.println(particles.keySet());
102+
// Some mod has duplicated render type, cause concurrent access to the same queue
103+
// See MixinParticleEngine_Late.java
101104
for (ParticleRenderType particleRenderType : (ModListHelper.IS_FORGE ? particles.keySet() : RENDER_ORDER)) {
102105
Queue<Particle> iterable = this.particles.get(particleRenderType);
103106
if (iterable == null || iterable.isEmpty()) {
@@ -131,16 +134,15 @@ public void render(PoseStack poseStack, MultiBufferSource.BufferSource bufferSou
131134
if (bufferBuilder.building()) {
132135
RenderSystem.setShader(GameRenderer::getParticleShader);
133136
particleRenderType.begin(FakeBeginBufferBuilder.INSTANCE, this.textureManager);
134-
BufferUploader.drawWithShader(bufferBuilder.end());
135-
particleRenderType.end(FakeEndTesselator.INSTANCE);
137+
particleRenderType.end(FakeEndTesselator.INSTANCE
138+
.onEnd(() -> BufferUploader.drawWithShader(bufferBuilder.end())));
136139
}
137140
} else {
138141
if (!bufferBuilder.building()) {
139142
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE);
140143
}
141144
Runnable runnable = () -> iterable.forEach(particle -> {
142-
if (particle == null // might be null because ArrayDeque is not thread-safe
143-
|| !frustum.isVisible(particle.getBoundingBox())) {
145+
if (!frustum.isVisible(particle.getBoundingBox())) {
144146
return;
145147
}
146148
if (((ParticleAddon) particle).asyncedParticles$isRenderSync()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package fun.qu_an.minecraft.asyncparticles.client.mixin;
2+
3+
import com.google.common.collect.ImmutableList;
4+
import net.minecraft.client.particle.ParticleEngine;
5+
import net.minecraft.client.particle.ParticleRenderType;
6+
import org.spongepowered.asm.mixin.*;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
10+
11+
import java.util.*;
12+
13+
// TODO: 分为两个 Mixin
14+
@Mixin(value = ParticleEngine.class, priority = 2000)
15+
public abstract class MixinParticleEngine_Late {
16+
@Mutable
17+
@Final
18+
@Shadow
19+
private static List<ParticleRenderType> RENDER_ORDER;
20+
21+
// FIXME: Some mod has duplicated render type, cause concurrent access to the same queue...
22+
@Inject(at = @At("RETURN"), method = "<clinit>")
23+
private static void addTypes(CallbackInfo ci) {
24+
RENDER_ORDER = ImmutableList.<ParticleRenderType>builder().addAll(new LinkedHashSet<>(RENDER_ORDER)).build();
25+
}
26+
}

src/main/java/fun/qu_an/minecraft/asyncparticles/client/mixin/forge/flerovium/MixinMixinParticleEngine.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
public class MixinMixinParticleEngine {
1515
@SuppressWarnings("UnresolvedMixinReference")
1616
@TargetHandler(
17-
name = "lambda$render$0",
17+
name = "lambda$render$1",
1818
mixin = "fun.qu_an.minecraft.asyncparticles.client.mixin.MixinParticleEngine"
1919
)
2020
@Redirect(method = "@MixinSquared:Handler", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/culling/Frustum;isVisible(Lnet/minecraft/world/phys/AABB;)Z"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package fun.qu_an.minecraft.asyncparticles.client.mixin.hexcasting;
2+
3+
import at.petrak.hexcasting.client.particles.ConjureParticle;
4+
import net.minecraft.client.multiplayer.ClientLevel;
5+
import net.minecraft.client.particle.TextureSheetParticle;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
10+
11+
@Mixin(ConjureParticle.class)
12+
public abstract class MixinConjureParticle extends TextureSheetParticle {
13+
protected MixinConjureParticle(ClientLevel level, double x, double y, double z) {
14+
super(level, x, y, z);
15+
}
16+
17+
@Inject(method = "tick", at = @At("RETURN"))
18+
private void onTick(CallbackInfo ci) {
19+
if (alpha <= 0.001) {
20+
alpha = 0.0f;
21+
}
22+
}
23+
}

src/main/java/fun/qu_an/minecraft/asyncparticles/client/mixin/iris/MixinFullyBufferedMultiBufferSource.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
import com.mojang.blaze3d.systems.RenderSystem;
44
import com.mojang.blaze3d.vertex.VertexConsumer;
55
import net.irisshaders.batchedentityrendering.impl.FullyBufferedMultiBufferSource;
6-
import net.irisshaders.batchedentityrendering.impl.OldFullyBufferedMultiBufferSource;
76
import net.minecraft.client.renderer.RenderType;
87
import org.spongepowered.asm.mixin.Mixin;
98
import org.spongepowered.asm.mixin.injection.At;
109
import org.spongepowered.asm.mixin.injection.Inject;
1110
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
1211
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
1312

14-
@Mixin(value = FullyBufferedMultiBufferSource.class,remap = false)
13+
@Mixin(value = FullyBufferedMultiBufferSource.class, remap = false)
1514
public class MixinFullyBufferedMultiBufferSource {
1615
@Inject(method = "getBuffer", at = @At("HEAD"))
1716
private void getBuffer(RenderType renderType, CallbackInfoReturnable<VertexConsumer> cir) {

src/main/java/fun/qu_an/minecraft/asyncparticles/client/util/FakeBeginBufferBuilder.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
import com.mojang.blaze3d.vertex.BufferBuilder;
44
import com.mojang.blaze3d.vertex.VertexFormat;
55
import org.jetbrains.annotations.NotNull;
6+
import org.lwjgl.system.MemoryUtil;
67

78
public class FakeBeginBufferBuilder extends BufferBuilder {
8-
public static final FakeBeginBufferBuilder INSTANCE = new FakeBeginBufferBuilder(0);
9+
public static final FakeBeginBufferBuilder INSTANCE = new FakeBeginBufferBuilder();
910

10-
private FakeBeginBufferBuilder(int capacity) {
11+
private FakeBeginBufferBuilder() {
1112
super(0);
13+
MemoryUtil.memFree(buffer);
14+
buffer = null;
1215
}
1316

1417
@Override
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
package fun.qu_an.minecraft.asyncparticles.client.util;
22

33
import com.mojang.blaze3d.vertex.Tesselator;
4+
import org.lwjgl.system.MemoryUtil;
45

56
public class FakeEndTesselator extends Tesselator {
67
public static final FakeEndTesselator INSTANCE = new FakeEndTesselator();
8+
private Runnable endRunnable;
9+
710
private FakeEndTesselator() {
811
super(0);
12+
MemoryUtil.memFree(builder.buffer);
13+
builder.buffer = null;
914
}
1015

1116
@Override
1217
public void end() {
18+
endRunnable.run();
19+
endRunnable = null;
1320
// do nothing
1421
}
22+
23+
public Tesselator onEnd(Runnable runnable) {
24+
this.endRunnable = runnable;
25+
return this;
26+
}
1527
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package fun.qu_an.minecraft.asyncparticles.client.util;
2+
3+
public class Test {
4+
public static void test() {
5+
}
6+
}

src/main/resources/asyncparticles.accesswidener

+1
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ accessible field net/minecraft/client/renderer/culling/Frustum camZ D
3737
accessible method net/minecraft/client/particle/ParticleEngine clearParticles ()V
3838
accessible method net/minecraft/client/particle/ParticleEngine updateCount (Lnet/minecraft/core/particles/ParticleGroup;I)V
3939
accessible field com/mojang/blaze3d/vertex/BufferBuilder buffer Ljava/nio/ByteBuffer;
40+
accessible field com/mojang/blaze3d/vertex/Tesselator builder Lcom/mojang/blaze3d/vertex/BufferBuilder;

src/main/resources/asyncparticles.mixins.json

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"MixinMultiBufferSource$BufferSource",
1717
"MixinParticle",
1818
"MixinParticleEngine",
19+
"MixinParticleEngine_Late",
1920
"MixinSoundEngine",
2021
"MixinTesselator",
2122
"MixinTextureManager",
@@ -47,6 +48,7 @@
4748
"forge.particlerain_vs.MixinWeatherParticles",
4849
"forge.particlerain_vs.MixinWeatherParticleSpawner",
4950
"forge.particlerain_vs.MixinWeatherPatricle",
51+
"hexcasting.MixinConjureParticle",
5052
"lodestone.MixinLodestoneWorldParticle",
5153
"sodium.MixinThreadLocalBufferBuilder",
5254
"vs2.InvokerEntityShipCollisionUtils",

0 commit comments

Comments
 (0)