mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 22:26:24 -04:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0484c31ff | ||
|
|
658564f8c1 | ||
|
|
c95a44039e | ||
|
|
b0f0c20404 |
@@ -75,4 +75,4 @@ object ParticleMaterials {
|
||||
|
||||
override fun toString() = "OPAQUE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.cobblemon.mod.common.client.gui.tmmachine.TMMachineScreen
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
|
||||
import com.cobblemon.mod.common.client.render.DeferredRenderer
|
||||
import com.cobblemon.mod.common.client.render.SnowstormShaderBypassRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.*
|
||||
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
||||
import com.cobblemon.mod.common.client.render.color.AprijuiceItemColorProvider
|
||||
@@ -140,6 +141,9 @@ object CobblemonClient {
|
||||
PlatformEvents.CLIENT_PLAYER_LOGIN.subscribe { onLogin() }
|
||||
PlatformEvents.CLIENT_PLAYER_LOGOUT.subscribe { onLogout() }
|
||||
|
||||
// Renders snowstorm particles with a vanilla-identical look when a shaderpack is active.
|
||||
SnowstormShaderBypassRenderer.register()
|
||||
|
||||
this.registerBlockEntityRenderers()
|
||||
registerBlockRenderTypes()
|
||||
registerColors()
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render
|
||||
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* Detects whether a shaderpack is currently active, via Iris (Fabric/NeoForge) or OptiFine.
|
||||
*
|
||||
* Every reference here is reflective and fully guarded: Iris/OptiFine are optional and may be
|
||||
* absent at runtime, so we never hard-reference their classes. If neither is present (or their
|
||||
* APIs ever change shape) the lookups fail silently during class init and [shadersActive] simply
|
||||
* returns `false`. This is the loader-safe contract the rest of the particle code relies on — it
|
||||
* must work identically on Fabric and NeoForge and when no shader mod is installed at all.
|
||||
*
|
||||
* The reflective handles are resolved once; only the cheap boolean accessor is invoked per call.
|
||||
* Particle render types call this at most a handful of times per frame (once per [begin]), so the
|
||||
* cost is negligible.
|
||||
*/
|
||||
object ShaderCompat {
|
||||
|
||||
// Iris: net.irisshaders.iris.api.v0.IrisApi.getInstance().isShaderPackInUse()
|
||||
// getInstance() returns a stable singleton, so it is safe to cache.
|
||||
private val irisInstance: Any?
|
||||
private val irisIsShaderPackInUse: Method?
|
||||
|
||||
// OptiFine: net.optifine.Config.isShaders() (static)
|
||||
private val optifineIsShaders: Method?
|
||||
|
||||
init {
|
||||
var irisInst: Any? = null
|
||||
var irisMethod: Method? = null
|
||||
try {
|
||||
val irisApi = Class.forName("net.irisshaders.iris.api.v0.IrisApi")
|
||||
irisInst = irisApi.getMethod("getInstance").invoke(null)
|
||||
irisMethod = irisApi.getMethod("isShaderPackInUse")
|
||||
} catch (ignored: Throwable) {
|
||||
irisInst = null
|
||||
irisMethod = null
|
||||
}
|
||||
irisInstance = irisInst
|
||||
irisIsShaderPackInUse = irisMethod
|
||||
|
||||
var optifineMethod: Method? = null
|
||||
try {
|
||||
optifineMethod = Class.forName("net.optifine.Config").getMethod("isShaders")
|
||||
} catch (ignored: Throwable) {
|
||||
optifineMethod = null
|
||||
}
|
||||
optifineIsShaders = optifineMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* `true` when Iris or OptiFine reports an active (compiled and enabled) shaderpack. Never throws;
|
||||
* any reflective failure is treated as "no shaders".
|
||||
*/
|
||||
fun shadersActive(): Boolean {
|
||||
val instance = irisInstance
|
||||
val irisMethod = irisIsShaderPackInUse
|
||||
if (instance != null && irisMethod != null) {
|
||||
try {
|
||||
if (irisMethod.invoke(instance) == true) return true
|
||||
} catch (ignored: Throwable) {}
|
||||
}
|
||||
|
||||
val optifineMethod = optifineIsShaders
|
||||
if (optifineMethod != null) {
|
||||
try {
|
||||
if (optifineMethod.invoke(null) == true) return true
|
||||
} catch (ignored: Throwable) {}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,15 @@ class SnowstormParticle(
|
||||
) : Particle(world, x, y, z) {
|
||||
companion object {
|
||||
const val MAXIMUM_DISTANCE_CHANGE_PER_TICK_FOR_FRICTION = 0.005
|
||||
|
||||
/**
|
||||
* Every live (non-removed) snowstorm particle, in spawn order. When a shaderpack is active we
|
||||
* pull these out of the vanilla [net.minecraft.client.particle.ParticleEngine] (see
|
||||
* [getRenderType] returning [NO_RENDER]) and redraw them post-composite via
|
||||
* [SnowstormShaderBypassRenderer], so the pack's particle program can't alter their look.
|
||||
* Insertion-ordered; particles use identity equality so a LinkedHashSet is safe.
|
||||
*/
|
||||
val activeParticles: MutableSet<SnowstormParticle> = LinkedHashSet()
|
||||
}
|
||||
|
||||
val sprite = getSpriteFromAtlas()
|
||||
@@ -127,6 +136,7 @@ class SnowstormParticle(
|
||||
}
|
||||
}
|
||||
storm.effect.particle.creationEvents.forEach { it.trigger(storm, this) }
|
||||
activeParticles.add(this)
|
||||
}
|
||||
|
||||
override fun render(vertexConsumer: VertexConsumer, camera: Camera, tickDelta: Float) {
|
||||
@@ -496,10 +506,15 @@ class SnowstormParticle(
|
||||
runtime.environment.variable.setDirectly("particle_lifetime", DoubleValue(lifetime / 20.0))
|
||||
}
|
||||
|
||||
override fun getRenderType() = particleTextureSheet
|
||||
// Under an active shaderpack we suppress the vanilla ParticleEngine draw (it would be routed
|
||||
// through the pack's translucent particle program and mangled differently per pack) and instead
|
||||
// redraw post-composite in SnowstormShaderBypassRenderer for a vanilla-identical, pack-agnostic
|
||||
// look. With no shaders this is the normal material sheet, so the majority path is unchanged.
|
||||
override fun getRenderType() = if (Cobblemon.config.shaderParticleBypass && ShaderCompat.shadersActive()) NO_RENDER else particleTextureSheet
|
||||
|
||||
override fun remove() {
|
||||
super.remove()
|
||||
storm.particles.remove(this)
|
||||
activeParticles.remove(this)
|
||||
}
|
||||
}
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.platform.events.RenderEvent
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.BufferUploader
|
||||
import com.mojang.blaze3d.vertex.Tesselator
|
||||
import net.minecraft.client.Minecraft
|
||||
import org.joml.Matrix4f
|
||||
|
||||
/**
|
||||
* Renders Cobblemon's snowstorm particles with a vanilla-identical, pack-agnostic look while a
|
||||
* shaderpack (Iris/OptiFine) is active.
|
||||
*
|
||||
* ## Why this exists
|
||||
* Iris/OptiFine replace the vanilla particle shader with the shaderpack's translucent-particle
|
||||
* program for the duration of the world pass, and every pack composites that program differently —
|
||||
* which made our particles render too solid (Complementary), invisible (Photon), or still-darkening
|
||||
* (Bliss) no matter how we tuned blend/alpha inside the vanilla [net.minecraft.client.particle.ParticleEngine].
|
||||
* The pack has final authority there; we cannot win.
|
||||
*
|
||||
* The one place a shaderpack does NOT intercept a draw is **after** `LevelRenderer.renderLevel`
|
||||
* returns: Iris only overrides shaders while `isRenderingWorld` is true, and it flips that off during
|
||||
* its final composite (injected at the world-render RETURN). So we:
|
||||
* 1. suppress the vanilla draw of these particles while shaders are active
|
||||
* ([SnowstormParticle.getRenderType] returns NO_RENDER), and
|
||||
* 2. redraw them here at [RenderEvent.Stage.POST_LEVEL] (post-composite) with the exact vanilla GL
|
||||
* state from [com.cobblemon.mod.common.api.snowstorm.ParticleMaterials] and the unchanged
|
||||
* [SnowstormParticle.render] quad math.
|
||||
*
|
||||
* The main framebuffer's depth attachment still holds the full (opaque + translucent) world depth at
|
||||
* this point — Iris reuses Minecraft's main depth texture and the composite only copies colour — so
|
||||
* particles still occlude correctly behind terrain AND water/glass. They simply don't receive the
|
||||
* pack's lighting/fog/bloom, which is exactly the intended "looks like vanilla" result.
|
||||
*
|
||||
* When no shaderpack is active this renderer does nothing and particles draw normally through the
|
||||
* ParticleEngine, so the majority (no-shader) path is completely unchanged.
|
||||
*
|
||||
* @author Cobblemon
|
||||
*/
|
||||
object SnowstormShaderBypassRenderer {
|
||||
|
||||
// The world's camera view matrix for the current frame, captured at the late in-level stage
|
||||
// where Fabric/NeoForge still have the camera transform applied. POST_LEVEL fires after that
|
||||
// state is unwound, but the bypass draw still needs it because SnowstormParticle.render emits
|
||||
// camera-relative vertices just like vanilla particles do.
|
||||
private val modelViewMatrix = Matrix4f()
|
||||
private var captured = false
|
||||
|
||||
fun register() {
|
||||
PlatformEvents.RENDER.subscribe { event ->
|
||||
when (event.stage) {
|
||||
RenderEvent.Stage.LAST -> {
|
||||
modelViewMatrix.set(RenderSystem.getModelViewMatrix())
|
||||
captured = true
|
||||
}
|
||||
RenderEvent.Stage.POST_LEVEL -> render(event)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun render(event: RenderEvent) {
|
||||
if (!Cobblemon.config.shaderParticleBypass || !ShaderCompat.shadersActive() || !captured) {
|
||||
captured = false
|
||||
return
|
||||
}
|
||||
|
||||
val visible = SnowstormParticle.activeParticles.filter { !it.invisible }
|
||||
if (visible.isEmpty()) {
|
||||
captured = false
|
||||
return
|
||||
}
|
||||
|
||||
val minecraft = Minecraft.getInstance()
|
||||
val camera = event.camera
|
||||
val partialTicks = event.tickCounter.getGameTimeDeltaPartialTick(false)
|
||||
val lightTexture = minecraft.gameRenderer.lightTexture()
|
||||
val tesselator = Tesselator.getInstance()
|
||||
|
||||
// Re-establish the world's camera view so the camera-relative quads built by render() land
|
||||
// in the right place; projection is still the world's 3D projection at this point in the frame.
|
||||
val modelViewStack = RenderSystem.getModelViewStack()
|
||||
modelViewStack.pushMatrix()
|
||||
modelViewStack.set(modelViewMatrix)
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
|
||||
try {
|
||||
lightTexture.turnOnLightLayer()
|
||||
|
||||
// Group by the particle's own render type (ParticleMaterials.ALPHA/ADD/BLEND/OPAQUE). Calling
|
||||
// its begin() sets the IDENTICAL GL state vanilla would use, so the look matches no-shaders.
|
||||
for ((renderType, particles) in visible.groupBy { it.particleTextureSheet }) {
|
||||
val buffer = renderType.begin(tesselator, minecraft.textureManager) ?: continue
|
||||
for (particle in particles) {
|
||||
particle.render(buffer, camera, partialTicks)
|
||||
}
|
||||
val mesh = buffer.build() ?: continue
|
||||
BufferUploader.drawWithShader(mesh)
|
||||
}
|
||||
} finally {
|
||||
lightTexture.turnOffLightLayer()
|
||||
modelViewStack.popMatrix()
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
captured = false
|
||||
}
|
||||
|
||||
// Restore neutral GL state so nothing downstream (hand already drawn, GUI next) is affected.
|
||||
RenderSystem.depthMask(true)
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.enableCull()
|
||||
}
|
||||
}
|
||||
@@ -331,6 +331,9 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Interface, lang = "animate_battle_tiles", CLIENT)
|
||||
var animateBattleTiles = false
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "shader_particle_bypass", CLIENT)
|
||||
var shaderParticleBypass = true
|
||||
|
||||
// Disabled as non-tenable for 1.7 until all the posers catch up with this property.
|
||||
// @CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing", CLIENT)
|
||||
var thirdPersonViewBobbing = true
|
||||
|
||||
@@ -32,6 +32,22 @@ data class RenderEvent(
|
||||
|
||||
/** Represents when a layer is rendered by [LevelRenderer.renderLevel]. Ordinal corresponds with its render order. */
|
||||
enum class Stage {
|
||||
TRANSLUCENT
|
||||
TRANSLUCENT,
|
||||
|
||||
/**
|
||||
* Fired after the world framebuffer writes are complete but before the level renderer tears
|
||||
* down its camera view transform. Direct draws at [POST_LEVEL] can reuse the matrix captured
|
||||
* here when they need to render after shaderpack composition.
|
||||
*/
|
||||
LAST,
|
||||
|
||||
/**
|
||||
* Fired after [LevelRenderer.renderLevel] has fully finished — on a shaderpack, this is after
|
||||
* Iris/OptiFine has composited the world to the main framebuffer and restored vanilla shaders.
|
||||
* Draws here are NOT intercepted by the shaderpack, so they render with vanilla shaders while
|
||||
* still depth-testing against the full (opaque + translucent) world depth. Used to render
|
||||
* Cobblemon's snowstorm particles with a vanilla-identical look under shaders.
|
||||
*/
|
||||
POST_LEVEL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2539,6 +2539,8 @@
|
||||
"cobblemon.config.ui.summary_pokemon_follow_cursor.tooltip": "Whether or not Pokémon should follow the mouse cursor with their heads in the Summary screen.",
|
||||
"cobblemon.config.ui.animate_battle_tiles": "Animate Battle Tiles",
|
||||
"cobblemon.config.ui.animate_battle_tiles.tooltip": "Whether or not the battle portraits of Pokemon should be animated.",
|
||||
"cobblemon.config.ui.shader_particle_bypass": "Shader Particle Bypass",
|
||||
"cobblemon.config.ui.shader_particle_bypass.tooltip": "When enabled, Cobblemon particles are redrawn after shaderpack composition so Iris and OptiFine shaderpacks do not alter their appearance.",
|
||||
"cobblemon.config.ui.party_portrait_animations": "Party Portrait Animations",
|
||||
"cobblemon.config.ui.party_portrait_animations.never_animate": "Never Animate",
|
||||
"cobblemon.config.ui.party_portrait_animations.never_animate.tooltip": "No portraits animate",
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import java.net.URI
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
force(libs.fabric.loader)
|
||||
@@ -48,6 +50,23 @@ dependencies {
|
||||
isTransitive = false
|
||||
}
|
||||
modLocalRuntime(libs.fabric.debugutils)
|
||||
|
||||
// Shader-compat testing (DEV RUNTIME ONLY — never shipped, never a real dependency).
|
||||
// Lets `runClient` load Iris + Sodium so shaderpacks actually run, which is required to
|
||||
// exercise ParticleMaterials' depthMask branch (see ShaderCompat). isTransitive = false so
|
||||
// these don't drag in a second copy of Fabric API / FLK (already provided above). If you bump
|
||||
// these, keep the Iris<->Sodium pairing valid (Iris 1.8.x needs Sodium 0.6.x for MC 1.21.1).
|
||||
modLocalRuntime("maven.modrinth:iris:1.8.8+1.21.1-fabric") { isTransitive = false }
|
||||
modLocalRuntime("maven.modrinth:sodium:mc1.21.1-0.6.13-fabric") { isTransitive = false }
|
||||
// Iris bundles these as jar-in-jar in production, but loom doesn't add a mod's nested *libraries*
|
||||
// to the dev classpath, so the dev client crashes with NoClassDefFoundError (e.g. org.anarres.cpp
|
||||
// / glsl-transformer) when Iris loads a shaderpack. Supply them as plain dev-runtime libs.
|
||||
// Versions are taken verbatim from iris-1.8.8's META-INF/jars — keep them in lockstep if Iris is
|
||||
// bumped. localRuntime = dev runtime only, not remapped, not exported to the published jar.
|
||||
localRuntime("org.anarres:jcpp:1.4.14")
|
||||
localRuntime("io.github.douira:glsl-transformer:2.0.1")
|
||||
localRuntime("org.antlr:antlr4-runtime:4.13.1")
|
||||
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.fabric.api)
|
||||
modApi(libs.bundles.fabric)
|
||||
@@ -110,6 +129,57 @@ publishing {
|
||||
}
|
||||
|
||||
tasks {
|
||||
// Downloads the Complementary Unbound shaderpack into the dev client's shaderpacks/ folder and
|
||||
// enables Iris by default, so `runClient` comes up shader-ready with zero manual setup. Both
|
||||
// writes are idempotent: existing files are left untouched, so your in-game shader choice and
|
||||
// any pack you swap in are preserved across runs. Run dir is "runClient" (see platform-conventions).
|
||||
val setupShaderTesting by registering {
|
||||
group = "cobblemon"
|
||||
description = "Provisions the test shaderpacks + enables Iris for the dev runClient."
|
||||
// The four Iris packs we want particles to look correct under. Swap between them in-game
|
||||
// (Video Settings -> Shader Packs) to A/B the premultiplied-alpha fix in ParticleMaterials.
|
||||
// <filename> to <direct Modrinth CDN url>.
|
||||
//
|
||||
// VERSIONS ARE PINNED FOR MC 1.21.1. The newest releases of these packs reference the
|
||||
// BIOME_PALE_GARDEN uniform (Pale Garden is a 1.21.4 biome), which Iris cannot resolve on
|
||||
// 1.21.1 -> hard crash building the render pipeline ("Unknown variable: BIOME_PALE_GARDEN").
|
||||
// Each pin below was confirmed Pale-Garden-free by grepping the archive. If this project ever
|
||||
// targets >= 1.21.4, bump these to the latest versions.
|
||||
val packs = mapOf(
|
||||
"ComplementaryUnbound_r5.3.zip" to "https://cdn.modrinth.com/data/R6NEzAwj/versions/CVu3AGAd/ComplementaryUnbound_r5.3.zip",
|
||||
"ComplementaryReimagined_r5.3.zip" to "https://cdn.modrinth.com/data/HVnmMxH1/versions/71Hn3myZ/ComplementaryReimagined_r5.3.zip",
|
||||
"Bliss_v2.1.2_(Chocapic13_Shaders_edit).zip" to "https://cdn.modrinth.com/data/ZvMtQlho/versions/kC2Y8q1P/Bliss_v2.1.2_%28Chocapic13_Shaders_edit%29.zip",
|
||||
"photon_v1.1.zip" to "https://cdn.modrinth.com/data/lLqFfGNs/versions/6FdrBtKp/photon_v1.1.zip"
|
||||
)
|
||||
val shaderpacksDir = layout.projectDirectory.dir("runClient/shaderpacks")
|
||||
val irisProps = layout.projectDirectory.file("runClient/config/iris.properties")
|
||||
// Default the in-game selection to Complementary Unbound (the originally-reported pack); idempotent.
|
||||
val defaultPack = "ComplementaryUnbound_r5.3.zip"
|
||||
outputs.dir(shaderpacksDir)
|
||||
doLast {
|
||||
packs.forEach { (filename, url) ->
|
||||
val zip = shaderpacksDir.file(filename).asFile
|
||||
if (!zip.exists()) {
|
||||
zip.parentFile.mkdirs()
|
||||
logger.lifecycle("Downloading shaderpack -> ${zip.relativeTo(rootProject.projectDir)}")
|
||||
URI(url).toURL().openStream().use { input ->
|
||||
zip.outputStream().use { output -> input.copyTo(output) }
|
||||
}
|
||||
}
|
||||
}
|
||||
val props = irisProps.asFile
|
||||
if (!props.exists()) {
|
||||
props.parentFile.mkdirs()
|
||||
props.writeText("enableShaders=true\nshaderPack=$defaultPack\n")
|
||||
logger.lifecycle("Wrote ${props.relativeTo(rootProject.projectDir)} (Iris auto-enabled with $defaultPack).")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
named("runClient") {
|
||||
dependsOn(setupShaderTesting)
|
||||
}
|
||||
|
||||
// The AW file is needed in :fabric project resources when the game is run.
|
||||
val copyAccessWidener by registering(Copy::class) {
|
||||
from(loom.accessWidenerPath)
|
||||
|
||||
@@ -171,6 +171,35 @@ class CobblemonFabricClient: ClientModInitializer, CobblemonClientImplementation
|
||||
)
|
||||
}
|
||||
|
||||
// Capture the final in-level camera transform before Fabric unwinds render state.
|
||||
WorldRenderEvents.LAST.register { context -> PlatformEvents.RENDER.post(
|
||||
RenderEvent(
|
||||
stage = RenderEvent.Stage.LAST,
|
||||
levelRenderer = context.worldRenderer(),
|
||||
poseStack = context.matrixStack() ?: PoseStack(),
|
||||
modelViewMatrix = context.positionMatrix(),
|
||||
projectionMatrix = context.projectionMatrix(),
|
||||
tickCounter = context.tickCounter(),
|
||||
camera = context.camera()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Fires after the level (and any shaderpack composite) has finished — the only point where a
|
||||
// draw is NOT intercepted by Iris/OptiFine. Used by SnowstormShaderBypassRenderer.
|
||||
WorldRenderEvents.END.register { context -> PlatformEvents.RENDER.post(
|
||||
RenderEvent(
|
||||
stage = RenderEvent.Stage.POST_LEVEL,
|
||||
levelRenderer = context.worldRenderer(),
|
||||
poseStack = context.matrixStack() ?: PoseStack(),
|
||||
modelViewMatrix = context.positionMatrix(),
|
||||
projectionMatrix = context.projectionMatrix(),
|
||||
tickCounter = context.tickCounter(),
|
||||
camera = context.camera()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
CobblemonModelPredicateRegistry.registerPredicates()
|
||||
}
|
||||
|
||||
@@ -201,4 +230,4 @@ class CobblemonFabricClient: ClientModInitializer, CobblemonClientImplementation
|
||||
override fun <T : Entity> registerEntityRenderer(type: EntityType<out T>, factory: EntityRendererProvider<T>) {
|
||||
EntityRendererRegistry.register(type, factory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -74,6 +74,8 @@ object NeoForgeClientPlatformEventHandler {
|
||||
fun onRenderLevelStageEvent(event: RenderLevelStageEvent) {
|
||||
val stage = when (event.stage) {
|
||||
RenderLevelStageEvent.Stage.AFTER_PARTICLES -> RenderEvent.Stage.TRANSLUCENT
|
||||
RenderLevelStageEvent.Stage.AFTER_WEATHER -> RenderEvent.Stage.LAST
|
||||
RenderLevelStageEvent.Stage.AFTER_LEVEL -> RenderEvent.Stage.POST_LEVEL
|
||||
else -> return
|
||||
}
|
||||
|
||||
@@ -89,4 +91,4 @@ object NeoForgeClientPlatformEventHandler {
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user