Merge pull request #240 from IThundxr/feat/multi-loader-1.21

Port to 1.21.1
This commit is contained in:
Jozufozu 2025-01-21 14:55:23 -08:00 committed by GitHub
commit 1a89f36130
Failed to generate hash of commit
128 changed files with 1434 additions and 1747 deletions

View file

@ -3,7 +3,7 @@ name: Build
on: [ workflow_dispatch, pull_request, push ]
env:
JAVA_VERSION: 17
JAVA_VERSION: 21
jobs:
build:
@ -43,13 +43,15 @@ jobs:
path: |
common/build/libs/
fabric/build/libs/
forge/build/libs/
neoforge/build/libs/
vanillinFabric/build/libs/
vanillinNeoForge/build/libs/
test:
strategy:
fail-fast: false
matrix:
loader: [ forge, fabric ]
loader: [ neoforge, fabric ]
needs: build
runs-on: ubuntu-latest
steps:
@ -63,15 +65,15 @@ jobs:
- name: Setup Environment Variables
run: |
echo "MOD_VERSION=$(grep '^mod_version =' gradle.properties | cut -d'=' -f2 | tr -d ' ')" >> "$GITHUB_ENV"
echo "MINECRAFT_VERSION=$(grep '^minecraft_version =' gradle.properties | cut -d'=' -f2 | tr -d ' ')" >> "$GITHUB_ENV"
echo "FABRIC_API_VERSION=$(grep '^fabric_api_version =' gradle.properties | cut -d'=' -f2 | tr -d ' ' | sed 's/+.*//')" >> "$GITHUB_ENV"
- name: Move Test Mod and Flywheel into run/mods
# We don't want to recreate the jar name formatting so glob everything over then remove the sources and javadoc jars
run: |
mkdir -p run/mods
cp ${{ matrix.loader }}/build/libs/flywheel-${{ matrix.loader }}-${{ env.MINECRAFT_VERSION }}-${{ env.MOD_VERSION }}.jar run/mods
cp ${{ matrix.loader }}/build/libs/flywheel-${{ matrix.loader }}-${{ env.MINECRAFT_VERSION }}-${{ env.MOD_VERSION }}-testmod.jar run/mods
cp ${{ matrix.loader }}/build/libs/*.jar run/mods
rm -f run/mods/*-sources.jar run/mods/*-javadoc.jar
# Lock to a specific commit, it would be bad if the tag is re-pushed with unwanted changes
- name: Run the MC client

View file

@ -39,8 +39,8 @@ repositories {
}
dependencies {
compileOnly fg.deobf("dev.engine_room.flywheel:flywheel-forge-api-${minecraft_version}:${flywheel_version}")
runtimeOnly fg.deobf("dev.engine_room.flywheel:flywheel-forge-${minecraft_version}:${flywheel_version}")
compileOnly fg.deobf("dev.engine_room.flywheel:flywheel-neoforge-api-${minecraft_version}:${flywheel_version}")
runtimeOnly fg.deobf("dev.engine_room.flywheel:flywheel-neoforge-${minecraft_version}:${flywheel_version}")
}
```
`${flywheel_version}` gets replaced by the version of Flywheel you want to use, eg. `1.0.0-beta`

View file

@ -8,8 +8,8 @@ plugins {
repositories {
gradlePluginPortal()
mavenCentral()
maven("https://maven.minecraftforge.net/") {
name = "MinecraftForge"
maven("https://maven.neoforged.net/releases/") {
name = "NeoForged"
}
maven("https://maven.architectury.dev/") {
name = "Architectury"

View file

@ -13,10 +13,6 @@ open class JarSetExtension(private val project: Project) {
return JarTaskSet.create(project, name, *sourceSetSet)
}
fun outgoing(name: String, vararg sourceSetSet: SourceSet): JarTaskSet {
return JarTaskSet.create(project, name, *sourceSetSet).also { it.createOutgoingConfiguration() }
}
val mainSet: JarTaskSet by lazy {
val jarTask = project.tasks.named<Jar>("jar")
val remapJarTask = project.tasks.named<RemapJarTask>("remapJar")

View file

@ -23,11 +23,11 @@ import org.gradle.language.jvm.tasks.ProcessResources
class JarTaskSet(
private val project: Project,
private val name: String,
private val jar: TaskProvider<Jar>,
private val sources: TaskProvider<Jar>,
private val javadocJar: TaskProvider<Jar>,
private val remapJar: TaskProvider<RemapJarTask>,
private val remapSources: TaskProvider<RemapSourcesJarTask>
val jar: TaskProvider<Jar>,
val sources: TaskProvider<Jar>,
val javadocJar: TaskProvider<Jar>,
val remapJar: TaskProvider<RemapJarTask>,
val remapSources: TaskProvider<RemapSourcesJarTask>
) {
fun publish(artifactId: String) {
@ -41,10 +41,21 @@ class JarTaskSet(
}
}
/**
* Create a new configuration that can be consumed by other projects, and export the base jar.
*/
fun createOutgoingConfiguration() {
fun outgoing(name: String) {
outgoingRemapJar("${name}Remap")
outgoingJar("${name}Dev")
}
fun outgoingRemapJar(name: String) {
val config = project.configurations.register(name) {
isCanBeConsumed = true
isCanBeResolved = false
}
project.artifacts.add(config.name, remapJar)
}
fun outgoingJar(name: String) {
val config = project.configurations.register(name) {
isCanBeConsumed = true
isCanBeResolved = false

View file

@ -1,30 +1,18 @@
package dev.engine_room.gradle.platform
import dev.engine_room.gradle.jarset.JarTaskSet
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import net.fabricmc.loom.task.RemapJarTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the
import java.io.File
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
open class PlatformExtension(val project: Project) {
var commonProject: Project by DependentProject(this.project)
var modArtifactId: String = "flywheel-${project.name}-${project.property("artifact_minecraft_version")}"
var apiArtifactId: String = "flywheel-${project.name}-api-${project.property("artifact_minecraft_version")}"
private val commonSourceSets: SourceSetContainer by lazy { commonProject.the<SourceSetContainer>() }
fun setupLoomMod(vararg sourceSets: SourceSet) {
project.the<LoomGradleExtensionAPI>().mods.maybeCreate("main").apply {
sourceSets.forEach(::sourceSet)
@ -56,52 +44,6 @@ open class PlatformExtension(val project: Project) {
}
}
fun compileWithCommonSourceSets(vararg sourceSets: SourceSet) {
project.tasks.apply {
withType<JavaCompile>().configureEach {
JarTaskSet.excludeDuplicatePackageInfos(this)
}
sourceSets.forEach {
val commonSourceSet = commonSourceSets.named(it.name).get()
named<JavaCompile>(it.compileJavaTaskName).configure {
source(commonSourceSet.allJava)
}
named<ProcessResources>(it.processResourcesTaskName).configure {
from(commonSourceSet.resources)
}
}
}
}
fun setupFatJar(vararg sourceSets: SourceSet) {
project.tasks.apply {
val extraSourceSets = sourceSets.filter { it.name != "main" }.toList()
val commonSources = sourceSets.map { commonSourceSets.named(it.name).get() }
named<Jar>("jar").configure {
extraSourceSets.forEach { from(it.output) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
named<Javadoc>("javadoc").configure {
commonSources.forEach { source(it.allJava) }
extraSourceSets.forEach { source(it.allJava) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
named<Jar>("sourcesJar").configure {
commonSources.forEach { from(it.allJava) }
extraSourceSets.forEach { from(it.allJava) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
}
}
fun setupTestMod(sourceSet: SourceSet) {
project.tasks.apply {
val testModJar = register<Jar>("testModJar") {
@ -124,20 +66,4 @@ open class PlatformExtension(val project: Project) {
}
}
}
private class DependentProject(private val thisProject: Project) : ReadWriteProperty<Any?, Project> {
private var value: Project? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): Project {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Project) {
this.value = value
thisProject.evaluationDependsOn(value.path)
}
override fun toString(): String =
"NotNullProperty(${if (value != null) "value=$value" else "value not initialized yet"})"
}
}

View file

@ -0,0 +1,182 @@
package dev.engine_room.gradle.subproject
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.BasePluginExtension
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.tasks.GenerateModuleMetadata
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.jvm.tasks.Jar
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
open class SubprojectExtension(val project: Project) {
fun init(archiveBase: String, group: String, version: String) {
setBaseProperties(archiveBase, group, version)
setupJava()
addRepositories()
setupLoom()
setupDependencies()
configureTasks()
setupPublishing()
}
private fun setBaseProperties(archiveBase: String, group: String, version: String) {
val dev = System.getenv("RELEASE")?.contentEquals("false", true) ?: true
val buildNumber = System.getenv("BUILD_NUMBER")
val versionSuffix = if (dev && buildNumber != null) "-${buildNumber}" else ""
project.group = project.property(group) as String
project.version = "${project.property(version)}${versionSuffix}"
project.the<BasePluginExtension>().apply {
archivesName = "${archiveBase}-${project.property("artifact_minecraft_version")}"
}
}
private fun setupLoom() {
val loom = project.the<LoomGradleExtensionAPI>()
loom.silentMojangMappingsLicense()
}
private fun setupJava() {
val java_version: String by project
project.the<JavaPluginExtension>().apply {
val javaVersion = JavaVersion.toVersion(java_version)
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
toolchain.languageVersion = JavaLanguageVersion.of(java_version)
withSourcesJar()
withJavadocJar()
}
}
private fun addRepositories() {
project.repositories.apply {
mavenCentral()
maven("https://maven.parchmentmc.org") {
name = "ParchmentMC"
}
maven("https://maven.tterrag.com/") {
name = "tterrag maven"
}
maven("https://www.cursemaven.com") {
name = "CurseMaven"
content {
includeGroup("curse.maven")
}
}
maven("https://api.modrinth.com/maven") {
name = "Modrinth"
content {
includeGroup("maven.modrinth")
}
}
}
}
@Suppress("UnstableApiUsage")
private fun setupDependencies() {
project.dependencies.apply {
val minecraft_version: String by project
val parchment_minecraft_version: String by project
val parchment_version: String by project
val loom = project.the<LoomGradleExtensionAPI>()
add("minecraft", "com.mojang:minecraft:${minecraft_version}")
add("mappings", loom.layered {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${parchment_minecraft_version}:${parchment_version}@zip")
})
add("api", "com.google.code.findbugs:jsr305:3.0.2")
}
}
private fun configureTasks() {
val java_version: String by project
project.tasks.apply {
// make builds reproducible
withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
// module metadata is often broken on multi-platform projects
withType<GenerateModuleMetadata>().configureEach {
enabled = false
}
withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.release = Integer.parseInt(java_version)
options.compilerArgs.add("-Xdiags:verbose")
}
withType<Jar>().configureEach {
from("${project.rootDir}/LICENSE.md") {
into("META-INF")
}
}
withType<Javadoc>().configureEach {
options.optionFiles(project.rootProject.file("javadoc-options.txt"))
options.encoding = "UTF-8"
}
val replaceProperties = processResourcesExpandProperties.associateWith { project.property(it) as String }
withType<ProcessResources>().configureEach {
inputs.properties(replaceProperties)
filesMatching(processResourcesExpandFiles) {
expand(replaceProperties)
}
}
}
}
private fun setupPublishing() {
project.the<PublishingExtension>().repositories.apply {
maven("file://${project.rootProject.projectDir}/mcmodsrepo")
if (project.hasProperty("mavendir")) {
maven(project.rootProject.file(project.property("mavendir") as String))
}
}
}
}
val processResourcesExpandFiles = listOf("pack.mcmeta", "fabric.mod.json", "META-INF/neoforge.mods.toml")
val processResourcesExpandProperties = listOf(
"mod_license",
"mod_sources",
"mod_issues",
"mod_homepage",
"flywheel_id",
"flywheel_name",
"flywheel_description",
"flywheel_version",
"vanillin_id",
"vanillin_name",
"vanillin_version",
"vanillin_description",
"flywheel_maven_version_range",
"flywheel_semver_version_range",
"minecraft_semver_version_range",
"minecraft_maven_version_range",
"fabric_api_version_range",
"neoforge_version_range",
)

View file

@ -3,183 +3,14 @@ package dev.engine_room.gradle.subproject
import dev.engine_room.gradle.jarset.JarSetExtension
import dev.engine_room.gradle.nullability.PackageInfosExtension
import dev.engine_room.gradle.transitive.TransitiveSourceSetsExtension
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.BasePluginExtension
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.tasks.GenerateModuleMetadata
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.jvm.tasks.Jar
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
class SubprojectPlugin: Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create("defaultPackageInfos", PackageInfosExtension::class.java, project)
project.extensions.create("transitiveSourceSets", TransitiveSourceSetsExtension::class.java, project)
project.extensions.create("jarSets", JarSetExtension::class.java, project)
setBaseProperties(project)
setupJava(project)
addRepositories(project)
setupLoom(project)
setupDependencies(project)
configureTasks(project)
setupPublishing(project)
}
private fun setBaseProperties(project: Project) {
val dev = System.getenv("RELEASE")?.contentEquals("false", true) ?: true
val buildNumber = System.getenv("BUILD_NUMBER")
val versionSuffix = if (dev && buildNumber != null) "-${buildNumber}" else ""
project.group = project.property("group") as String
project.version = "${project.property("mod_version")}${versionSuffix}"
project.the<BasePluginExtension>().apply {
archivesName = "flywheel-${project.name}-${project.property("artifact_minecraft_version")}"
}
}
private fun setupLoom(project: Project) {
val loom = project.the<LoomGradleExtensionAPI>()
loom.silentMojangMappingsLicense()
}
private fun setupJava(project: Project) {
val java_version: String by project
project.the<JavaPluginExtension>().apply {
val javaVersion = JavaVersion.toVersion(java_version)
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
toolchain.languageVersion = JavaLanguageVersion.of(java_version)
withSourcesJar()
withJavadocJar()
}
}
private fun addRepositories(project: Project) {
project.repositories.apply {
mavenCentral()
maven("https://maven.parchmentmc.org") {
name = "ParchmentMC"
}
maven("https://maven.tterrag.com/") {
name = "tterrag maven"
}
maven("https://www.cursemaven.com") {
name = "CurseMaven"
content {
includeGroup("curse.maven")
}
}
maven("https://api.modrinth.com/maven") {
name = "Modrinth"
content {
includeGroup("maven.modrinth")
}
}
}
}
@Suppress("UnstableApiUsage")
private fun setupDependencies(project: Project) {
project.dependencies.apply {
val minecraft_version: String by project
val parchment_minecraft_version: String by project
val parchment_version: String by project
val loom = project.the<LoomGradleExtensionAPI>()
add("minecraft", "com.mojang:minecraft:${minecraft_version}")
add("mappings", loom.layered {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${parchment_minecraft_version}:${parchment_version}@zip")
})
add("api", "com.google.code.findbugs:jsr305:3.0.2")
}
}
private fun configureTasks(project: Project) {
val java_version: String by project
project.tasks.apply {
// make builds reproducible
withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
// module metadata is often broken on multi-platform projects
withType<GenerateModuleMetadata>().configureEach {
enabled = false
}
withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.release = Integer.parseInt(java_version)
options.compilerArgs.add("-Xdiags:verbose")
}
withType<Jar>().configureEach {
from("${project.rootDir}/LICENSE.md") {
into("META-INF")
}
}
withType<Javadoc>().configureEach {
options.optionFiles(project.rootProject.file("javadoc-options.txt"))
options.encoding = "UTF-8"
}
val replaceProperties = processResourcesExpandProperties.associateWith { project.property(it) as String }
withType<ProcessResources>().configureEach {
inputs.properties(replaceProperties)
filesMatching(processResourcesExpandFiles) {
expand(replaceProperties)
}
}
}
}
private fun setupPublishing(project: Project) {
project.the<PublishingExtension>().repositories.apply {
maven("file://${project.rootProject.projectDir}/mcmodsrepo")
if (project.hasProperty("mavendir")) {
maven(project.rootProject.file(project.property("mavendir") as String))
}
}
project.extensions.create("subproject", SubprojectExtension::class.java, project)
}
}
val processResourcesExpandFiles = listOf("pack.mcmeta", "fabric.mod.json", "META-INF/mods.toml")
val processResourcesExpandProperties = listOf(
"mod_id",
"mod_name",
"mod_description",
"mod_license",
"mod_sources",
"mod_issues",
"mod_homepage",
"mod_version",
"minecraft_semver_version_range",
"minecraft_maven_version_range",
"fabric_api_version_range",
"forge_version_range",
)

View file

@ -1,6 +1,15 @@
package dev.engine_room.gradle.transitive
import dev.engine_room.gradle.jarset.JarTaskSet
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.the
import org.gradle.language.jvm.tasks.ProcessResources
class TransitiveSourceSetConfigurator(private val parent: TransitiveSourceSetsExtension, private val sourceSet: SourceSet) {
internal val compileSourceSets = mutableSetOf<SourceSet>()
@ -19,14 +28,21 @@ class TransitiveSourceSetConfigurator(private val parent: TransitiveSourceSetsEx
rootRuntime()
}
fun compile(vararg sourceSets: SourceSet) {
fun compileClasspath(vararg sourceSets: SourceSet) {
compileSourceSets += sourceSets
for (sourceSet in sourceSets) {
this.sourceSet.compileClasspath += sourceSet.output
}
}
fun runtime(vararg sourceSets: SourceSet) {
fun compileClasspath(project: Project, vararg sourceSets: String) {
val externalSourceSets = project.the<SourceSetContainer>()
for (name in sourceSets) {
this.sourceSet.compileClasspath += externalSourceSets.getByName(name).output
}
}
fun runtimeClasspath(vararg sourceSets: SourceSet) {
runtimeSourceSets += sourceSets
for (sourceSet in sourceSets) {
this.sourceSet.runtimeClasspath += sourceSet.output
@ -34,7 +50,107 @@ class TransitiveSourceSetConfigurator(private val parent: TransitiveSourceSetsEx
}
fun implementation(vararg sourceSets: SourceSet) {
compile(*sourceSets)
runtime(*sourceSets)
compileClasspath(*sourceSets)
runtimeClasspath(*sourceSets)
}
fun from(otherProject: Project) {
from(otherProject, sourceSet.name)
}
fun from(otherProject: Project, vararg names: String) {
val otherSourceSets = otherProject.the<SourceSetContainer>()
from(*names.map { otherSourceSets.getByName(it) }.toTypedArray())
}
fun from(vararg sourceSets: SourceSet) {
parent.project.tasks.apply {
named<JavaCompile>(sourceSet.compileJavaTaskName).configure {
sourceSets.forEach { source(it.allJava) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
named<ProcessResources>(sourceSet.processResourcesTaskName).configure {
sourceSets.forEach { from(it.resources) }
}
}
}
fun bundleFrom(otherProject: Project) {
bundleFrom(otherProject, sourceSet.name)
}
fun bundleFrom(otherProject: Project, vararg names: String) {
val otherSourceSets = otherProject.the<SourceSetContainer>()
bundleFrom(*names.map { otherSourceSets.getByName(it) }.toTypedArray())
}
fun bundleFrom(vararg sourceSets: SourceSet) {
from(*sourceSets)
// The external sourceSets will be included in the jar by default since we bring it into the java compile task,
// however we need to make sure that the javadoc and sources jars also include the external sourceSets
bundleJavadocAndSources(*sourceSets)
}
fun bundleOutput(vararg sourceSets: SourceSet) {
bundleJavadocAndSources(*sourceSets)
parent.project.tasks.apply {
named<Jar>(sourceSet.jarTaskName).configure {
sourceSets.forEach { from(it.output) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
}
}
private fun bundleJavadocAndSources(vararg sourceSets: SourceSet) {
parent.project.tasks.apply {
named<Javadoc>(sourceSet.javadocTaskName).configure {
sourceSets.forEach { source(it.allJava) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
named<Jar>(sourceSet.sourcesJarTaskName).configure {
sourceSets.forEach { from(it.allJava) }
JarTaskSet.excludeDuplicatePackageInfos(this)
}
}
}
fun outgoing() {
outgoingClasses()
outgoingResources()
}
fun outgoingResources() {
val project = parent.project
val exportResources = project.configurations.register("${sourceSet.name}Resources") {
isCanBeResolved = false
isCanBeConsumed = true
}
val processResources = project.tasks.named<ProcessResources>(sourceSet.processResourcesTaskName).get()
project.artifacts.add(exportResources.name, processResources.destinationDir) {
builtBy(processResources)
}
}
fun outgoingClasses() {
val project = parent.project
val exportClasses = project.configurations.register("${sourceSet.name}Classes") {
isCanBeResolved = false
isCanBeConsumed = true
}
val compileTask = project.tasks.named<JavaCompile>(sourceSet.compileJavaTaskName).get()
project.artifacts.add(exportClasses.name, compileTask.destinationDirectory) {
builtBy(compileTask)
}
}
}

View file

@ -5,7 +5,7 @@ import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.SourceSet
open class TransitiveSourceSetsExtension(private val project: Project) {
open class TransitiveSourceSetsExtension(val project: Project) {
var compileClasspath: FileCollection? = null
var runtimeClasspath: FileCollection? = null

View file

@ -6,49 +6,55 @@ plugins {
id("flywheel.subproject")
}
subproject.init("flywheel-common", "flywheel_group", "flywheel_version")
val api = sourceSets.create("api")
val lib = sourceSets.create("lib")
val backend = sourceSets.create("backend")
val stubs = sourceSets.create("stubs")
val main = sourceSets.getByName("main")
val vanillin = sourceSets.create("vanillin")
transitiveSourceSets {
compileClasspath = main.compileClasspath
sourceSet(api) {
rootCompile()
outgoingClasses()
}
sourceSet(lib) {
rootCompile()
compile(api)
compileClasspath(api)
outgoing()
}
sourceSet(backend) {
rootCompile()
compile(api, lib)
compileClasspath(api, lib)
outgoing()
}
sourceSet(stubs) {
rootCompile()
outgoingClasses()
}
sourceSet(main) {
compile(api, lib, backend, stubs)
compileClasspath(api, lib, backend)
outgoing()
}
sourceSet(sourceSets.getByName("test")) {
implementation(api, lib, backend)
}
sourceSet(vanillin) {
rootCompile()
compileClasspath(api, lib)
outgoing()
}
}
defaultPackageInfos {
sources(api, lib, backend, main)
sources(api, lib, backend, main, vanillin)
}
jarSets {
// For sharing with other subprojects.
outgoing("commonApiOnly", api)
outgoing("commonLib", lib)
outgoing("commonBackend", backend)
outgoing("commonStubs", stubs)
outgoing("commonImpl", main)
// For publishing.
create("api", api, lib).apply {
addToAssemble()
@ -77,6 +83,9 @@ jarSets {
dependencies {
modCompileOnly("net.fabricmc:fabric-loader:${property("fabric_loader_version")}")
modCompileOnly("maven.modrinth:sodium:${property("sodium_version")}-fabric")
modCompileOnly("maven.modrinth:iris:${property("iris_version")}-fabric")
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
}

View file

@ -9,6 +9,6 @@ public final class Flywheel {
}
public static ResourceLocation rl(String path) {
return new ResourceLocation(ID, path);
return ResourceLocation.fromNamespaceAndPath(ID, path);
}
}

View file

@ -2,8 +2,6 @@ package dev.engine_room.flywheel.api;
import org.joml.Matrix4fc;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
@ -16,7 +14,7 @@ public interface RenderContext {
RenderBuffers buffers();
PoseStack stack();
Matrix4fc modelView();
Matrix4fc projection();

View file

@ -15,11 +15,48 @@ public interface InstanceType<I extends Instance> {
*/
I create(InstanceHandle handle);
/**
* The native memory layout of this instance type.
*
* <p>This layout determines what fields are made available to the instance type's shaders
* as well as determining how the fields are arranged in memory.
*
* @return The layout of this instance type.
*/
Layout layout();
/**
* The writer of this instance type.
*
* <p>The writer of an InstanceType is responsible for translating java instance objects
* into contiguous native memory. The instance writer must write to the given pointer
* according to the layout of this instance type.
*
* <p>It is undefined behavior to write outside the half closed range
* {@code [ptr, ptr + layout().byteSize())}.
*
* @return The writer for this instance type.
*/
InstanceWriter<I> writer();
/**
* <p>The vertex shader of an InstanceType is responsible for transforming vertices from mesh
* space to world space in whatever way the instance type requires.
*
* @return The vertex shader for this instance type.
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation vertexShader();
/**
* The cull shader of this instance type.
*
* <p>The cull shader of an InstanceType is responsible for transforming bounding spheres from mesh
* space to world space, such that a mesh contained by the input bounding sphere and transformed
* by the vertex shader would be contained by the output bounding sphere.
*
* @return The cull shader for this instance type.
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation cullShader();
}

View file

@ -2,6 +2,12 @@ package dev.engine_room.flywheel.api.material;
import net.minecraft.resources.ResourceLocation;
/**
* A shader that decides what colors should be discarded in the fragment shader.
*/
public interface CutoutShader {
/**
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation source();
}

View file

@ -2,6 +2,12 @@ package dev.engine_room.flywheel.api.material;
import net.minecraft.resources.ResourceLocation;
/**
* A shader that controls the fog effect on a material.
*/
public interface FogShader {
/**
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation source();
}

View file

@ -2,6 +2,12 @@ package dev.engine_room.flywheel.api.material;
import net.minecraft.resources.ResourceLocation;
/**
* A shader that controls the GPU-based light on a material.
*/
public interface LightShader {
/**
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation source();
}

View file

@ -2,8 +2,17 @@ package dev.engine_room.flywheel.api.material;
import net.minecraft.resources.ResourceLocation;
/**
* A vertex and fragment shader pair that can be attached to a material.
*/
public interface MaterialShaders {
/**
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation vertexSource();
/**
* @apiNote {@code flywheel/} is implicitly prepended to the {@link ResourceLocation}'s path.
*/
ResourceLocation fragmentSource();
}

View file

@ -42,6 +42,10 @@ public class InstancedDraw {
return deleted;
}
public MeshPool.PooledMesh mesh() {
return mesh;
}
public void render(TextureBuffer buffer) {
if (mesh.isInvalid()) {
return;

View file

@ -64,6 +64,9 @@ public class InstancedRenderStage {
uploadMaterialUniform(program, material);
program.setUInt("_flw_vertexOffset", drawCall.mesh()
.baseVertex());
MaterialRenderState.setup(material);
Samplers.INSTANCE_BUFFER.makeActive();

View file

@ -14,6 +14,7 @@ public enum DebugMode implements StringRepresentable {
LIGHT_COLOR,
OVERLAY,
DIFFUSE,
MODEL_ID,
;
public static final Codec<DebugMode> CODEC = StringRepresentable.fromEnum(DebugMode::values);

View file

@ -73,7 +73,7 @@ public final class FrameUniforms extends UniformWriter {
var camY = (float) (cameraPos.y - renderOrigin.getY());
var camZ = (float) (cameraPos.z - renderOrigin.getZ());
VIEW.set(context.stack().last().pose());
VIEW.set(context.modelView());
VIEW.translate(-camX, -camY, -camZ);
PROJECTION.set(context.projection());
VIEW_PROJECTION.set(context.viewProjection());

View file

@ -41,7 +41,7 @@ public class ShaderSources {
}
private static ResourceLocation locationWithoutFlywheelPrefix(ResourceLocation loc) {
return new ResourceLocation(loc.getNamespace(), loc.getPath()
return ResourceLocation.fromNamespaceAndPath(loc.getNamespace(), loc.getPath()
.substring(SHADER_DIR.length()));
}

View file

@ -14,7 +14,7 @@ in vec2 _flw_crumblingTexCoord;
#endif
#ifdef _FLW_DEBUG
flat in uint _flw_instanceID;
flat in uvec2 _flw_ids;
#endif
out vec4 _flw_outputColor;
@ -79,7 +79,7 @@ void _flw_main() {
color = vec4(flw_vertexNormal * .5 + .5, 1.);
break;
case 2u:
color = _flw_id2Color(_flw_instanceID);
color = _flw_id2Color(_flw_ids.x);
break;
case 3u:
color = vec4(vec2((flw_fragLight * 15.0 + 0.5) / 16.), 0., 1.);
@ -93,6 +93,9 @@ void _flw_main() {
case 6u:
color = vec4(vec3(diffuseFactor), 1.);
break;
case 7u:
color = _flw_id2Color(_flw_ids.y);
break;
}
#endif

View file

@ -72,10 +72,10 @@ mat3 _flw_normalMatrix;
#endif
#ifdef _FLW_DEBUG
flat out uint _flw_instanceID;
flat out uvec2 _flw_ids;
#endif
void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
void _flw_main(in FlwInstance instance, in uint stableInstanceID, in uint modelID) {
_flw_layoutVertex();
flw_instanceVertex(instance);
flw_materialVertex();
@ -96,6 +96,6 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
gl_Position = flw_viewProjection * flw_vertexPos;
#ifdef _FLW_DEBUG
_flw_instanceID = stableInstanceID;
_flw_ids = uvec2(stableInstanceID, modelID);
#endif
}

View file

@ -51,5 +51,5 @@ void main() {
FlwInstance instance = _flw_unpackInstance(instanceIndex);
_flw_main(instance, instanceIndex);
_flw_main(instance, instanceIndex, draw.vertexOffset);
}

View file

@ -10,6 +10,8 @@ uniform mat4 _flw_modelMatrixUniform;
uniform mat3 _flw_normalMatrixUniform;
#endif
uniform uint _flw_vertexOffset;
void main() {
_flw_unpackMaterialProperties(_flw_packedMaterial.y, flw_material);
@ -20,5 +22,5 @@ void main() {
_flw_normalMatrix = _flw_normalMatrixUniform;
#endif
_flw_main(instance, uint(gl_InstanceID));
_flw_main(instance, uint(gl_InstanceID), _flw_vertexOffset);
}

View file

@ -2,7 +2,7 @@
"required": true,
"minVersion": "0.8",
"package": "dev.engine_room.flywheel.backend.mixin",
"compatibilityLevel": "JAVA_17",
"compatibilityLevel": "JAVA_21",
"refmap": "backend-flywheel.refmap.json",
"client": [
"AbstractClientPlayerAccessor",

View file

@ -21,7 +21,7 @@ public interface FlwLibLink {
Map<String, ModelPart> getModelPartChildren(ModelPart part);
void compileModelPart(ModelPart part, PoseStack.Pose pose, VertexConsumer consumer, int light, int overlay, float red, float green, float blue, float alpha);
void compileModelPart(ModelPart part, PoseStack.Pose pose, VertexConsumer consumer, int light, int overlay, int color);
Deque<PoseStack.Pose> getPoseStack(PoseStack stack);

View file

@ -3,15 +3,13 @@ package dev.engine_room.flywheel.lib.internal;
import org.jetbrains.annotations.UnknownNullability;
import dev.engine_room.flywheel.api.internal.DependencyInjection;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import dev.engine_room.flywheel.lib.model.baked.BakedModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.BlockModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.MultiBlockModelBuilder;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
public interface FlwLibXplat {
FlwLibXplat INSTANCE = DependencyInjection.load(FlwLibXplat.class, "dev.engine_room.flywheel.impl.FlwLibXplatImpl");
@ -19,9 +17,9 @@ public interface FlwLibXplat {
@UnknownNullability
BakedModel getBakedModel(ModelManager modelManager, ResourceLocation location);
BakedModelBuilder createBakedModelBuilder(BakedModel bakedModel);
SimpleModel buildBakedModelBuilder(BakedModelBuilder builder);
BlockModelBuilder createBlockModelBuilder(BlockState state);
SimpleModel buildBlockModelBuilder(BlockModelBuilder builder);
MultiBlockModelBuilder createMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions);
SimpleModel buildMultiBlockModelBuilder(MultiBlockModelBuilder builder);
}

View file

@ -53,7 +53,7 @@ public final class ModelUtil {
if (renderType == Sheets.translucentCullBlockSheet() || renderType == Sheets.translucentItemSheet()) {
return Materials.CUTOUT_BLOCK;
}
if (renderType == RenderType.glint() || renderType == RenderType.glintDirect()) {
if (renderType == RenderType.glint() || renderType == RenderType.glintTranslucent()) {
return Materials.GLINT;
}
if (renderType == RenderType.entityGlint() || renderType == RenderType.entityGlintDirect()) {

View file

@ -20,9 +20,9 @@ import net.minecraft.world.level.block.state.BlockState;
* method with the same parameters will return the same object.
*/
public final class Models {
private static final RendererReloadCache<BlockState, Model> BLOCK_STATE = new RendererReloadCache<>(it -> BlockModelBuilder.create(it)
private static final RendererReloadCache<BlockState, Model> BLOCK_STATE = new RendererReloadCache<>(it -> new BlockModelBuilder(it)
.build());
private static final RendererReloadCache<PartialModel, Model> PARTIAL = new RendererReloadCache<>(it -> BakedModelBuilder.create(it.get())
private static final RendererReloadCache<PartialModel, Model> PARTIAL = new RendererReloadCache<>(it -> new BakedModelBuilder(it.get())
.build());
private static final RendererReloadCache<TransformedPartial<?>, Model> TRANSFORMED_PARTIAL = new RendererReloadCache<>(TransformedPartial::create);
@ -88,7 +88,7 @@ public final class Models {
private Model create() {
var stack = new PoseStack();
transformer.accept(key, stack);
return BakedModelBuilder.create(partial.get())
return new BakedModelBuilder(partial.get())
.poseStack(stack)
.build();
}

View file

@ -2,21 +2,20 @@ package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.lib.internal.FlwLibXplat;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
@ApiStatus.NonExtendable
public abstract class BakedModelBuilder {
public final class BakedModelBuilder {
final BakedModel bakedModel;
@Nullable
BlockAndTintGetter level;
@ -27,14 +26,10 @@ public abstract class BakedModelBuilder {
@Nullable
BiFunction<RenderType, Boolean, Material> materialFunc;
BakedModelBuilder(BakedModel bakedModel) {
public BakedModelBuilder(BakedModel bakedModel) {
this.bakedModel = bakedModel;
}
public static BakedModelBuilder create(BakedModel bakedModel) {
return FlwLibXplat.INSTANCE.createBakedModelBuilder(bakedModel);
}
public BakedModelBuilder level(BlockAndTintGetter level) {
this.level = level;
return this;
@ -55,5 +50,11 @@ public abstract class BakedModelBuilder {
return this;
}
public abstract SimpleModel build();
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
return FlwLibXplat.INSTANCE.buildBakedModelBuilder(this);
}
}

View file

@ -2,20 +2,19 @@ package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.lib.internal.FlwLibXplat;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
@ApiStatus.NonExtendable
public abstract class BlockModelBuilder {
public final class BlockModelBuilder {
final BlockState state;
@Nullable
BlockAndTintGetter level;
@ -24,14 +23,10 @@ public abstract class BlockModelBuilder {
@Nullable
BiFunction<RenderType, Boolean, Material> materialFunc;
BlockModelBuilder(BlockState state) {
public BlockModelBuilder(BlockState state) {
this.state = state;
}
public static BlockModelBuilder create(BlockState state) {
return FlwLibXplat.INSTANCE.createBlockModelBuilder(state);
}
public BlockModelBuilder level(BlockAndTintGetter level) {
this.level = level;
return this;
@ -47,5 +42,11 @@ public abstract class BlockModelBuilder {
return this;
}
public abstract SimpleModel build();
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
return FlwLibXplat.INSTANCE.buildBlockModelBuilder(this);
}
}

View file

@ -5,7 +5,7 @@ import java.nio.ByteBuffer;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.MemoryUtil;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.MeshData;
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
import dev.engine_room.flywheel.lib.model.SimpleQuadMesh;
@ -16,15 +16,15 @@ final class MeshHelper {
private MeshHelper() {
}
public static SimpleQuadMesh blockVerticesToMesh(BufferBuilder.RenderedBuffer buffer, @Nullable String meshDescriptor) {
BufferBuilder.DrawState drawState = buffer.drawState();
public static SimpleQuadMesh blockVerticesToMesh(MeshData data, @Nullable String meshDescriptor) {
MeshData.DrawState drawState = data.drawState();
int vertexCount = drawState.vertexCount();
long srcStride = drawState.format().getVertexSize();
VertexView vertexView = new NoOverlayVertexView();
long dstStride = vertexView.stride();
ByteBuffer src = buffer.vertexBuffer();
ByteBuffer src = data.vertexBuffer();
MemoryBlock dst = MemoryBlock.mallocTracked((long) vertexCount * dstStride);
long srcPtr = MemoryUtil.memAddress(src);
long dstPtr = dst.ptr();

View file

@ -2,20 +2,19 @@ package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.lib.internal.FlwLibXplat;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
@ApiStatus.NonExtendable
public abstract class MultiBlockModelBuilder {
public final class MultiBlockModelBuilder {
final BlockAndTintGetter level;
final Iterable<BlockPos> positions;
@Nullable
@ -24,15 +23,11 @@ public abstract class MultiBlockModelBuilder {
@Nullable
BiFunction<RenderType, Boolean, Material> materialFunc;
MultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
public MultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
this.level = level;
this.positions = positions;
}
public static MultiBlockModelBuilder create(BlockAndTintGetter level, Iterable<BlockPos> positions) {
return FlwLibXplat.INSTANCE.createMultiBlockModelBuilder(level, positions);
}
public MultiBlockModelBuilder poseStack(PoseStack poseStack) {
this.poseStack = poseStack;
return this;
@ -48,5 +43,11 @@ public abstract class MultiBlockModelBuilder {
return this;
}
public abstract SimpleModel build();
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
return FlwLibXplat.INSTANCE.buildMultiBlockModelBuilder(this);
}
}

View file

@ -26,67 +26,46 @@ class TransformingVertexConsumer implements VertexConsumer {
}
@Override
public VertexConsumer vertex(double x, double y, double z) {
public VertexConsumer addVertex(float x, float y, float z) {
Matrix4f matrix = poseStack.last().pose();
float fx = (float) x;
float fy = (float) y;
float fz = (float) z;
delegate.vertex(
MatrixMath.transformPositionX(matrix, fx, fy, fz),
MatrixMath.transformPositionY(matrix, fx, fy, fz),
MatrixMath.transformPositionZ(matrix, fx, fy, fz));
delegate.addVertex(
MatrixMath.transformPositionX(matrix, x, y, z),
MatrixMath.transformPositionY(matrix, x, y, z),
MatrixMath.transformPositionZ(matrix, x, y, z));
return this;
}
@Override
public VertexConsumer color(int red, int green, int blue, int alpha) {
delegate.color(red, green, blue, alpha);
public VertexConsumer setColor(int red, int green, int blue, int alpha) {
delegate.setColor(red, green, blue, alpha);
return this;
}
@Override
public VertexConsumer uv(float u, float v) {
delegate.uv(u, v);
public VertexConsumer setUv(float u, float v) {
delegate.setUv(u, v);
return this;
}
@Override
public VertexConsumer overlayCoords(int u, int v) {
delegate.overlayCoords(u, v);
public VertexConsumer setUv1(int u, int v) {
delegate.setUv1(u, v);
return this;
}
@Override
public VertexConsumer uv2(int u, int v) {
delegate.uv2(u, v);
public VertexConsumer setUv2(int u, int v) {
delegate.setUv2(u, v);
return this;
}
@Override
public VertexConsumer normal(float x, float y, float z) {
public VertexConsumer setNormal(float x, float y, float z) {
Matrix3f matrix = poseStack.last().normal();
float fx = (float) x;
float fy = (float) y;
float fz = (float) z;
delegate.normal(
MatrixMath.transformNormalX(matrix, fx, fy, fz),
MatrixMath.transformNormalY(matrix, fx, fy, fz),
MatrixMath.transformNormalZ(matrix, fx, fy, fz));
delegate.setNormal(
MatrixMath.transformNormalX(matrix, x, y, z),
MatrixMath.transformNormalY(matrix, x, y, z),
MatrixMath.transformNormalZ(matrix, x, y, z));
return this;
}
@Override
public void endVertex() {
delegate.endVertex();
}
@Override
public void defaultColor(int red, int green, int blue, int alpha) {
delegate.defaultColor(red, green, blue, alpha);
}
@Override
public void unsetDefaultColor() {
delegate.unsetDefaultColor();
}
}

View file

@ -74,7 +74,7 @@ public final class MeshTree {
}
VertexWriter vertexWriter = objects.vertexWriter;
FlwLibLink.INSTANCE.compileModelPart(modelPart, IDENTITY_POSE, vertexWriter, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F);
FlwLibLink.INSTANCE.compileModelPart(modelPart, IDENTITY_POSE, vertexWriter, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF);
MemoryBlock data = vertexWriter.copyDataAndReset();
VertexView vertexView = new PosTexNormalVertexView();

View file

@ -14,34 +14,42 @@ class VertexWriter implements VertexConsumer {
private MemoryBlock data;
private int vertexCount;
private boolean filledPosition;
private boolean filledTexture;
private boolean filledNormal;
private boolean filledTexture = true;
private boolean filledNormal = true;
public VertexWriter() {
data = MemoryBlock.malloc(128 * STRIDE);
}
@Override
public VertexConsumer vertex(double x, double y, double z) {
if (!filledPosition) {
long ptr = vertexPtr();
MemoryUtil.memPutFloat(ptr, (float) x);
MemoryUtil.memPutFloat(ptr + 4, (float) y);
MemoryUtil.memPutFloat(ptr + 8, (float) z);
filledPosition = true;
public VertexConsumer addVertex(float x, float y, float z) {
endLastVertex();
vertexCount++;
long byteSize = vertexCount * STRIDE;
long capacity = data.size();
if (byteSize > capacity) {
data = data.realloc(capacity * 2);
}
filledTexture = false;
filledNormal = false;
long ptr = vertexPtr();
MemoryUtil.memPutFloat(ptr, x);
MemoryUtil.memPutFloat(ptr + 4, y);
MemoryUtil.memPutFloat(ptr + 8, z);
return this;
}
@Override
public VertexConsumer color(int red, int green, int blue, int alpha) {
public VertexConsumer setColor(int red, int green, int blue, int alpha) {
// ignore color
return this;
}
@Override
public VertexConsumer uv(float u, float v) {
public VertexConsumer setUv(float u, float v) {
if (!filledTexture) {
long ptr = vertexPtr();
MemoryUtil.memPutFloat(ptr + 12, u);
@ -52,19 +60,19 @@ class VertexWriter implements VertexConsumer {
}
@Override
public VertexConsumer overlayCoords(int u, int v) {
public VertexConsumer setUv1(int u, int v) {
// ignore overlay
return this;
}
@Override
public VertexConsumer uv2(int u, int v) {
public VertexConsumer setUv2(int u, int v) {
// ignore light
return this;
}
@Override
public VertexConsumer normal(float x, float y, float z) {
public VertexConsumer setNormal(float x, float y, float z) {
if (!filledNormal) {
long ptr = vertexPtr();
MemoryUtil.memPutByte(ptr + 20, DataPacker.packNormI8(x));
@ -75,44 +83,27 @@ class VertexWriter implements VertexConsumer {
return this;
}
@Override
public void endVertex() {
if (!filledPosition || !filledTexture || !filledNormal) {
throw new IllegalStateException("Not filled all elements of the vertex");
}
filledPosition = false;
filledTexture = false;
filledNormal = false;
vertexCount++;
long byteSize = (vertexCount + 1) * STRIDE;
long capacity = data.size();
if (byteSize > capacity) {
data = data.realloc(capacity * 2);
}
}
@Override
public void defaultColor(int red, int green, int blue, int alpha) {
}
@Override
public void unsetDefaultColor() {
}
private long vertexPtr() {
return data.ptr() + vertexCount * STRIDE;
return data.ptr() + (vertexCount - 1) * STRIDE;
}
private void endLastVertex() {
if (vertexCount != 0) {
if (!filledTexture || !filledNormal) {
throw new IllegalStateException("Missing elements in vertex");
}
}
}
public MemoryBlock copyDataAndReset() {
endLastVertex();
MemoryBlock dataCopy = MemoryBlock.mallocTracked(vertexCount * STRIDE);
data.copyTo(dataCopy);
vertexCount = 0;
filledPosition = false;
filledTexture = false;
filledNormal = false;
filledTexture = true;
filledNormal = true;
return dataCopy;
}

View file

@ -16,7 +16,7 @@ public final class ResourceUtil {
}
/**
* Same as {@link ResourceLocation#ResourceLocation(String)}, but defaults to Flywheel namespace.
* Same as {@link ResourceLocation#parse(String)}, but defaults to Flywheel namespace.
*/
public static ResourceLocation parseFlywheelDefault(String location) {
String namespace = Flywheel.ID;
@ -30,7 +30,7 @@ public final class ResourceUtil {
}
}
return new ResourceLocation(namespace, path);
return ResourceLocation.fromNamespaceAndPath(namespace, path);
}
/**

View file

@ -8,8 +8,8 @@ public final class VertexTransformations {
}
public static void retexture(MutableVertexList vertexList, int index, TextureAtlasSprite sprite) {
vertexList.u(index, sprite.getU(vertexList.u(index) * 16));
vertexList.v(index, sprite.getV(vertexList.v(index) * 16));
vertexList.u(index, sprite.getU(vertexList.u(index)));
vertexList.v(index, sprite.getV(vertexList.v(index)));
}
public static void retexture(MutableVertexList vertexList, TextureAtlasSprite sprite) {

View file

@ -42,7 +42,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
* The shadow will be cast on blocks at most {@code min(radius, 2 * strength)} blocks below the entity.</p>
*/
public final class ShadowComponent implements EntityComponent {
private static final ResourceLocation SHADOW_TEXTURE = new ResourceLocation("textures/misc/shadow.png");
private static final ResourceLocation SHADOW_TEXTURE = ResourceLocation.withDefaultNamespace("textures/misc/shadow.png");
private static final Material SHADOW_MATERIAL = SimpleMaterial.builder()
.texture(SHADOW_TEXTURE)
.mipmap(false)

View file

@ -6,7 +6,6 @@ import org.slf4j.LoggerFactory;
import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.backend.FlwBackend;
import dev.engine_room.flywheel.impl.registry.IdRegistryImpl;
import dev.engine_room.flywheel.vanilla.VanillaVisuals;
public final class FlwImpl {
public static final Logger LOGGER = LoggerFactory.getLogger(Flywheel.ID);
@ -23,9 +22,6 @@ public final class FlwImpl {
// backend
FlwBackend.init(FlwConfig.INSTANCE.backendConfig());
// vanilla
VanillaVisuals.init();
}
public static void freezeRegistries() {

View file

@ -13,8 +13,4 @@ public interface FlwImplXplat {
String getVersionStr();
FlwConfig getConfig();
boolean useSodium0_6Compat();
boolean useIrisCompat();
}

View file

@ -34,8 +34,8 @@ public class FlwLibLinkImpl implements FlwLibLink {
}
@Override
public void compileModelPart(ModelPart part, PoseStack.Pose pose, VertexConsumer consumer, int light, int overlay, float red, float green, float blue, float alpha) {
((ModelPartAccessor) (Object) part).flywheel$compile(pose, consumer, light, overlay, red, green, blue, alpha);
public void compileModelPart(ModelPart part, PoseStack.Pose pose, VertexConsumer consumer, int light, int overlay, int color) {
((ModelPartAccessor) (Object) part).flywheel$compile(pose, consumer, light, overlay, color);
}
@Override

View file

@ -5,7 +5,6 @@ import dev.engine_room.flywheel.impl.FlwImplXplat;
public enum CompatMod {
EMBEDDIUM("embeddium"),
IRIS("iris"),
OCULUS("oculus"),
SODIUM("sodium");
public final String id;

View file

@ -1,11 +1,10 @@
package dev.engine_room.flywheel.impl.compat;
import dev.engine_room.flywheel.impl.FlwImpl;
import dev.engine_room.flywheel.impl.FlwImplXplat;
import net.irisshaders.iris.api.v0.IrisApi;
public final class IrisCompat {
public static final boolean ACTIVE = FlwImplXplat.INSTANCE.useIrisCompat();
public static final boolean ACTIVE = CompatMod.IRIS.isLoaded;
static {
if (ACTIVE) {

View file

@ -4,7 +4,6 @@ import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
import dev.engine_room.flywheel.impl.FlwImpl;
import dev.engine_room.flywheel.impl.FlwImplXplat;
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
import net.caffeinemc.mods.sodium.api.blockentity.BlockEntityRenderHandler;
import net.caffeinemc.mods.sodium.api.blockentity.BlockEntityRenderPredicate;
@ -12,11 +11,11 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
public final class SodiumCompat {
public static final boolean USE_0_6_COMPAT = FlwImplXplat.INSTANCE.useSodium0_6Compat();
public static final boolean ACTIVE = CompatMod.SODIUM.isLoaded;
static {
if (USE_0_6_COMPAT) {
FlwImpl.LOGGER.debug("Detected Sodium 0.6");
if (ACTIVE) {
FlwImpl.LOGGER.debug("Detected Sodium");
}
}
@ -25,7 +24,7 @@ public final class SodiumCompat {
@Nullable
public static <T extends BlockEntity> Object onSetBlockEntityVisualizer(BlockEntityType<T> type, @Nullable BlockEntityVisualizer<? super T> oldVisualizer, @Nullable BlockEntityVisualizer<? super T> newVisualizer, @Nullable Object predicate) {
if (!USE_0_6_COMPAT) {
if (!ACTIVE) {
return null;
}
@ -49,7 +48,7 @@ public final class SodiumCompat {
private static final class Internals {
static <T extends BlockEntity> Object addPredicate(BlockEntityType<T> type) {
BlockEntityRenderPredicate<T> predicate = (getter, pos, be) -> VisualizationHelper.tryAddBlockEntity(be);
BlockEntityRenderPredicate<T> predicate = (getter, pos, be) -> !VisualizationHelper.tryAddBlockEntity(be);
BlockEntityRenderHandler.instance().addRenderPredicate(type, predicate);
return predicate;
}

View file

@ -3,22 +3,19 @@ package dev.engine_room.flywheel.impl.event;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.RenderContext;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.RenderBuffers;
public record RenderContextImpl(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack,
public record RenderContextImpl(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, Matrix4fc modelView,
Matrix4fc projection, Matrix4fc viewProjection, Camera camera,
float partialTick) implements RenderContext {
public static RenderContextImpl create(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, Matrix4f projection, Camera camera, float partialTick) {
public static RenderContextImpl create(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, Matrix4fc modelView, Matrix4f projection, Camera camera, float partialTick) {
Matrix4f viewProjection = new Matrix4f(projection);
viewProjection.mul(stack.last()
.pose());
viewProjection.mul(modelView);
return new RenderContextImpl(renderer, level, buffers, stack, projection, viewProjection, camera, partialTick);
return new RenderContextImpl(renderer, level, buffers, modelView, projection, viewProjection, camera, partialTick);
}
}

View file

@ -28,7 +28,7 @@ abstract class BlockEntityTypeMixin<T extends BlockEntity> implements BlockEntit
@Override
public void flywheel$setVisualizer(@Nullable BlockEntityVisualizer<? super T> visualizer) {
if (SodiumCompat.USE_0_6_COMPAT) {
if (SodiumCompat.ACTIVE) {
flywheel$sodiumPredicate = SodiumCompat.onSetBlockEntityVisualizer((BlockEntityType<T>) (Object) this, flywheel$visualizer, visualizer, flywheel$sodiumPredicate);
}

View file

@ -22,6 +22,7 @@ import dev.engine_room.flywheel.impl.event.RenderContextImpl;
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
@ -51,8 +52,8 @@ abstract class LevelRendererMixin {
// @Inject(method = "renderLevel", at = @At("HEAD"))
@Inject(method = "renderLevel", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"))
private void flywheel$beginRender(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
flywheel$renderContext = RenderContextImpl.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera, partialTick);
private void flywheel$beginRender(DeltaTracker deltaTracker, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f modelMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
flywheel$renderContext = RenderContextImpl.create((LevelRenderer) (Object) this, level, renderBuffers, modelMatrix, projectionMatrix, camera, deltaTracker.getGameTimeDeltaPartialTick(false));
VisualizationManager manager = VisualizationManager.get(level);
if (manager != null) {
@ -102,8 +103,8 @@ abstract class LevelRendererMixin {
}
}
@Group(name = "afterParticles", min = 2, max = 2)
@Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleEngine;render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;F)V", shift = Shift.AFTER))
@Group(name = "afterParticles", min = 2, max = 3)
@Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleEngine;render(Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;F)V", shift = Shift.AFTER))
private void flywheel$afterParticles$fabric(CallbackInfo ci) {
if (flywheel$renderContext != null) {
VisualizationManager manager = VisualizationManager.get(level);
@ -114,8 +115,8 @@ abstract class LevelRendererMixin {
}
@Group(name = "afterParticles")
@Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleEngine;render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;FLnet/minecraft/client/renderer/culling/Frustum;)V", shift = Shift.AFTER))
private void flywheel$afterParticles$forge(CallbackInfo ci) {
@Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleEngine;render(Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;FLnet/minecraft/client/renderer/culling/Frustum;Ljava/util/function/Predicate;)V", shift = Shift.AFTER))
private void flywheel$afterParticles$neoforge(CallbackInfo ci) {
if (flywheel$renderContext != null) {
VisualizationManager manager = VisualizationManager.get(level);
if (manager != null) {

View file

@ -17,5 +17,5 @@ public interface ModelPartAccessor {
Map<String, ModelPart> flywheel$children();
@Invoker("compile")
void flywheel$compile(PoseStack.Pose pose, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha);
void flywheel$compile(PoseStack.Pose pose, VertexConsumer buffer, int packedLight, int packedOverlay, int color);
}

View file

@ -1,36 +0,0 @@
package dev.engine_room.flywheel.impl.mixin.fix;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.vertex.PoseStack;
@Mixin(PoseStack.class)
abstract class FixNormalScalingMixin {
/**
* Minecraft negates the normal matrix if all scales are equal and negative, but
* does not return afterward. This allows the rest of the method's logic to be
* applied, which negates the matrix again, resulting in the matrix being the
* same as in the beginning.
*/
@Inject(method = "scale(FFF)V", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix3f;scale(F)Lorg/joml/Matrix3f;", shift = Shift.AFTER, remap = false), cancellable = true)
private void flywheel$returnAfterNegate(float x, float y, float z, CallbackInfo ci) {
ci.cancel();
}
/**
* Minecraft takes the inverse cube root of the product of all scales to provide a
* rough estimate for normalization so that it does not need to be done later. It
* does not make sense for this "normalization factor" to be negative though, as
* that would invert all normals. Additionally, Minecraft's fastInvCubeRoot method
* does not work for negative numbers.
*/
@ModifyArg(method = "scale(FFF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;fastInvCubeRoot(F)F"))
private float flywheel$absInvCbrtInput(float input) {
return Math.abs(input);
}
}

View file

@ -7,11 +7,12 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
import net.minecraft.client.renderer.chunk.SectionCompiler;
import net.minecraft.world.level.block.entity.BlockEntity;
@Mixin(targets = "net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk$RebuildTask")
abstract class RebuildTaskMixin {
@Inject(method = "handleBlockEntity(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk$RebuildTask$CompileResults;Lnet/minecraft/world/level/block/entity/BlockEntity;)V", at = @At("HEAD"), cancellable = true)
@Mixin(SectionCompiler.class)
abstract class SectionCompilerMixin {
@Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true)
private void flywheel$tryAddBlockEntity(@Coerce Object compileResults, BlockEntity blockEntity, CallbackInfo ci) {
if (VisualizationHelper.tryAddBlockEntity(blockEntity)) {
ci.cancel();

View file

@ -2,7 +2,7 @@
"required": true,
"minVersion": "0.8",
"package": "dev.engine_room.flywheel.impl.mixin",
"compatibilityLevel": "JAVA_17",
"compatibilityLevel": "JAVA_21",
"refmap": "flywheel.refmap.json",
"client": [
"BlockEntityTypeMixin",
@ -15,11 +15,10 @@
"PoseStackAccessor",
"PoseStackMixin",
"fix.FixFabulousDepthMixin",
"fix.FixNormalScalingMixin",
"visualmanage.BlockEntityMixin",
"visualmanage.LevelChunkMixin",
"visualmanage.LevelRendererMixin",
"visualmanage.RebuildTaskMixin"
"visualmanage.SectionCompilerMixin"
],
"injectors": {
"defaultRequire": 1

View file

@ -1,38 +0,0 @@
// https://github.com/CaffeineMC/sodium-fabric/blob/e7643f4544f61180ed2f0ff4952d7daa2c1feaf4/common/src/api/java/net/caffeinemc/mods/sodium/api/blockentity/BlockEntityRenderHandler.java
// PolyForm Shield License 1.0.0
package net.caffeinemc.mods.sodium.api.blockentity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
@ApiStatus.AvailableSince("0.6.0")
public interface BlockEntityRenderHandler {
BlockEntityRenderHandler INSTANCE = null;
static BlockEntityRenderHandler instance() {
return INSTANCE;
}
/**
* Adds a predicate to determine if a block entity should be rendered.
*
* <p>Upon chunk bake, block entities of the given type will have {@code shouldRender} evaluated.
* <br>If <b>all predicates</b> returns {@code true} (and the block entity has a renderer), the block entity will be
* added to the chunk for future rendering.</p>
* @param type The block entity type to associate the given predicate with.
* @param shouldRender The predicate for the block entity to evaluate.
*/
<T extends BlockEntity> void addRenderPredicate(BlockEntityType<T> type, BlockEntityRenderPredicate<T> shouldRender);
/**
* Removes a predicate added by {@code addRenderPredicate}. <b>It must be the same object that was added.</b>
*
* @param type The block entity type to associate the given predicate with.
* @param shouldRender The predicate to remove.
* @return If the predicate existed and was removed.
*/
<T extends BlockEntity> boolean removeRenderPredicate(BlockEntityType<T> type, BlockEntityRenderPredicate<T> shouldRender);
}

View file

@ -1,16 +0,0 @@
// https://github.com/CaffeineMC/sodium-fabric/blob/e7643f4544f61180ed2f0ff4952d7daa2c1feaf4/common/src/api/java/net/caffeinemc/mods/sodium/api/blockentity/BlockEntityRenderPredicate.java
// PolyForm Shield License 1.0.0
package net.caffeinemc.mods.sodium.api.blockentity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
@ApiStatus.AvailableSince("0.6.0")
@FunctionalInterface
public interface BlockEntityRenderPredicate<T extends BlockEntity> {
boolean shouldRender(BlockGetter blockGetter, BlockPos blockPos, T entity);
}

View file

@ -1,114 +0,0 @@
// https://github.com/IrisShaders/Iris/blob/20be7fc1ff8a48048cb4eb787e1299782bb1caa4/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java
// GNU Lesser General Public License v3.0
package net.irisshaders.iris.api.v0;
/**
* The entry point to the Iris API, major version 0. This is currently the latest
* version of the API.
*
* To access the API, use {@link #getInstance()}.
*/
public interface IrisApi {
/**
* @since API v0.0
*/
static IrisApi getInstance() {
return null;
}
/**
* Gets the minor revision of this API. This is incremented when
* new methods are added without breaking API. Mods can check this
* if they wish to check whether given API calls are available on
* the currently installed Iris version.
*
* @return The current minor revision. Currently, revision 2.
*/
int getMinorApiRevision();
/**
* Checks whether a shader pack is currently in use and being used
* for rendering. If there is no shader pack enabled or a shader
* pack failed to compile and is therefore not in use, this will
* return false.
*
* <p>Mods that need to enable custom workarounds for shaders
* should use this method.
*
* @return Whether shaders are being used for rendering.
* @since {@link #getMinorApiRevision() API v0.0}
*/
boolean isShaderPackInUse();
/**
* Checks whether the shadow pass is currently being rendered.
*
* <p>Generally, mods won't need to call this function for much.
* Mods should be fine with things being rendered multiple times
* each frame from different camera perspectives. Often, there's
* a better approach to fixing bugs than calling this function.
*
* <p>Pretty much the main legitimate use for this function that
* I've seen is in a mod like Immersive Portals, where it has
* very custom culling that doesn't work when the Iris shadow
* pass is active.
*
* <p>Naturally, this function can only return true if
* {@link #isShaderPackInUse()} returns true.
*
* @return Whether Iris is currently rendering the shadow pass.
* @since API v0.0
*/
boolean isRenderingShadowPass();
/**
* Opens the main Iris GUI screen. It's up to Iris to decide
* what this screen is, but generally this is the shader selection
* screen.
*
* This method takes and returns Objects instead of any concrete
* Minecraft screen class to avoid referencing Minecraft classes.
* Nevertheless, the passed parent must either be null, or an
* object that is a subclass of the appropriate {@code Screen}
* class for the given Minecraft version.
*
* @param parent The parent screen, an instance of the appropriate
* {@code Screen} class.
* @return A {@code Screen} class for the main Iris GUI screen.
* @since API v0.0
*/
Object openMainIrisScreenObj(Object parent);
/**
* Gets the language key of the main screen. Currently, this
* is "options.iris.shaderPackSelection".
*
* @return the language key, for use with {@code TranslatableText}
* / {@code TranslatableComponent}
* @since API v0.0
*/
String getMainScreenLanguageKey();
// /**
// * Gets a config object that can edit the Iris configuration.
// * @since API v0.0
// */
// IrisApiConfig getConfig();
// /**
// * Gets a text vertex sink to render into.
// * @param maxQuadCount Maximum amount of quads that will be rendered with this sink
// * @param bufferProvider An IntFunction that can provide a {@code ByteBuffer} with at minimum the bytes provided by the input parameter
// * @since API 0.1
// */
// IrisTextVertexSink createTextVertexSink(int maxQuadCount, IntFunction<ByteBuffer> bufferProvider);
/**
* Gets the sun path rotation used by the current shader pack.
*
* @return The sun path rotation as specified by the shader pack, or 0 if no shader pack is in use.
* @since API v0.2
*/
float getSunPathRotation();
}

View file

@ -0,0 +1,5 @@
package dev.engine_room.vanillin;
public class Vanillin {
public static final String ID = "vanillin";
}

View file

@ -1,4 +1,4 @@
package dev.engine_room.flywheel.vanilla;
package dev.engine_room.vanillin.visuals;
import java.util.function.Consumer;

View file

@ -1,4 +1,4 @@
package dev.engine_room.flywheel.vanilla;
package dev.engine_room.vanillin.visuals;
import java.util.Calendar;
import java.util.EnumMap;

View file

@ -1,4 +1,4 @@
package dev.engine_room.flywheel.vanilla;
package dev.engine_room.vanillin.visuals;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
@ -30,7 +30,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityVisual<T> implements SimpleTickableVisual, SimpleDynamicVisual {
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/entity/minecart.png");
private static final ResourceLocation TEXTURE = ResourceLocation.withDefaultNamespace("textures/entity/minecart.png");
private static final Material MATERIAL = SimpleMaterial.builder()
.texture(TEXTURE)
.mipmap(false)

View file

@ -1,4 +1,4 @@
package dev.engine_room.flywheel.vanilla;
package dev.engine_room.vanillin.visuals;
import java.util.Set;
import java.util.function.Consumer;

View file

@ -1,4 +1,4 @@
package dev.engine_room.flywheel.vanilla;
package dev.engine_room.vanillin.visuals;
import org.joml.Matrix4f;

View file

@ -1,4 +1,4 @@
package dev.engine_room.flywheel.vanilla;
package dev.engine_room.vanillin.visuals;
import static dev.engine_room.flywheel.lib.visualization.SimpleBlockEntityVisualizer.builder;
import static dev.engine_room.flywheel.lib.visualization.SimpleEntityVisualizer.builder;

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -7,6 +7,11 @@ plugins {
id("flywheel.platform")
}
val common = ":common"
val commonProject = project(common)
subproject.init("flywheel-fabric", "flywheel_group", "flywheel_version")
val api = sourceSets.create("api")
val lib = sourceSets.create("lib")
val backend = sourceSets.create("backend")
@ -19,22 +24,34 @@ transitiveSourceSets {
sourceSet(api) {
rootCompile()
from(commonProject)
}
sourceSet(lib) {
rootCompile()
compile(api)
compileClasspath(api)
from(commonProject)
}
sourceSet(backend) {
rootCompile()
compile(api, lib)
compileClasspath(api, lib)
from(commonProject)
}
sourceSet(stubs) {
rootCompile()
from(commonProject)
}
sourceSet(main) {
// Don't want stubs at runtime
compile(stubs)
compileClasspath(stubs)
implementation(api, lib, backend)
bundleFrom(commonProject)
bundleOutput(api, lib, backend)
}
sourceSet(testMod) {
rootCompile()
@ -44,19 +61,18 @@ transitiveSourceSets {
}
platform {
commonProject = project(":common")
compileWithCommonSourceSets(api, lib, backend, stubs, main)
setupLoomMod(api, lib, backend, main)
setupLoomRuns()
setupFatJar(api, lib, backend, main)
setupTestMod(testMod)
}
jarSets {
mainSet.publish(platform.modArtifactId)
mainSet.publish("flywheel-fabric-${project.property("artifact_minecraft_version")}")
mainSet.outgoing("flywheel")
create("api", api, lib).apply {
addToAssemble()
publish(platform.apiArtifactId)
publish("flywheel-fabric-api-${project.property("artifact_minecraft_version")}")
configureJar {
manifest {
@ -82,11 +98,16 @@ dependencies {
modImplementation("net.fabricmc:fabric-loader:${property("fabric_loader_version")}")
modApi("net.fabricmc.fabric-api:fabric-api:${property("fabric_api_version")}")
modCompileOnly("maven.modrinth:sodium:${property("sodium_version")}")
modCompileOnly("maven.modrinth:sodium:${property("sodium_version")}-fabric")
modCompileOnly("maven.modrinth:iris:${property("iris_version")}-fabric")
"forApi"(project(path = ":common", configuration = "commonApiOnly"))
"forLib"(project(path = ":common", configuration = "commonLib"))
"forBackend"(project(path = ":common", configuration = "commonBackend"))
"forStubs"(project(path = ":common", configuration = "commonStubs"))
"forMain"(project(path = ":common", configuration = "commonImpl"))
"forApi"(project(path = common, configuration = "apiClasses"))
"forLib"(project(path = common, configuration = "libClasses"))
"forBackend"(project(path = common, configuration = "backendClasses"))
"forStubs"(project(path = common, configuration = "stubsClasses"))
"forMain"(project(path = common, configuration = "mainClasses"))
"forLib"(project(path = common, configuration = "libResources"))
"forBackend"(project(path = common, configuration = "backendResources"))
"forMain"(project(path = common, configuration = "mainResources"))
}

View file

@ -4,7 +4,7 @@ import java.util.Iterator;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
import com.mojang.blaze3d.vertex.MeshData;
import com.mojang.blaze3d.vertex.PoseStack;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
@ -150,7 +150,7 @@ final class BakedModelBufferer {
}
public interface ResultConsumer {
void accept(RenderType renderType, boolean shaded, RenderedBuffer data);
void accept(RenderType renderType, boolean shaded, MeshData data);
}
private static class ThreadLocalObjects {

View file

@ -1,64 +0,0 @@
package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
public final class FabricBakedModelBuilder extends BakedModelBuilder {
public FabricBakedModelBuilder(BakedModel bakedModel) {
super(bakedModel);
}
@Override
public FabricBakedModelBuilder level(BlockAndTintGetter level) {
super.level(level);
return this;
}
@Override
public FabricBakedModelBuilder blockState(BlockState blockState) {
super.blockState(blockState);
return this;
}
@Override
public FabricBakedModelBuilder poseStack(PoseStack poseStack) {
super.poseStack(poseStack);
return this;
}
@Override
public FabricBakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
super.materialFunc(materialFunc);
return this;
}
@Override
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferSingle(level, bakedModel, blockState, poseStack, (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder.build());
}
}

View file

@ -1,57 +0,0 @@
package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
public final class FabricBlockModelBuilder extends BlockModelBuilder {
public FabricBlockModelBuilder(BlockState state) {
super(state);
}
@Override
public FabricBlockModelBuilder level(BlockAndTintGetter level) {
super.level(level);
return this;
}
@Override
public FabricBlockModelBuilder poseStack(PoseStack poseStack) {
super.poseStack(poseStack);
return this;
}
@Override
public FabricBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
super.materialFunc(materialFunc);
return this;
}
@Override
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferBlock(level, state, poseStack, (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder.build());
}
}

View file

@ -1,57 +0,0 @@
package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
public final class FabricMultiBlockModelBuilder extends MultiBlockModelBuilder {
public FabricMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
super(level, positions);
}
@Override
public FabricMultiBlockModelBuilder poseStack(PoseStack poseStack) {
super.poseStack(poseStack);
return this;
}
@Override
public FabricMultiBlockModelBuilder enableFluidRendering() {
super.enableFluidRendering();
return this;
}
@Override
public FabricMultiBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
super.materialFunc(materialFunc);
return this;
}
@Override
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferMultiBlock(positions.iterator(), level, poseStack, renderFluids, (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder.build());
}
}

View file

@ -3,6 +3,7 @@ package dev.engine_room.flywheel.lib.model.baked;
import org.jetbrains.annotations.UnknownNullability;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
@ -10,14 +11,16 @@ import net.minecraft.client.renderer.RenderType;
class MeshEmitter {
private final RenderType renderType;
private final BufferBuilder bufferBuilder;
private final ByteBufferBuilder byteBufferBuilder;
@UnknownNullability
private BufferBuilder bufferBuilder;
private BakedModelBufferer.@UnknownNullability ResultConsumer resultConsumer;
private boolean currentShade;
MeshEmitter(RenderType renderType) {
this.renderType = renderType;
this.bufferBuilder = new BufferBuilder(renderType.bufferSize());
this.byteBufferBuilder = new ByteBufferBuilder(renderType.bufferSize());
}
public void prepare(BakedModelBufferer.ResultConsumer resultConsumer) {
@ -25,7 +28,7 @@ class MeshEmitter {
}
public void end() {
if (bufferBuilder.building()) {
if (bufferBuilder != null) {
emit();
}
resultConsumer = null;
@ -36,23 +39,24 @@ class MeshEmitter {
return bufferBuilder;
}
void prepareForGeometry(boolean shade) {
if (!bufferBuilder.building()) {
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
private void prepareForGeometry(boolean shade) {
if (bufferBuilder == null) {
bufferBuilder = new BufferBuilder(byteBufferBuilder, VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
} else if (shade != currentShade) {
emit();
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
bufferBuilder = new BufferBuilder(byteBufferBuilder, VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
}
currentShade = shade;
}
void emit() {
var renderedBuffer = bufferBuilder.endOrDiscardIfEmpty();
private void emit() {
var data = bufferBuilder.build();
bufferBuilder = null;
if (renderedBuffer != null) {
resultConsumer.accept(renderType, currentShade, renderedBuffer);
renderedBuffer.release();
if (data != null) {
resultConsumer.accept(renderType, currentShade, data);
data.close();
}
}
}

View file

@ -0,0 +1,56 @@
package dev.engine_room.flywheel.lib.model.baked;
import org.jetbrains.annotations.ApiStatus;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.SimpleModel;
@ApiStatus.Internal
public final class ModelBuilderImpl {
private ModelBuilderImpl() {
}
public static SimpleModel buildBakedModelBuilder(BakedModelBuilder builder) {
var builder1 = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferSingle(builder.level, builder.bakedModel, builder.blockState, builder.poseStack, (renderType, shaded, data) -> {
Material material = builder.materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=BakedModelBuilder," + "bakedModel=" + builder.bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
builder1.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder1.build());
}
public static SimpleModel buildBlockModelBuilder(BlockModelBuilder builder) {
var builder1 = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferBlock(builder.level, builder.state, builder.poseStack, (renderType, shaded, data) -> {
Material material = builder.materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=BlockModelBuilder," + "blockState=" + builder.state + ",renderType=" + renderType + ",shaded=" + shaded);
builder1.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder1.build());
}
public static SimpleModel buildMultiBlockModelBuilder(MultiBlockModelBuilder builder) {
var builder1 = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferMultiBlock(builder.positions.iterator(), builder.level, builder.poseStack, builder.renderFluids, (renderType, shaded, data) -> {
Material material = builder.materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
builder1.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder1.build());
}
}

View file

@ -56,69 +56,54 @@ class UniversalMeshEmitter implements VertexConsumer {
}
@Override
public VertexConsumer vertex(double x, double y, double z) {
currentDelegate.vertex(x, y, z);
public VertexConsumer addVertex(float x, float y, float z) {
currentDelegate.addVertex(x, y, z);
return this;
}
@Override
public VertexConsumer color(int red, int green, int blue, int alpha) {
currentDelegate.color(red, green, blue, alpha);
public VertexConsumer setColor(int red, int green, int blue, int alpha) {
currentDelegate.setColor(red, green, blue, alpha);
return this;
}
@Override
public VertexConsumer uv(float u, float v) {
currentDelegate.uv(u, v);
public VertexConsumer setUv(float u, float v) {
currentDelegate.setUv(u, v);
return this;
}
@Override
public VertexConsumer overlayCoords(int u, int v) {
currentDelegate.overlayCoords(u, v);
public VertexConsumer setUv1(int u, int v) {
currentDelegate.setUv1(u, v);
return this;
}
@Override
public VertexConsumer uv2(int u, int v) {
currentDelegate.uv2(u, v);
public VertexConsumer setUv2(int u, int v) {
currentDelegate.setUv2(u, v);
return this;
}
@Override
public VertexConsumer normal(float x, float y, float z) {
currentDelegate.normal(x, y, z);
public VertexConsumer setNormal(float x, float y, float z) {
currentDelegate.setNormal(x, y, z);
return this;
}
@Override
public void endVertex() {
currentDelegate.endVertex();
public void addVertex(float x, float y, float z, int color, float u, float v, int packedOverlay, int packedLight, float normalX, float normalY, float normalZ) {
currentDelegate.addVertex(x, y, z, color, u, v, packedOverlay, packedLight, normalX, normalY, normalZ);
}
@Override
public void defaultColor(int red, int green, int blue, int alpha) {
currentDelegate.defaultColor(red, green, blue, alpha);
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float red, float green, float blue, float alpha, int packedLight, int packedOverlay) {
currentDelegate.putBulkData(pose, quad, red, green, blue, alpha, packedLight, packedOverlay);
}
@Override
public void unsetDefaultColor() {
currentDelegate.unsetDefaultColor();
}
@Override
public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) {
currentDelegate.vertex(x, y, z, red, green, blue, alpha, u, v, overlay, light, normalX, normalY, normalZ);
}
@Override
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float red, float green, float blue, int light, int overlay) {
currentDelegate.putBulkData(pose, quad, red, green, blue, light, overlay);
}
@Override
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float[] brightnesses, float red, float green, float blue, int[] lights, int overlay, boolean readExistingColor) {
currentDelegate.putBulkData(pose, quad, brightnesses, red, green, blue, lights, overlay, readExistingColor);
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float[] brightness, float red, float green, float blue, float alpha, int[] lightmap, int packedOverlay, boolean readAlpha) {
currentDelegate.putBulkData(pose, quad, brightness, red, green, blue, alpha, lightmap, packedOverlay, readAlpha);
}
private class WrapperModel extends ForwardingBakedModel {

View file

@ -110,7 +110,7 @@ public class FabricFlwConfig implements FlwConfig {
if (backendJson instanceof JsonPrimitive primitive && primitive.isString()) {
var value = primitive.getAsString();
try {
this.backend = Backend.REGISTRY.getOrThrow(new ResourceLocation(value));
this.backend = Backend.REGISTRY.getOrThrow(ResourceLocation.parse(value));
return;
} catch (ResourceLocationException e) {
msg = "'backend' value '" + value + "' is not a valid resource location";

View file

@ -1,8 +1,6 @@
package dev.engine_room.flywheel.impl;
import dev.engine_room.flywheel.api.event.ReloadLevelRendererCallback;
import dev.engine_room.flywheel.impl.compat.CompatMod;
import dev.engine_room.flywheel.impl.compat.FabricSodiumCompat;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.multiplayer.ClientLevel;
@ -26,14 +24,4 @@ public class FlwImplXplatImpl implements FlwImplXplat {
public FlwConfig getConfig() {
return FabricFlwConfig.INSTANCE;
}
@Override
public boolean useSodium0_6Compat() {
return FabricSodiumCompat.USE_0_6_COMPAT;
}
@Override
public boolean useIrisCompat() {
return CompatMod.IRIS.isLoaded;
}
}

View file

@ -3,18 +3,14 @@ package dev.engine_room.flywheel.impl;
import org.jetbrains.annotations.UnknownNullability;
import dev.engine_room.flywheel.lib.internal.FlwLibXplat;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import dev.engine_room.flywheel.lib.model.baked.BakedModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.BlockModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.FabricBakedModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.FabricBlockModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.FabricMultiBlockModelBuilder;
import dev.engine_room.flywheel.lib.model.baked.ModelBuilderImpl;
import dev.engine_room.flywheel.lib.model.baked.MultiBlockModelBuilder;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
public class FlwLibXplatImpl implements FlwLibXplat {
@Override
@ -24,17 +20,17 @@ public class FlwLibXplatImpl implements FlwLibXplat {
}
@Override
public BakedModelBuilder createBakedModelBuilder(BakedModel bakedModel) {
return new FabricBakedModelBuilder(bakedModel);
public SimpleModel buildBakedModelBuilder(BakedModelBuilder builder) {
return ModelBuilderImpl.buildBakedModelBuilder(builder);
}
@Override
public BlockModelBuilder createBlockModelBuilder(BlockState state) {
return new FabricBlockModelBuilder(state);
public SimpleModel buildBlockModelBuilder(BlockModelBuilder builder) {
return ModelBuilderImpl.buildBlockModelBuilder(builder);
}
@Override
public MultiBlockModelBuilder createMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
return new FabricMultiBlockModelBuilder(level, positions);
public SimpleModel buildMultiBlockModelBuilder(MultiBlockModelBuilder builder) {
return ModelBuilderImpl.buildMultiBlockModelBuilder(builder);
}
}

View file

@ -1,48 +0,0 @@
package dev.engine_room.flywheel.impl.compat;
import java.util.Optional;
import dev.engine_room.flywheel.impl.FlwImpl;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.api.VersionParsingException;
import net.fabricmc.loader.api.metadata.version.VersionPredicate;
public final class FabricSodiumCompat {
public static final boolean USE_0_5_COMPAT;
public static final boolean USE_0_6_COMPAT;
static {
boolean use0_5Compat = false;
boolean use0_6Compat = false;
Optional<ModContainer> optionalModContainer = FabricLoader.getInstance().getModContainer(CompatMod.SODIUM.id);
if (optionalModContainer.isPresent()) {
ModContainer modContainer = optionalModContainer.get();
Version sodiumVersion = modContainer.getMetadata().getVersion();
try {
VersionPredicate predicate0_5 = VersionPredicate.parse("~0.5.0");
VersionPredicate predicate0_6 = VersionPredicate.parse(">=0.6.0-beta.2");
use0_5Compat = predicate0_5.test(sodiumVersion);
use0_6Compat = predicate0_6.test(sodiumVersion);
} catch (VersionParsingException e) {
FlwImpl.LOGGER.debug("Failed to parse Sodium version predicates", e);
}
}
USE_0_5_COMPAT = use0_5Compat;
USE_0_6_COMPAT = use0_6Compat;
}
static {
if (USE_0_5_COMPAT) {
FlwImpl.LOGGER.debug("Detected Sodium 0.5");
}
}
private FabricSodiumCompat() {
}
}

View file

@ -7,6 +7,7 @@ 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.Coerce;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@ -30,14 +31,14 @@ abstract class MinecraftMixin {
FabricFlwConfig.INSTANCE.load();
}
@Inject(method = "method_24040", at = @At("HEAD"))
private void flywheel$onEndInitialResourceReload(Optional<Throwable> error, CallbackInfo ci) {
@Inject(method = "method_53522", at = @At("HEAD"))
private void flywheel$onEndInitialResourceReload(@Coerce Object gameLoadCookie, Optional<Throwable> error, CallbackInfo ci) {
EndClientResourceReloadCallback.EVENT.invoker()
.onEndClientResourceReload((Minecraft) (Object) this, resourceManager, true, error);
}
@Inject(method = "method_24228", at = @At("HEAD"))
private void flywheel$onEndManualResourceReload(boolean recovery, CompletableFuture<Void> future,
private void flywheel$onEndManualResourceReload(boolean recovery, @Coerce Object gameLoadCookie, CompletableFuture<Void> future,
Optional<Throwable> error, CallbackInfo ci) {
EndClientResourceReloadCallback.EVENT.invoker()
.onEndClientResourceReload((Minecraft) (Object) this, resourceManager, false, error);

View file

@ -15,15 +15,15 @@ abstract class MinecraftMixin {
@Shadow
public ClientLevel level;
@Inject(method = "setLevel(Lnet/minecraft/client/multiplayer/ClientLevel;)V", at = @At("HEAD"))
@Inject(method = "setLevel(Lnet/minecraft/client/multiplayer/ClientLevel;Lnet/minecraft/client/gui/screens/ReceivingLevelScreen$Reason;)V", at = @At("HEAD"))
private void flywheel$onSetLevel(CallbackInfo ci) {
if (level != null) {
LevelAttached.invalidateLevel(level);
}
}
@Inject(method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At("HEAD"))
private void flywheel$onClearLevel(CallbackInfo ci) {
@Inject(method = "disconnect(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At("HEAD"))
private void flywheel$onDisconnect(CallbackInfo ci) {
if (level != null) {
LevelAttached.invalidateLevel(level);
}

View file

@ -1,33 +0,0 @@
package dev.engine_room.flywheel.impl.mixin.sodium;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.world.level.block.entity.BlockEntity;
@Mixin(value = ChunkBuilderMeshingTask.class, remap = false)
abstract class ChunkBuilderMeshingTaskMixin {
@WrapOperation(
method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderDispatcher;getRenderer(Lnet/minecraft/world/level/block/entity/BlockEntity;)Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderer;",
remap = true
)
)
@Nullable
private BlockEntityRenderer<?> flywheel$wrapGetRenderer(BlockEntityRenderDispatcher instance, BlockEntity blockEntity, Operation<BlockEntityRenderer<BlockEntity>> original) {
if (VisualizationHelper.tryAddBlockEntity(blockEntity)) {
return null;
}
return original.call(instance, blockEntity);
}
}

View file

@ -1,46 +0,0 @@
package dev.engine_room.flywheel.impl.mixin.sodium;
import java.util.List;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import dev.engine_room.flywheel.impl.compat.FabricSodiumCompat;
public class SodiumMixinPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
}
@Override
@Nullable
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return FabricSodiumCompat.USE_0_5_COMPAT;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
@Nullable
public List<String> getMixins() {
return null;
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
}

View file

@ -1,9 +1,9 @@
{
"schemaVersion": 1,
"id": "${mod_id}",
"version": "${mod_version}",
"name": "${mod_name}",
"description": "${mod_description}",
"id" : "${flywheel_id}",
"version" : "${flywheel_version}",
"name" : "${flywheel_name}",
"description" : "${flywheel_description}",
"authors": [
"Jozufozu",
"PepperCode1"
@ -24,8 +24,7 @@
"mixins": [
"flywheel.backend.mixins.json",
"flywheel.impl.mixins.json",
"flywheel.impl.fabric.mixins.json",
"flywheel.impl.sodium.mixins.json"
"flywheel.impl.fabric.mixins.json"
],
"depends": {
"minecraft": "${minecraft_semver_version_range}",
@ -33,7 +32,6 @@
"fabric-api": "${fabric_api_version_range}"
},
"breaks": {
"sodium": ["<0.5.0", "~0.6.0- <0.6.0-beta.2"],
"embeddium": "*"
"sodium": "<0.6.0-beta.2"
}
}

View file

@ -2,7 +2,7 @@
"required": true,
"minVersion": "0.8",
"package": "dev.engine_room.flywheel.impl.mixin.fabric",
"compatibilityLevel": "JAVA_17",
"compatibilityLevel": "JAVA_21",
"refmap": "flywheel.refmap.json",
"client": [
"DebugScreenOverlayMixin",

View file

@ -1,14 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.engine_room.flywheel.impl.mixin.sodium",
"compatibilityLevel": "JAVA_17",
"refmap": "flywheel.refmap.json",
"plugin": "dev.engine_room.flywheel.impl.mixin.sodium.SodiumMixinPlugin",
"client": [
"ChunkBuilderMeshingTaskMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"id" : "${mod_id}_testmod",
"name": "${mod_name} Test Mod",
"id" : "${flywheel_id}_testmod",
"name" : "${flywheel_name} Test Mod",
"version": "1.0.0",
"environment": "*",
"license": "${mod_license}",

View file

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

View file

@ -1,78 +0,0 @@
package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
public final class ForgeBakedModelBuilder extends BakedModelBuilder {
@Nullable
private ModelData modelData;
public ForgeBakedModelBuilder(BakedModel bakedModel) {
super(bakedModel);
}
@Override
public ForgeBakedModelBuilder level(BlockAndTintGetter level) {
super.level(level);
return this;
}
@Override
public ForgeBakedModelBuilder blockState(BlockState blockState) {
super.blockState(blockState);
return this;
}
@Override
public ForgeBakedModelBuilder poseStack(PoseStack poseStack) {
super.poseStack(poseStack);
return this;
}
@Override
public ForgeBakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
super.materialFunc(materialFunc);
return this;
}
public ForgeBakedModelBuilder modelData(ModelData modelData) {
this.modelData = modelData;
return this;
}
@Override
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
if (modelData == null) {
modelData = ModelData.EMPTY;
}
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferSingle(level, bakedModel, blockState, poseStack, modelData, (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder.build());
}
}

View file

@ -1,71 +0,0 @@
package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
public final class ForgeBlockModelBuilder extends BlockModelBuilder {
@Nullable
private ModelData modelData;
public ForgeBlockModelBuilder(BlockState state) {
super(state);
}
@Override
public ForgeBlockModelBuilder level(BlockAndTintGetter level) {
super.level(level);
return this;
}
@Override
public ForgeBlockModelBuilder poseStack(PoseStack poseStack) {
super.poseStack(poseStack);
return this;
}
@Override
public ForgeBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
super.materialFunc(materialFunc);
return this;
}
public ForgeBlockModelBuilder modelData(ModelData modelData) {
this.modelData = modelData;
return this;
}
@Override
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
if (modelData == null) {
modelData = ModelData.EMPTY;
}
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferBlock(level, state, poseStack, modelData, (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder.build());
}
}

View file

@ -1,72 +0,0 @@
package dev.engine_room.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.lib.model.ModelUtil;
import dev.engine_room.flywheel.lib.model.SimpleModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraftforge.client.model.data.ModelData;
public final class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder {
@Nullable
private Function<BlockPos, ModelData> modelDataLookup;
public ForgeMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
super(level, positions);
}
@Override
public ForgeMultiBlockModelBuilder poseStack(PoseStack poseStack) {
super.poseStack(poseStack);
return this;
}
@Override
public ForgeMultiBlockModelBuilder enableFluidRendering() {
super.enableFluidRendering();
return this;
}
@Override
public ForgeMultiBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
super.materialFunc(materialFunc);
return this;
}
public ForgeMultiBlockModelBuilder modelDataLookup(Function<BlockPos, ModelData> modelDataLookup) {
this.modelDataLookup = modelDataLookup;
return this;
}
@Override
public SimpleModel build() {
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
if (modelDataLookup == null) {
modelDataLookup = pos -> ModelData.EMPTY;
}
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();
BakedModelBufferer.bufferMultiBlock(positions.iterator(), level, poseStack, modelDataLookup, renderFluids, (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
Mesh mesh = MeshHelper.blockVerticesToMesh(data, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});
return new SimpleModel(builder.build());
}
}

View file

@ -1,39 +0,0 @@
package dev.engine_room.flywheel.impl;
import dev.engine_room.flywheel.api.event.ReloadLevelRendererEvent;
import dev.engine_room.flywheel.impl.compat.CompatMod;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.loading.LoadingModList;
public class FlwImplXplatImpl implements FlwImplXplat {
@Override
public boolean isModLoaded(String modId) {
return LoadingModList.get().getModFileById(modId) != null;
}
@Override
public void dispatchReloadLevelRendererEvent(ClientLevel level) {
MinecraftForge.EVENT_BUS.post(new ReloadLevelRendererEvent(level));
}
@Override
public String getVersionStr() {
return FlywheelForge.version().toString();
}
@Override
public FlwConfig getConfig() {
return ForgeFlwConfig.INSTANCE;
}
@Override
public boolean useSodium0_6Compat() {
return CompatMod.SODIUM.isLoaded && !CompatMod.EMBEDDIUM.isLoaded;
}
@Override
public boolean useIrisCompat() {
return CompatMod.IRIS.isLoaded || CompatMod.OCULUS.isLoaded;
}
}

View file

@ -1,132 +0,0 @@
package dev.engine_room.flywheel.impl;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.jetbrains.annotations.UnknownNullability;
import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.event.EndClientResourceReloadEvent;
import dev.engine_room.flywheel.api.event.ReloadLevelRendererEvent;
import dev.engine_room.flywheel.backend.compile.FlwProgramsReloader;
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
import dev.engine_room.flywheel.impl.compat.EmbeddiumCompat;
import dev.engine_room.flywheel.impl.visualization.VisualizationEventHandler;
import dev.engine_room.flywheel.lib.model.baked.PartialModelEventHandler;
import dev.engine_room.flywheel.lib.util.LevelAttached;
import dev.engine_room.flywheel.lib.util.RendererReloadCache;
import dev.engine_room.flywheel.lib.util.ResourceReloadHolder;
import net.minecraft.client.Minecraft;
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.event.entity.EntityLeaveLevelEvent;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.CrashReportCallables;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegisterEvent;
@Mod(Flywheel.ID)
public final class FlywheelForge {
@UnknownNullability
private static ArtifactVersion version;
public FlywheelForge() {
ModLoadingContext modLoadingContext = ModLoadingContext.get();
version = modLoadingContext
.getActiveContainer()
.getModInfo()
.getVersion();
IEventBus forgeEventBus = MinecraftForge.EVENT_BUS;
IEventBus modEventBus = FMLJavaModLoadingContext.get()
.getModEventBus();
ForgeFlwConfig.INSTANCE.registerSpecs(modLoadingContext);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FlywheelForge.clientInit(forgeEventBus, modEventBus));
}
private static void clientInit(IEventBus forgeEventBus, IEventBus modEventBus) {
registerImplEventListeners(forgeEventBus, modEventBus);
registerLibEventListeners(forgeEventBus, modEventBus);
registerBackendEventListeners(forgeEventBus, modEventBus);
CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString);
FlwImpl.init();
EmbeddiumCompat.init();
}
private static void registerImplEventListeners(IEventBus forgeEventBus, IEventBus modEventBus) {
forgeEventBus.addListener((ReloadLevelRendererEvent e) -> BackendManagerImpl.onReloadLevelRenderer(e.level()));
forgeEventBus.addListener((TickEvent.LevelTickEvent e) -> {
// Make sure we don't tick on the server somehow.
if (e.phase == TickEvent.Phase.END && e.side == LogicalSide.CLIENT) {
VisualizationEventHandler.onClientTick(Minecraft.getInstance(), e.level);
}
});
forgeEventBus.addListener((EntityJoinLevelEvent e) -> VisualizationEventHandler.onEntityJoinLevel(e.getLevel(), e.getEntity()));
forgeEventBus.addListener((EntityLeaveLevelEvent e) -> VisualizationEventHandler.onEntityLeaveLevel(e.getLevel(), e.getEntity()));
forgeEventBus.addListener(FlwCommands::registerClientCommands);
forgeEventBus.addListener((CustomizeGuiOverlayEvent.DebugText e) -> {
Minecraft minecraft = Minecraft.getInstance();
if (!minecraft.options.renderDebug) {
return;
}
FlwDebugInfo.addDebugInfo(minecraft, e.getRight());
});
modEventBus.addListener((EndClientResourceReloadEvent e) -> BackendManagerImpl.onEndClientResourceReload(e.error().isPresent()));
modEventBus.addListener((FMLCommonSetupEvent e) -> {
ArgumentTypeInfos.registerByClass(BackendArgument.class, BackendArgument.INFO);
ArgumentTypeInfos.registerByClass(DebugModeArgument.class, DebugModeArgument.INFO);
ArgumentTypeInfos.registerByClass(LightSmoothnessArgument.class, LightSmoothnessArgument.INFO);
});
modEventBus.addListener((RegisterEvent e) -> {
if (e.getRegistryKey().equals(ForgeRegistries.Keys.COMMAND_ARGUMENT_TYPES)) {
e.register(ForgeRegistries.Keys.COMMAND_ARGUMENT_TYPES, Flywheel.rl("backend"), () -> BackendArgument.INFO);
e.register(ForgeRegistries.Keys.COMMAND_ARGUMENT_TYPES, Flywheel.rl("debug_mode"), () -> DebugModeArgument.INFO);
e.register(ForgeRegistries.Keys.COMMAND_ARGUMENT_TYPES, Flywheel.rl("light_smoothness"), () -> LightSmoothnessArgument.INFO);
}
});
}
private static void registerLibEventListeners(IEventBus forgeEventBus, IEventBus modEventBus) {
forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.invalidateLevel(e.getLevel()));
modEventBus.addListener((EndClientResourceReloadEvent e) -> RendererReloadCache.onReloadLevelRenderer());
modEventBus.addListener((EndClientResourceReloadEvent e) -> ResourceReloadHolder.onEndClientResourceReload());
modEventBus.addListener(PartialModelEventHandler::onRegisterAdditional);
modEventBus.addListener(PartialModelEventHandler::onBakingCompleted);
}
private static void registerBackendEventListeners(IEventBus forgeEventBus, IEventBus modEventBus) {
forgeEventBus.addListener((ReloadLevelRendererEvent e) -> Uniforms.onReloadLevelRenderer());
modEventBus.addListener((RegisterClientReloadListenersEvent e) -> {
e.registerReloadListener(FlwProgramsReloader.INSTANCE);
});
}
public static ArtifactVersion version() {
return version;
}
}

View file

@ -1,47 +0,0 @@
package dev.engine_room.flywheel.impl.mixin;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
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.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.realmsclient.client.RealmsClient;
import dev.engine_room.flywheel.api.event.EndClientResourceReloadEvent;
import dev.engine_room.flywheel.impl.FlwImpl;
import net.minecraft.client.Minecraft;
import net.minecraft.client.main.GameConfig;
import net.minecraft.server.packs.resources.ReloadInstance;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraftforge.fml.ModLoader;
@Mixin(Minecraft.class)
abstract class MinecraftMixin {
@Shadow
@Final
private ReloadableResourceManager resourceManager;
// Inject at invoke cannot be used in constructors in vanilla Mixin, so use ModifyArg instead.
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;createReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/server/packs/resources/ReloadInstance;"), index = 0)
private Executor flywheel$onBeginInitialResourceReload(Executor arg0) {
FlwImpl.freezeRegistries();
return arg0;
}
@Inject(method = "lambda$new$5", at = @At("HEAD"))
private void flywheel$onEndInitialResourceReload(RealmsClient realmsClient, ReloadInstance reloadInstance, GameConfig gameConfig, Optional<Throwable> error, CallbackInfo ci) {
ModLoader.get().postEvent(new EndClientResourceReloadEvent((Minecraft) (Object) this, resourceManager, true, error));
}
@Inject(method = "lambda$reloadResourcePacks$28", at = @At("HEAD"))
private void flywheel$onEndManualResourceReload(boolean recovery, CompletableFuture<Void> future, Optional<Throwable> error, CallbackInfo ci) {
ModLoader.get().postEvent(new EndClientResourceReloadEvent((Minecraft) (Object) this, resourceManager, false, error));
}
}

View file

@ -1,39 +0,0 @@
modLoader = "javafml"
# The loader version doesn't matter. Modify the Forge and/or Minecraft version ranges instead.
loaderVersion = "[0,)"
license = "${mod_license}"
issueTrackerURL = "${mod_issues}"
[[mods]]
modId = "${mod_id}"
version = "${mod_version}"
displayName = "${mod_name}"
description = "${mod_description}"
logoFile = "logo.png"
authors = "Jozufozu, PepperCode1"
displayURL = "${mod_homepage}"
displayTest = "IGNORE_ALL_VERSION"
[[dependencies.${mod_id}]]
modId = "minecraft"
mandatory = true
versionRange = "${minecraft_maven_version_range}"
side = "CLIENT"
[[dependencies.${mod_id}]]
modId = "forge"
mandatory = true
versionRange = "${forge_version_range}"
side = "CLIENT"
[[dependencies.${mod_id}]]
modId = "embeddium"
mandatory = false
versionRange = "[0.3.25,)"
side = "CLIENT"
[[dependencies.${mod_id}]]
modId = "sodium"
mandatory = false
versionRange = "[0.6.0-beta.2,)"
side = "CLIENT"

View file

@ -1,6 +0,0 @@
{
"pack": {
"description": "${mod_name} resources",
"pack_format": 15
}
}

View file

@ -1,39 +1,50 @@
org.gradle.jvmargs = -Xmx3G
org.gradle.daemon = false
# Mod metadata
mod_id = flywheel
mod_name = Flywheel
mod_version = 1.0.0-beta
mod_description = An overhauled entity and block entity rendering API.
# Common metadata
mod_license = MIT
mod_sources = https://github.com/Engine-Room/Flywheel
mod_issues = https://github.com/Engine-Room/Flywheel/issues
mod_homepage = https://github.com/Engine-Room/Flywheel
# Flywheel metadata
flywheel_id=flywheel
flywheel_name=Flywheel
flywheel_version=1.0.0-beta
flywheel_description=An overhauled entity and block entity rendering API.
# Vanillin metadata
vanillin_id=vanillin
vanillin_name=Vanillin
vanillin_version=1.0.0-beta
vanillin_description=Instanced rendering for entities and block entities via Flywheel.
# Vanillin dependencies
flywheel_maven_version_range=[1.0.0-beta,2.0)
flywheel_semver_version_range=>=1.0.0-beta <2.0.0
# Mod dependency declarations
minecraft_semver_version_range = >=1.20.1 <1.20.2
minecraft_maven_version_range = [1.20.1,1.20.2)
fabric_api_version_range = >=0.86.0
forge_version_range = [47.0.0,)
minecraft_semver_version_range = >=1.21.1 <1.21.2
minecraft_maven_version_range = [1.21.1,1.21.2)
fabric_api_version_range = >=0.105.0
neoforge_version_range = [21.1.66,)
# General build dependency versions
java_version = 17
java_version = 21
arch_loom_version = 1.7.412
cursegradle_version = 1.4.0
parchment_minecraft_version = 1.20.1
parchment_version = 2023.09.03
parchment_minecraft_version = 1.21
parchment_version = 2024.07.07
# Minecraft build dependency versions
minecraft_version = 1.20.1
forge_version = 47.2.19
fabric_loader_version = 0.15.9
fabric_api_version = 0.92.1+1.20.1
minecraft_version = 1.21.1
neoforge_version = 21.1.66
fabric_loader_version = 0.16.5
fabric_api_version = 0.105.0+1.21.1
# Build dependency mod versions
sodium_version = mc1.20.1-0.5.11
embeddium_version = 0.3.25+mc1.20.1
sodium_version = mc1.21.1-0.6.5
iris_version = 1.8.0-beta.8+1.21.1
# There is no oculus for 1.21.1 so we will only support iris
embeddium_version = 1.0.11+mc1.21.1
# Publication info
group = dev.engine_room.flywheel
artifact_minecraft_version = 1.20.1
flywheel_group=dev.engine_room.flywheel
vanillin_group=dev.engine_room.vanillin
artifact_minecraft_version = 1.21.1

View file

@ -7,6 +7,11 @@ plugins {
id("flywheel.platform")
}
val common = ":common"
val commonProject = project(common)
subproject.init("flywheel-neoforge", "flywheel_group", "flywheel_version")
val api = sourceSets.create("api")
val lib = sourceSets.create("lib")
val backend = sourceSets.create("backend")
@ -19,20 +24,32 @@ transitiveSourceSets {
sourceSet(api) {
rootCompile()
from(commonProject)
}
sourceSet(lib) {
rootCompile()
compile(api)
compileClasspath(api)
from(commonProject)
}
sourceSet(backend) {
rootCompile()
compile(api, lib)
compileClasspath(api, lib)
from(commonProject)
}
sourceSet(stubs) {
rootCompile()
from(commonProject)
}
sourceSet(main) {
compile(api, lib, backend, stubs)
compileClasspath(api, lib, backend)
bundleFrom(commonProject)
bundleOutput(api, lib, backend)
}
sourceSet(testMod) {
rootCompile()
@ -42,19 +59,18 @@ transitiveSourceSets {
}
platform {
commonProject = project(":common")
compileWithCommonSourceSets(api, lib, backend, stubs, main)
setupLoomMod(api, lib, backend, main)
setupLoomRuns()
setupFatJar(api, lib, backend, main)
setupTestMod(testMod)
}
jarSets {
mainSet.publish(platform.modArtifactId)
mainSet.publish("flywheel-neoforge-${project.property("artifact_minecraft_version")}")
mainSet.outgoing("flywheel")
create("api", api, lib).apply {
addToAssemble()
publish(platform.apiArtifactId)
publish("flywheel-neoforge-api-${project.property("artifact_minecraft_version")}")
configureJar {
manifest {
@ -75,11 +91,6 @@ loom {
add(backend, "backend-flywheel.refmap.json")
}
forge {
mixinConfig("flywheel.backend.mixins.json")
mixinConfig("flywheel.impl.mixins.json")
}
runs {
configureEach {
property("forge.logging.markers", "")
@ -88,14 +99,25 @@ loom {
}
}
repositories {
maven("https://maven.neoforged.net/releases/")
}
dependencies {
forge("net.minecraftforge:forge:${property("minecraft_version")}-${property("forge_version")}")
neoForge("net.neoforged:neoforge:${property("neoforge_version")}")
modCompileOnly("maven.modrinth:sodium:${property("sodium_version")}-neoforge")
modCompileOnly("maven.modrinth:iris:${property("iris_version")}-neoforge")
modCompileOnly("maven.modrinth:embeddium:${property("embeddium_version")}")
"forApi"(project(path = ":common", configuration = "commonApiOnly"))
"forLib"(project(path = ":common", configuration = "commonLib"))
"forBackend"(project(path = ":common", configuration = "commonBackend"))
"forStubs"(project(path = ":common", configuration = "commonStubs"))
"forMain"(project(path = ":common", configuration = "commonImpl"))
"forApi"(project(path = common, configuration = "apiClasses"))
"forLib"(project(path = common, configuration = "libClasses"))
"forBackend"(project(path = common, configuration = "backendClasses"))
"forStubs"(project(path = common, configuration = "stubsClasses"))
"forMain"(project(path = common, configuration = "mainClasses"))
"forLib"(project(path = common, configuration = "libResources"))
"forBackend"(project(path = common, configuration = "backendResources"))
"forMain"(project(path = common, configuration = "mainResources"))
}

View file

@ -0,0 +1 @@
loom.platform = neoforge

View file

@ -4,8 +4,8 @@ import java.util.Optional;
import net.minecraft.client.Minecraft;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.neoforged.bus.api.Event;
import net.neoforged.fml.event.IModBusEvent;
/**
* This event is posted to mod event buses.

View file

@ -1,10 +1,10 @@
package dev.engine_room.flywheel.api.event;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraftforge.eventbus.api.Event;
import net.neoforged.bus.api.Event;
/**
* This event is posted to the Forge event bus.
* This event is posted to the NeoForge event bus.
*/
public final class ReloadLevelRendererEvent extends Event {
private final ClientLevel level;

Some files were not shown because too many files have changed in this diff Show more