diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ff1e1bb..a212724 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: Artifacts - path: build/libs/ + path: versions/*/build/libs/ client-game-test: name: Client Game Test @@ -66,10 +66,10 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Run client game tests - run: ./gradlew runProductionClientGameTest + run: ./gradlew :1.21.8:runProductionClientGameTest - name: Upload screenshots if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: Client Game Test Screenshots - path: build/run/clientGameTest/screenshots/ + path: versions/*/build/run/clientGameTest/screenshots/ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4dccd24..2d5a51b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -87,14 +87,30 @@ jobs: run: ./gradlew build env: MOD_VERSION: ${{ steps.version.outputs.mod_version }} - - name: Publish + - name: Publish to Modrinth and CurseForge run: ./gradlew publishMods env: MOD_VERSION: ${{ steps.version.outputs.mod_version }} - TAG_NAME: ${{ github.ref_name }} CHANGELOG: ${{ steps.tag_message.outputs.message }} MODRINTH_ID: ${{ secrets.MODRINTH_ID }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} CURSEFORGE_ID: ${{ secrets.CURSEFORGE_ID }} CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG_NAME: ${{ github.ref_name }} + RELEASE_NOTES: ${{ steps.tag_message.outputs.message }} + MOD_VERSION: ${{ steps.version.outputs.mod_version }} + run: | + shopt -s nullglob + assets=(versions/*/build/libs/connectedtank-"${MOD_VERSION}"+mc*.jar) + if [ ${#assets[@]} -eq 0 ]; then + echo "::error::No release assets found matching pattern" + exit 1 + fi + echo "Found ${#assets[@]} release asset(s): ${assets[*]}" + gh release create "$TAG_NAME" \ + --title "$TAG_NAME" \ + --notes "$RELEASE_NOTES" \ + "${assets[@]}" diff --git a/.gitignore b/.gitignore index 4b6e749..e3913ab 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,7 @@ hs_err_*.log replay_*.log *.hprof *.jfr + +# git-hooks.nix + +.pre-commit-config.yaml diff --git a/README.ja.md b/README.ja.md index 546a6f7..a3a06ff 100644 --- a/README.ja.md +++ b/README.ja.md @@ -46,7 +46,7 @@ ## 動作要件 -- Minecraft 1.21.8 +- Minecraft 1.21.8 / 1.21.11 - Fabric Loader >= 0.17.2 - Fabric API - Fabric Language Kotlin @@ -84,7 +84,7 @@ ./gradlew build ``` -ビルド成果物は `build/libs/` に出力されます。 +ビルド成果物は `versions/*/build/libs/` に出力されます。 ## ライセンス diff --git a/README.md b/README.md index 396b45d..0985204 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Base capacity is 32 buckets by default (configurable). Each tank's capacity = ba ## Requirements -- Minecraft 1.21.8 +- Minecraft 1.21.8 / 1.21.11 - Fabric Loader >= 0.17.2 - Fabric API - Fabric Language Kotlin @@ -86,7 +86,7 @@ Base capacity is 32 buckets by default (configurable). Each tank's capacity = ba ./gradlew build ``` -The built jar will be in `build/libs/`. +The built jars will be in `versions/*/build/libs/`. ## License diff --git a/build.gradle.kts b/build.gradle.kts index 9a7fa15..77dc72d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,14 +2,16 @@ import java.util.concurrent.TimeUnit import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { + id("dev.kikugie.stonecutter") alias(libs.plugins.fabric.loom) id("maven-publish") alias(libs.plugins.kotlin.jvm) - alias(libs.plugins.spotless) alias(libs.plugins.mod.publish.plugin) } -version = providers.environmentVariable("MOD_VERSION").orElse("dev").get() +val mcVersion = stonecutter.current.version + +version = providers.environmentVariable("MOD_VERSION").orElse("dev").get() + "+mc$mcVersion" group = project.property("maven_group") as String base { @@ -109,34 +111,64 @@ loom { } dependencies { - // To change the versions see the gradle/libs.versions.toml file - minecraft(libs.minecraft) - mappings(variantOf(libs.yarn.mappings) { classifier("v2") }) + val yarnMappings = when (mcVersion) { + "1.21.8" -> "1.21.8+build.1" + "1.21.11" -> "1.21.11+build.5" + else -> error("Unsupported MC version: $mcVersion") + } + val fabricApiVersion = when (mcVersion) { + "1.21.8" -> "0.132.0+1.21.8" + "1.21.11" -> "0.141.3+1.21.11" + else -> error("Unsupported MC version: $mcVersion") + } + val yaclVersion = when (mcVersion) { + "1.21.8" -> "3.7.1+1.21.6-fabric" + "1.21.11" -> "3.8.2+1.21.11-fabric" + else -> error("Unsupported MC version: $mcVersion") + } + val modmenuVersion = when (mcVersion) { + "1.21.8" -> "15.0.1" + "1.21.11" -> "17.0.0" + else -> error("Unsupported MC version: $mcVersion") + } + val reiVersion = when (mcVersion) { + "1.21.8" -> "20.0.811" + "1.21.11" -> "21.11.814" + else -> error("Unsupported MC version: $mcVersion") + } + val jadeVersion = when (mcVersion) { + "1.21.8" -> "19.3.2+fabric" + "1.21.11" -> "21.1.6+fabric" + else -> error("Unsupported MC version: $mcVersion") + } + + minecraft("com.mojang:minecraft:$mcVersion") + mappings("net.fabricmc:yarn:$yarnMappings:v2") modImplementation(libs.fabric.loader) - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation(libs.fabric.api) + modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") modImplementation(libs.fabric.language.kotlin) - "productionRuntimeMods"(libs.fabric.api) + "productionRuntimeMods"("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") "productionRuntimeMods"(libs.fabric.language.kotlin) - modCompileOnly(libs.yacl) - modRuntimeOnly(libs.yacl) - modCompileOnly(libs.modmenu) - modRuntimeOnly(libs.modmenu) + modCompileOnly("dev.isxander:yet-another-config-lib:$yaclVersion") + modRuntimeOnly("dev.isxander:yet-another-config-lib:$yaclVersion") + modCompileOnly("com.terraformersmc:modmenu:$modmenuVersion") + modRuntimeOnly("com.terraformersmc:modmenu:$modmenuVersion") - modRuntimeOnly(libs.rei) - modCompileOnly(libs.jade) - modRuntimeOnly(libs.jade) + modRuntimeOnly("me.shedaniel:RoughlyEnoughItems-fabric:$reiVersion") + modCompileOnly("maven.modrinth:jade:$jadeVersion") + modRuntimeOnly("maven.modrinth:jade:$jadeVersion") } tasks { processResources { inputs.property("version", project.version) + inputs.property("minecraft_version", mcVersion) filesMatching("fabric.mod.json") { - expand("version" to inputs.properties["version"]) + expand(mapOf("version" to inputs.properties["version"], "minecraft_version" to inputs.properties["minecraft_version"])) } } jar { @@ -149,10 +181,6 @@ tasks { withType().configureEach { options.release.set(21) } - @Suppress("UnstableApiUsage") - named("updateDaemonJvm") { - languageVersion = JavaLanguageVersion.of(21) - } val clientGametestJar = register("clientGametestJar") { from(clientGametestSourceSet.output) archiveClassifier.set("client-gametest") @@ -193,18 +221,6 @@ java { targetCompatibility = JavaVersion.VERSION_21 } -spotless { - kotlin { - ktlint() - } - kotlinGradle { - ktlint() - } - java { - palantirJavaFormat() - } -} - publishMods { file.set(tasks.remapJar.flatMap { it.archiveFile }) additionalFiles.from(tasks.remapSourcesJar.flatMap { it.archiveFile }) @@ -215,23 +231,17 @@ publishMods { modrinth { projectId.set(providers.environmentVariable("MODRINTH_ID")) accessToken.set(providers.environmentVariable("MODRINTH_TOKEN")) - minecraftVersions.add(libs.versions.minecraft) + minecraftVersions.add(mcVersion) requires("fabric-api") requires("fabric-language-kotlin") } curseforge { projectId.set(providers.environmentVariable("CURSEFORGE_ID")) accessToken.set(providers.environmentVariable("CURSEFORGE_TOKEN")) - minecraftVersions.add(libs.versions.minecraft) + minecraftVersions.add(mcVersion) requires("fabric-api") requires("fabric-language-kotlin") } - github { - repository.set("turtton/ConnectedTank") - accessToken.set(providers.environmentVariable("GITHUB_TOKEN")) - commitish.set("main") - tagName.set(providers.environmentVariable("TAG_NAME").orElse("v${project.version}")) - } } // configure the maven publication diff --git a/flake.lock b/flake.lock index d17d456..a8a04d0 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,21 @@ { "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": [ @@ -20,6 +36,49 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776796298, + "narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "3cfd774b0a530725a077e17354fbdb87ea1c4aad", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1775126147, @@ -39,6 +98,7 @@ "root": { "inputs": { "flake-utils": "flake-utils", + "git-hooks": "git-hooks", "nixpkgs": "nixpkgs", "systems": "systems" } diff --git a/flake.nix b/flake.nix index 8d3c27c..ee5687a 100644 --- a/flake.nix +++ b/flake.nix @@ -6,9 +6,19 @@ url = "github:numtide/flake-utils"; inputs.systems.follows = "systems"; }; + inputs.git-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; outputs = - { nixpkgs, flake-utils, ... }: + { + self, + nixpkgs, + flake-utils, + git-hooks, + ... + }: flake-utils.lib.eachDefaultSystem ( system: let @@ -30,19 +40,37 @@ in { formatter = pkgs.nixfmt-tree; + + checks = { + pre-commit-check = git-hooks.lib.${system}.run { + src = ./.; + hooks = { + stonecutter-version = { + enable = true; + name = "Stonecutter vcsVersion guard"; + entry = "${pkgs.bash}/bin/bash -c 'if ! grep -q '\"'\"'stonecutter active \"1.21.8\"'\"'\"' stonecutter.gradle.kts; then ${pkgs.gnused}/bin/sed -i '\"'\"'s/stonecutter active \".*\"/stonecutter active \"1.21.8\"/'\"'\"' stonecutter.gradle.kts; echo \"Fixed: stonecutter active version reset to 1.21.8 (vcsVersion). Please re-commit.\"; exit 1; fi'"; + files = "stonecutter\\.gradle\\.kts$"; + language = "system"; + pass_filenames = false; + }; + }; + }; + }; + devShells.default = pkgs.mkShell { - packages = with pkgs; [ - bashInteractive - xrandr - xorg-server # Provides Xvfb for headless client tests - pinact - zizmor - ]; - shellHook = '' - export LD_LIBRARY_PATH=''${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}${libraries} - ''; + inherit (self.checks.${system}.pre-commit-check) shellHook; + packages = + with pkgs; + [ + bashInteractive + xrandr + xorg-server + pinact + zizmor + ] + ++ self.checks.${system}.pre-commit-check.enabledPackages; + env.LD_LIBRARY_PATH = libraries; }; } ); } - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 63aafc8..4f73810 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,33 +1,17 @@ [versions] -minecraft = "1.21.8" -yarn-mappings = "1.21.8+build.1" loader = "0.17.2" -loom = "1.11-SNAPSHOT" +loom = "1.16-SNAPSHOT" fabric-kotlin = "1.13.5+kotlin.2.2.10" -fabric-api = "0.132.0+1.21.8" kotlin = "2.2.10" spotless = "7.2.1" mod-publish-plugin = "0.8.4" -rei = "20.0.811" -jade = "19.3.2+fabric" -yacl = "3.7.1+1.21.6-fabric" -modmenu = "15.0.1" - [libraries] -minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } -yarn-mappings = { module = "net.fabricmc:yarn", version.ref = "yarn-mappings" } fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "loader" } -fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" } fabric-language-kotlin = { module = "net.fabricmc:fabric-language-kotlin", version.ref = "fabric-kotlin" } -rei = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" } -jade = { module = "maven.modrinth:jade", version.ref = "jade" } -yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" } -modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } - [plugins] fabric-loom = { id = "fabric-loom", version.ref = "loom" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } -mod-publish-plugin = { id = "me.modmuss50.mod-publish-plugin", version.ref = "mod-publish-plugin" } \ No newline at end of file +mod-publish-plugin = { id = "me.modmuss50.mod-publish-plugin", version.ref = "mod-publish-plugin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68..1a70468 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index 9c3e9cf..f093fd5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,10 +4,19 @@ pluginManagement { name = "Fabric" setUrl("https://maven.fabricmc.net/") } + maven("https://maven.kikugie.dev/releases") { name = "KikuGie" } mavenCentral() gradlePluginPortal() } } plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" + id("dev.kikugie.stonecutter") version "0.9.3" +} + +stonecutter { + create(rootProject) { + versions("1.21.8", "1.21.11") + vcsVersion = "1.21.8" + } } diff --git a/src/client/kotlin/net/turtton/connectedtank/ConnectedTankClient.kt b/src/client/kotlin/net/turtton/connectedtank/ConnectedTankClient.kt index 5f6db41..b2a929a 100644 --- a/src/client/kotlin/net/turtton/connectedtank/ConnectedTankClient.kt +++ b/src/client/kotlin/net/turtton/connectedtank/ConnectedTankClient.kt @@ -9,6 +9,8 @@ import net.minecraft.client.render.block.entity.BlockEntityRendererFactories import net.turtton.connectedtank.block.CTBlockEntityTypes import net.turtton.connectedtank.block.CTBlocks import net.turtton.connectedtank.block.ConnectedTankBlockEntityRenderer +//? if >=1.21.11 +/*import net.turtton.connectedtank.block.ConnectedTankRenderState*/ import net.turtton.connectedtank.config.CTClientConfig import net.turtton.connectedtank.config.CTServerConfig import net.turtton.connectedtank.config.SyncedServerConfig @@ -20,7 +22,15 @@ object ConnectedTankClient : ClientModInitializer { CTClientConfig.load() CTBlocks.ALL_TANKS.forEach { BlockRenderLayerMap.putBlock(it, BlockRenderLayer.CUTOUT) } - BlockEntityRendererFactories.register(CTBlockEntityTypes.CONNECTED_TANK, ::ConnectedTankBlockEntityRenderer) + //? if >=1.21.11 { + /*BlockEntityRendererFactories.register<_, ConnectedTankRenderState>( + CTBlockEntityTypes.CONNECTED_TANK, + ) { context -> ConnectedTankBlockEntityRenderer(context) }*/ + //?} else { + BlockEntityRendererFactories.register( + CTBlockEntityTypes.CONNECTED_TANK, + ) { context -> ConnectedTankBlockEntityRenderer(context) } + //?} ConnectedTankItemRenderer.register() ClientPlayNetworking.registerGlobalReceiver(ConfigSyncPayload.ID) { payload, _ -> diff --git a/src/client/kotlin/net/turtton/connectedtank/block/ConnectedTankBlockEntityRenderer.kt b/src/client/kotlin/net/turtton/connectedtank/block/ConnectedTankBlockEntityRenderer.kt index 13c18aa..5b0ead7 100644 --- a/src/client/kotlin/net/turtton/connectedtank/block/ConnectedTankBlockEntityRenderer.kt +++ b/src/client/kotlin/net/turtton/connectedtank/block/ConnectedTankBlockEntityRenderer.kt @@ -2,6 +2,137 @@ package net.turtton.connectedtank.block import kotlin.math.max import net.fabricmc.fabric.api.transfer.v1.client.fluid.FluidVariantRendering +//? if >=1.21.11 { +/*import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant +import net.minecraft.client.render.block.entity.BlockEntityRenderer +import net.minecraft.client.render.block.entity.BlockEntityRendererFactory +import net.minecraft.client.render.block.entity.state.BlockEntityRenderState +import net.minecraft.client.render.command.ModelCommandRenderer.CrumblingOverlayCommand +import net.minecraft.client.render.command.OrderedRenderCommandQueue +import net.minecraft.client.render.state.CameraRenderState +import net.minecraft.client.texture.Sprite +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import net.turtton.connectedtank.config.CTClientConfig +import net.turtton.connectedtank.config.CTClientConfig.RenderQuality +import net.turtton.connectedtank.render.FluidRenderHelper +import net.turtton.connectedtank.render.NeighborMask +import net.turtton.connectedtank.render.WaveParams + +class ConnectedTankRenderState : BlockEntityRenderState() { + var sprite: Sprite? = null + var argb: Int = 0 + var localFillLevel: Float = 0f + var wave: WaveParams = WaveParams(animTime = 0f, gridSize = 4) + var neighbors: NeighborMask = NeighborMask() +} + +class ConnectedTankBlockEntityRenderer( + @Suppress("UNUSED_PARAMETER") context: BlockEntityRendererFactory.Context, +) : BlockEntityRenderer { + companion object { + private const val DECAY_TICKS = 60f + } + + override fun createRenderState(): ConnectedTankRenderState = ConnectedTankRenderState() + + override fun updateRenderState( + entity: ConnectedTankBlockEntity, + state: ConnectedTankRenderState, + tickDelta: Float, + cameraPos: Vec3d, + crumbling: CrumblingOverlayCommand?, + ) { + super.updateRenderState(entity, state, tickDelta, cameraPos, crumbling) + + state.localFillLevel = entity.localFillLevel + if (entity.localFillLevel <= 0f || entity.fluidVariant.isBlank) { + state.sprite = null + return + } + + state.sprite = FluidVariantRendering.getSprite(entity.fluidVariant) + val color = FluidVariantRendering.getColor(entity.fluidVariant) + state.argb = (0xFF shl 24) or (color and 0x00FFFFFF) + + val world = entity.world + val pos = entity.pos + val myGroupId = entity.groupId + + fun sameGroupNeighbor(neighborPos: BlockPos): ConnectedTankBlockEntity? { + if (myGroupId == null) return null + val neighbor = world?.getBlockEntity(neighborPos) as? ConnectedTankBlockEntity ?: return null + return if (neighbor.groupId == myGroupId) neighbor else null + } + + val neighborDown = sameGroupNeighbor(pos.down()) + val neighborUp = sameGroupNeighbor(pos.up()) + + // 垂直: 下タンクが満杯で同一グループのときのみ連続とみなす + val hasDown = neighborDown != null && neighborDown.localFillLevel >= 1.0f + // 垂直: 自身が満杯かつ上タンクに同一グループの液体があるときのみ上面を省略 + val hasUp = neighborUp != null && entity.localFillLevel >= 1.0f && neighborUp.localFillLevel > 0f + // 水平: 同一グループで液体が存在する隣接タンクのみ連続 + val hasNorth = sameGroupNeighbor(pos.north())?.let { it.localFillLevel > 0f } == true + val hasSouth = sameGroupNeighbor(pos.south())?.let { it.localFillLevel > 0f } == true + val hasWest = sameGroupNeighbor(pos.west())?.let { it.localFillLevel > 0f } == true + val hasEast = sameGroupNeighbor(pos.east())?.let { it.localFillLevel > 0f } == true + + state.neighbors = NeighborMask( + up = hasUp, + down = hasDown, + north = hasNorth, + south = hasSouth, + west = hasWest, + east = hasEast, + ) + + val quality = CTClientConfig.instance.renderQuality + val worldTime = world?.time?.toFloat() ?: 0f + val elapsedTicks = worldTime - entity.waveStartTick.toFloat() + val decayFactor = if (quality == RenderQuality.LOW) 0f else max(0f, 1f - elapsedTicks / DECAY_TICKS) + val animTime = worldTime + tickDelta + // gridSize は decayFactor == 0 でも変えない。途中で分割数が変わると UV のちらつきが発生するため。 + val gridSize = if (quality == RenderQuality.HIGH) 8 else 4 + val worldX = pos.x.toFloat() + val worldZ = pos.z.toFloat() + val useWorldCoords = quality == RenderQuality.HIGH + + state.wave = WaveParams( + animTime = animTime, + gridSize = gridSize, + useWorldCoords = useWorldCoords, + worldX = worldX, + worldZ = worldZ, + decayFactor = decayFactor, + ) + } + + override fun render( + state: ConnectedTankRenderState, + matrices: MatrixStack, + queue: OrderedRenderCommandQueue, + cameraState: CameraRenderState, + ) { + val sprite = state.sprite ?: return + if (state.localFillLevel <= 0f) return + + matrices.push() + FluidRenderHelper.renderFluid( + queue, + matrices, + sprite, + state.argb, + state.localFillLevel, + state.wave, + state.neighbors, + ) + matrices.pop() + } +} +*/ +//?} else { import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.block.entity.BlockEntityRenderer import net.minecraft.client.render.block.entity.BlockEntityRendererFactory @@ -100,3 +231,4 @@ class ConnectedTankBlockEntityRenderer( matrices.pop() } } +//?} diff --git a/src/client/kotlin/net/turtton/connectedtank/item/ConnectedTankItemRenderer.kt b/src/client/kotlin/net/turtton/connectedtank/item/ConnectedTankItemRenderer.kt index cf9d3ec..fe66e49 100644 --- a/src/client/kotlin/net/turtton/connectedtank/item/ConnectedTankItemRenderer.kt +++ b/src/client/kotlin/net/turtton/connectedtank/item/ConnectedTankItemRenderer.kt @@ -3,6 +3,97 @@ package net.turtton.connectedtank.item import com.mojang.serialization.MapCodec import net.fabricmc.fabric.api.transfer.v1.client.fluid.FluidVariantRendering import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants +//? if >=1.21.11 { +/*import java.util.function.Consumer +import net.minecraft.client.render.RenderLayers +import net.minecraft.client.render.command.OrderedRenderCommandQueue +import net.minecraft.client.render.item.model.special.SpecialModelRenderer +import net.minecraft.client.render.item.model.special.SpecialModelTypes +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.item.BlockItem +import net.minecraft.item.ItemDisplayContext +import net.minecraft.item.ItemStack +import net.minecraft.util.Identifier +import net.turtton.connectedtank.block.ConnectedTankBlock +import net.turtton.connectedtank.component.CTDataComponentTypes +import net.turtton.connectedtank.config.CTClientConfig +import net.turtton.connectedtank.config.CTClientConfig.RenderQuality +import net.turtton.connectedtank.config.CTServerConfig +import net.turtton.connectedtank.config.SyncedServerConfig +import net.turtton.connectedtank.render.FluidRenderHelper +import net.turtton.connectedtank.render.WaveParams +import org.joml.Vector3fc + +class ConnectedTankItemRenderer : SpecialModelRenderer { + override fun getData(stack: ItemStack): ItemStack? = stack + + override fun render( + data: ItemStack?, + displayContext: ItemDisplayContext, + matrices: MatrixStack, + queue: OrderedRenderCommandQueue, + light: Int, + overlay: Int, + glint: Boolean, + seed: Int, + ) { + data ?: return + val fluidData = data.get(CTDataComponentTypes.TANK_FLUID) ?: return + if (fluidData.variant.isBlank || fluidData.amount <= 0L) return + + val sprite = FluidVariantRendering.getSprite(fluidData.variant) ?: return + val color = FluidVariantRendering.getColor(fluidData.variant) + val argb = (0xFF shl 24) or (color and 0x00FFFFFF) + + val tankBlock = (data.item as? BlockItem)?.block as? ConnectedTankBlock ?: return + val serverConfig = SyncedServerConfig.syncedConfig ?: CTServerConfig.instance + val capacity = serverConfig.getTierCapacity(tankBlock.tier) * FluidConstants.BUCKET + if (capacity <= 0L) return + val fillLevel = (fluidData.amount.toFloat() / capacity.toFloat()).coerceIn(0f, 1f) + + val quality = CTClientConfig.instance.renderQuality + val gridSize = if (quality == RenderQuality.HIGH) 8 else 4 + + matrices.push() + try { + FluidRenderHelper.renderFluid( + queue, + matrices, + sprite, + argb, + fillLevel, + WaveParams(animTime = 0f, gridSize = gridSize), + renderLayer = RenderLayers.itemEntityTranslucentCull(sprite.atlasId), + ) + } finally { + matrices.pop() + } + } + + override fun collectVertices(vertices: Consumer) { + } + + class Unbaked : SpecialModelRenderer.Unbaked { + override fun bake(context: SpecialModelRenderer.BakeContext): SpecialModelRenderer<*> = + ConnectedTankItemRenderer() + + override fun getCodec(): MapCodec = CODEC + + companion object { + val CODEC: MapCodec = MapCodec.unit(Unbaked()) + } + } + + companion object { + val ID: Identifier = Identifier.of("connectedtank", "tank_fluid") + + fun register() { + SpecialModelTypes.ID_MAPPER.put(ID, Unbaked.CODEC) + } + } +} +*/ +//?} else { import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.entity.model.LoadedEntityModels @@ -89,3 +180,4 @@ class ConnectedTankItemRenderer : SpecialModelRenderer { } } } +//?} diff --git a/src/client/kotlin/net/turtton/connectedtank/render/FluidRenderHelper.kt b/src/client/kotlin/net/turtton/connectedtank/render/FluidRenderHelper.kt index 2595401..e0cd69c 100644 --- a/src/client/kotlin/net/turtton/connectedtank/render/FluidRenderHelper.kt +++ b/src/client/kotlin/net/turtton/connectedtank/render/FluidRenderHelper.kt @@ -5,7 +5,13 @@ import net.minecraft.client.render.LightmapTextureManager import net.minecraft.client.render.OverlayTexture import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.VertexConsumer +//? if >=1.21.11 { +/*import net.minecraft.client.render.RenderLayers +import net.minecraft.client.render.command.OrderedRenderCommandQueue +*/ +//?} else { import net.minecraft.client.render.VertexConsumerProvider +//?} import net.minecraft.client.texture.Sprite import net.minecraft.client.util.math.MatrixStack @@ -38,14 +44,22 @@ object FluidRenderHelper { private const val SECONDARY_SPEED = 0.18f fun renderFluid( + //? if >=1.21.11 { + /*queue: OrderedRenderCommandQueue,*/ + //?} else { vertexConsumers: VertexConsumerProvider, + //?} matrices: MatrixStack, sprite: Sprite, argb: Int, fillLevel: Float, wave: WaveParams, neighbors: NeighborMask = NeighborMask(), + //? if >=1.21.11 { + /*renderLayer: RenderLayer = RenderLayers.entityTranslucent(sprite.atlasId),*/ + //?} else { renderLayer: RenderLayer = RenderLayer.getEntityTranslucent(sprite.atlasId), + //?} ) { if (fillLevel <= 0f || wave.gridSize <= 0) return @@ -57,6 +71,24 @@ object FluidRenderHelper { val fluidTop = minY + (1f - INSET - minY) * fillLevel + //? if >=1.21.11 { + /*queue.submitCustom(matrices, renderLayer) { entry, consumer -> + renderAnimatedFluid( + consumer, + entry, + sprite, + argb, + fluidTop, + wave, + minX, + maxX, + minY, + minZ, + maxZ, + neighbors, + ) + }*/ + //?} else { val consumer = vertexConsumers.getBuffer(renderLayer) val entry = matrices.peek() @@ -74,6 +106,7 @@ object FluidRenderHelper { maxZ, neighbors, ) + //?} } @Suppress("LongParameterList") diff --git a/src/main/kotlin/net/turtton/connectedtank/block/ConnectedTankBlock.kt b/src/main/kotlin/net/turtton/connectedtank/block/ConnectedTankBlock.kt index d07e4cd..168470d 100644 --- a/src/main/kotlin/net/turtton/connectedtank/block/ConnectedTankBlock.kt +++ b/src/main/kotlin/net/turtton/connectedtank/block/ConnectedTankBlock.kt @@ -204,9 +204,8 @@ class ConnectedTankBlock(val tier: TankTier, settings: Settings) : return ActionResult.SUCCESS } - override fun onUseWithItem(stack: ItemStack?, state: BlockState?, world: World?, pos: BlockPos?, player: PlayerEntity?, hand: Hand?, hit: BlockHitResult?): ActionResult? { + override fun onUseWithItem(stack: ItemStack, state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult { if (world !is ServerWorld) return ActionResult.SUCCESS - if (pos == null) return ActionResult.PASS_TO_DEFAULT_BLOCK_ACTION val persistentState = world.persistentStateManager.getOrCreate(FluidStoragePersistentState.TYPE) val tankStorage = persistentState.getStorage(pos) ?: return ActionResult.PASS_TO_DEFAULT_BLOCK_ACTION diff --git a/src/main/kotlin/net/turtton/connectedtank/block/TankFluidStorage.kt b/src/main/kotlin/net/turtton/connectedtank/block/TankFluidStorage.kt index 898cf5e..7b7efc5 100644 --- a/src/main/kotlin/net/turtton/connectedtank/block/TankFluidStorage.kt +++ b/src/main/kotlin/net/turtton/connectedtank/block/TankFluidStorage.kt @@ -24,7 +24,7 @@ class TankFluidStorage(val bucketCapacity: Int = CTServerConfig.instance.tankBuc override fun getBlankVariant(): FluidVariant = FluidVariant.blank() - override fun getCapacity(variant: FluidVariant?): Long = bucketCapacity * FluidConstants.BUCKET + override fun getCapacity(variant: FluidVariant): Long = bucketCapacity * FluidConstants.BUCKET override fun onFinalCommit() { onChanged?.invoke() diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 9187c35..2d91747 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -54,7 +54,7 @@ ], "depends": { "fabricloader": ">=0.17.2", - "minecraft": "~1.21.8", + "minecraft": "~${minecraft_version}", "java": ">=21", "fabric-api": "*", "fabric-language-kotlin": "*" diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts new file mode 100644 index 0000000..f617bb0 --- /dev/null +++ b/stonecutter.gradle.kts @@ -0,0 +1,30 @@ +plugins { + id("dev.kikugie.stonecutter") + alias(libs.plugins.spotless) +} + +stonecutter active "1.21.8" + +repositories { + mavenCentral() +} + +spotless { + kotlin { + target("src/**/*.kt") + ktlint().editorConfigOverride( + mapOf( + "ktlint_standard_import-ordering" to "disabled", + "ktlint_standard_comment-spacing" to "disabled", + ), + ) + } + kotlinGradle { + target("*.gradle.kts") + ktlint() + } + java { + target("src/**/*.java") + palantirJavaFormat() + } +}