diff --git a/README.md b/README.md index 583e9bbe..8e1e74ec 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,5 @@ A minecraft mod about casting Hexes, powerful and programmable magical effects, [Curseforge Link](https://www.curseforge.com/minecraft/mc-mods/hexcasting) -This mod requires Patchouli and Kotlin for Forge! +This mod requires PAUCAL, Patchouli and Kotlin for Forge! + diff --git a/build.gradle b/build.gradle index 49751133..78030d48 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ buildscript { + ext.kotlin_version = '1.6.21' repositories { // These repositories are only for Gradle plugins, put any other repositories in the repository block further below maven { url = 'https://maven.minecraftforge.net' } @@ -15,6 +16,7 @@ buildscript { } } + import com.diluv.schoomp.Webhook import com.diluv.schoomp.message.Message @@ -26,9 +28,10 @@ apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.parchmentmc.librarian.forgegradle' apply plugin: 'org.spongepowered.mixin' -version = '0.8.0' -group = 'at.petra-k.hexcasting' // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = 'hexcasting-1.18.2' + +version = modVersion +group = "at.petra-k.$modID" // http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = "$modID-$minecraftVersion" def isRelease = { -> try { @@ -82,25 +85,12 @@ apply plugin: 'kotlinx-serialization' // If you already know how to add the Kotlin plugin to Gradle, this is the only line you need for KFF apply from: 'https://raw.githubusercontent.com/thedarkcolour/KotlinForForge/site/thedarkcolour/kotlinforforge/gradle/kff-3.0.0.gradle' -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) +println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { - // The mappings can be changed at any time and must be in the following format. - // Channel: Version: - // snapshot YYYYMMDD Snapshot are built nightly. - // stable # Stables are built at the discretion of the MCP team. - // official MCVersion Official field/method names from Mojang mapping files - // - // You must be aware of the Mojang license when using the 'official' mappings. - // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md - // - // Use non-default mappings at your own risk. They may not always work. - // Simply re-run your setup task after changing the mappings to update your workspace. - mappings channel: 'parchment', version: '2022.03.13-1.18.2' + // After running this the first time, switch which is commented and rerun genIntellijRuns + mappings channel: 'official', version: '1.18.2' + // mappings channel: 'parchment', version: '2022.03.13-1.18.2' - // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default. - - // Default run configurations. - // These can be tweaked, removed, or duplicated as needed. runs { client { workingDirectory project.file('run') @@ -117,12 +107,11 @@ minecraft { // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels property 'forge.logging.console.level', 'debug' - // unbreak patchi?? - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', modID mods { - hexcasting { + create(modID) { source sourceSets.main } } @@ -131,29 +120,24 @@ minecraft { server { workingDirectory project.file('run') - // Recommended logging data for a userdev environment - // The markers can be added/remove as needed separated by commas. - // "SCAN": For mods scan. - // "REGISTRIES": For firing of registry events. - // "REGISTRYDUMP": For getting the contents of all registries. property 'forge.logging.markers', 'REGISTRIES' - // Recommended logging level for the console - // You can set various levels here. - // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels property 'forge.logging.console.level', 'debug' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', modID mods { - hexcasting { + create(modID) { source sourceSets.main } } } - data { + // This run config launches GameTestServer and runs all registered gametests, then exits. + // By default, the server will crash when no gametests are provided. + // The gametest system is also enabled by default for other run configs under the /test command. + gameTestServer { workingDirectory project.file('run') // Recommended logging data for a userdev environment @@ -168,14 +152,28 @@ minecraft { // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels property 'forge.logging.console.level', 'debug' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - - // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. - args '--mod', 'hexcasting', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', modID mods { - hexcasting { + create(modID) { + source sourceSets.main + } + } + } + + data { + workingDirectory project.file('run') + + property 'forge.logging.markers', 'REGISTRIES' + + property 'forge.logging.console.level', 'debug' + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + args '--mod', modID, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + + mods { + create(modID) { source sourceSets.main } } @@ -186,6 +184,13 @@ minecraft { // Include resources generated by data generators. sourceSets.main.resources { srcDir 'src/generated/resources' } +mixin { + add sourceSets.main, "${modID}.mixins.refmap.json" + config "${modID}.mixins.json" + dumpTargetOnFailure true +} + + repositories { mavenCentral() // Put repositories for dependencies here @@ -211,46 +216,34 @@ repositories { dependencies { implementation 'org.testng:testng:7.1.0' - + // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied. // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft 'net.minecraftforge:forge:1.18.2-40.0.19' + minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' - compileOnly fg.deobf("vazkii.patchouli:Patchouli:1.18.2-66:api") - runtimeOnly fg.deobf("vazkii.patchouli:Patchouli:1.18.2-66") + compileOnly fg.deobf("at.petra-k.paucal:paucal-$minecraftVersion:$paucalVersion") + runtimeOnly fg.deobf("at.petra-k.paucal:paucal-$minecraftVersion:$paucalVersion") + compileOnly fg.deobf("vazkii.patchouli:Patchouli:$minecraftVersion-$patchouliVersion:api") + runtimeOnly fg.deobf("vazkii.patchouli:Patchouli:$minecraftVersion-$patchouliVersion") - // compile against the JEI API but do not include it at runtime - compileOnly fg.deobf("mezz.jei:jei-1.18.2:9.5.3.143:api") - // at runtime, use the full JEI jar - runtimeOnly fg.deobf("mezz.jei:jei-1.18.2:9.5.3.143") - compileOnly fg.deobf("at.petra-k.paucal:paucal-1.18.2:0.3.2") - runtimeOnly fg.deobf("at.petra-k.paucal:paucal-1.18.2:0.3.2") -} - -mixin { - add sourceSets.main, 'hexcasting.mixins.refmap.json' - config 'hexcasting.mixins.json' - dumpTargetOnFailure true -} - -java { - withJavadocJar() - withSourcesJar() + compileOnly fg.deobf("mezz.jei:jei-$minecraftVersion:$jeiVersion:api") + runtimeOnly fg.deobf("mezz.jei:jei-$minecraftVersion:$jeiVersion") } // Example for how to get properties into the manifest for reading at runtime. jar { manifest { attributes([ - "Specification-Title" : "hexcasting", - "Specification-Vendor" : "petrak-at", + "Specification-Title" : modID, + "Specification-Vendor" : "petra-kat", "Specification-Version" : "1", // We are version 1 of ourselves "Implementation-Title" : project.name, "Implementation-Version" : project.jar.archiveVersion, - "Implementation-Vendor" : "petrak-at", + "Implementation-Vendor" : "petra-kat", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") ]) } @@ -262,12 +255,10 @@ jar.finalizedBy('reobfJar') // However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing // publish.dependsOn('reobfJar') - // Disables Gradle's custom module metadata from being published to maven. The // metadata includes mapped dependencies which are not reasonably consumable by // other mod developers. tasks.withType(GenerateModuleMetadata) { - enabled = false } @@ -280,9 +271,7 @@ publishing { from components.java pom.withXml { - asNode().dependencies.dependency.each { dep -> - assert dep.parent().remove(dep) } } @@ -294,14 +283,6 @@ publishing { } } } -compileKotlin { - kotlinOptions { - } -} -compileTestKotlin { - kotlinOptions { - } -} def getGitChangelog = { -> try { @@ -311,13 +292,13 @@ def getGitChangelog = { -> def travisRange = System.getenv('TRAVIS_COMMIT_RANGE') if (gitHash && gitPrevHash) { exec { - commandLine 'git', 'log', '--pretty=tformat:> %s', '' + gitPrevHash + '...' + gitHash + commandLine 'git', 'log', '--pretty=tformat:> - %s', '' + gitPrevHash + '...' + gitHash standardOutput = stdout } return stdout.toString().trim() } else if (travisRange) { exec { - commandLine 'git', 'log', '--pretty=tformat:> %s', '' + travisRange + commandLine 'git', 'log', '--pretty=tformat:> - %s', '' + travisRange standardOutput = stdout } return stdout.toString().trim() @@ -340,7 +321,7 @@ task sendWebhook { def message = new Message() message.setUsername("Patreon Early Access") - message.setContent("New Hexcasting release! Download it here: ${System.getenv("BUILD_URL")}\nChangelog:\n${getGitChangelog()}") + message.setContent("New **$modName** release! Download it here: ${System.getenv("BUILD_URL")}\nChangelog:\n${getGitChangelog()}") webhook.sendMessage(message) } catch (ignored) { @@ -349,3 +330,14 @@ task sendWebhook { } } +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation +} +compileKotlin { + kotlinOptions { + } +} +compileTestKotlin { + kotlinOptions { + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 784899a6..d87b5e53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,11 @@ # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false +modID=hexcasting +modName=Hex Casting +minecraftVersion=1.18.2 +modVersion=0.8.4 +forgeVersion=40.1.0 +paucalVersion=0.3.4 +patchouliVersion=66 +jeiVersion=9.5.3.143 diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 833f0f61..2512e711 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -321,19 +321,19 @@ f043370d6762b976e33dd6e9562d5e1659d32bbf assets/hexcasting/models/item/wand_old. 05e86742a71afd740f47639be62f93bc9898fcde data/forge/tags/items/gems.json b6593ea802a692c29b5032292df31beb84878ad8 data/hexcasting/advancements/aaa_wasteful_cast.json 4f4c94021adfb296e3ef3dce1acc46f724f38f92 data/hexcasting/advancements/aab_big_cast.json -a165e3959b7d0c37bea586d0e94609b483255569 data/hexcasting/advancements/enlightenment.json +2fe3543a209fca031b1eace7ea217c76142609cc data/hexcasting/advancements/enlightenment.json eb6393ffc79966e4b5983a68157742b78cd12414 data/hexcasting/advancements/opened_eyes.json -d0b09e984b9270fe20b6c8d6f17e7690caaea409 data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json -7e93886be31c3762a5b70e56a7214d19f64d58a8 data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json -12d9101d43c907f08b0f94747240678d53e4c1fb data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json -ed6ce219b2ee65d69ea45a43fb9a71b1f5da88bb data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json -d225f90cc1e3b8200014106cd2d3bede9c783817 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json -c966b7ab46808f86bdb7bbd07049146f0dfb24ec data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json +cf0ad981bebbb79414d955fb40fbf537fe88b89d data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json +c2a362b8c19cb288187d8ff340f82198edc54378 data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json +c11dc4388c18dadff5d93126eb0f7ae848d627b9 data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json +86424d21e1bf91c128d3b0d528b813629ad962e9 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json +5f9f0962f407062e7b6dd0e8c5f8c55ce13962a5 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json +5d4811f78feefbef0a305555143f488b3dac7ac6 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json 3fe1fcf17e1e25aebede47c537f92888330ccf9f data/hexcasting/advancements/recipes/hexcasting/abacus.json 5a17fa9a1496f5fbedd0362f94a5231e0e5ebbfc data/hexcasting/advancements/recipes/hexcasting/ageing_scroll_paper_lantern.json -c498998fcffe3d1a0b6dfd6459db64e9389f5c15 data/hexcasting/advancements/recipes/hexcasting/akashic_bookshelf.json +66e51300dc72c27ed8024ddf852ac9a6208a66b1 data/hexcasting/advancements/recipes/hexcasting/akashic_bookshelf.json 31f9b7d8141f67981deedf7a46894e454006bb28 data/hexcasting/advancements/recipes/hexcasting/akashic_button.json -d9f9fc153bf8e8861f79f982b185d2e4c7048067 data/hexcasting/advancements/recipes/hexcasting/akashic_connector.json +168749d413b20bb9c05a8e7191758e0e596a319b data/hexcasting/advancements/recipes/hexcasting/akashic_connector.json 1266b263056dd15c862bff27b05a119c4bbc89ee data/hexcasting/advancements/recipes/hexcasting/akashic_door.json 149179e18b1b8db5dc3fb96e6faa6cb6ffaecb75 data/hexcasting/advancements/recipes/hexcasting/akashic_panel.json 4f852507d843f82dce1512f55abfb205b9829ed4 data/hexcasting/advancements/recipes/hexcasting/akashic_planks.json @@ -368,8 +368,8 @@ d6dfd0c6e995270868cb90de818d24b8a667fd01 data/hexcasting/advancements/recipes/he b0b1c5fff194b92ff8c5d6468e177271fd910abd data/hexcasting/advancements/recipes/hexcasting/dye_colorizer_red.json ccc33b4f1a43c8ecd3352ad36ae2dd2191317b5b data/hexcasting/advancements/recipes/hexcasting/dye_colorizer_white.json 9c857c4aeda8a1b3d7a1b5d341871a9434b5816f data/hexcasting/advancements/recipes/hexcasting/dye_colorizer_yellow.json -d978ce120b6af69899ff556f06997fcea522948b data/hexcasting/advancements/recipes/hexcasting/empty_directrix.json -e40a09b7fdf5125be645a323ea5e1922a7e963f0 data/hexcasting/advancements/recipes/hexcasting/empty_impetus.json +7351200c8e3eb24772852c578286384c8aab61bd data/hexcasting/advancements/recipes/hexcasting/empty_directrix.json +023c32e8834eb313c4fa94a84a8f6390ee951ef0 data/hexcasting/advancements/recipes/hexcasting/empty_impetus.json f089ab17470c5fa0065438c5533d5fafb3ee8eaf data/hexcasting/advancements/recipes/hexcasting/focus.json fc57d15e9f9f11347a2170dd06053954345368d2 data/hexcasting/advancements/recipes/hexcasting/lens.json 82be04125e60a28701de5bb6bc7855bb46fa9d0f data/hexcasting/advancements/recipes/hexcasting/pride_colorizer_0.json @@ -406,7 +406,7 @@ f32ccb2d36d773215d91dee46bec70a20af501c3 data/hexcasting/advancements/recipes/he 30950c6dd31102cf145f8f7d2979df0736a7ba1e data/hexcasting/advancements/recipes/hexcasting/wand_oak.json f8d2872c4e692153049b6ae4879755a079954763 data/hexcasting/advancements/recipes/hexcasting/wand_spruce.json 3b2bcffe70bb1f732f06c2560cef66de6c273d62 data/hexcasting/advancements/recipes/hexcasting/wand_warped.json -d31956749bebbcb3f0d3c37f89b569642ac8c2fb data/hexcasting/advancements/root.json +ed0e62cb81783d8eb6323dd70609067219f163ec data/hexcasting/advancements/root.json 739cbdf7f204132f2acfab4df8d21c6197aa1456 data/hexcasting/advancements/y_u_no_cast_angy.json 70a8f77d38affa642afbfceebe129358737b09ac data/hexcasting/loot_modifiers/amethyst_cluster_charged.json f746acc6b3e798d3b95f4ceb463c648b1f3ae8c3 data/hexcasting/loot_modifiers/amethyst_cluster_dust.json @@ -418,6 +418,7 @@ afecba3144e00505977a4ab4de7940f949ab7818 data/hexcasting/loot_modifiers/scroll_d 50e7ad657a0ab43f3bd632120e09f109791aaf34 data/hexcasting/loot_modifiers/scroll_shipwreck.json 7ffa361bd8a108b504fe450749b42997dc898e5e data/hexcasting/loot_modifiers/scroll_stronghold_library.json cfd72df535fe95cd2b0d800696e7b4b3429a0459 data/hexcasting/loot_tables/blocks/akashic_bookshelf.json +fc787ec13389b66afda79083f22c7b72f02d5966 data/hexcasting/loot_tables/blocks/akashic_button.json 2e5958279471fa57ae2929d9f9da46e59495f50e data/hexcasting/loot_tables/blocks/akashic_connector.json 3794453f5412af9c7307c9cd91fe2d01ffb763af data/hexcasting/loot_tables/blocks/akashic_door.json e05da321f00ce09c6f4ad3f6da95ae3dc93e7748 data/hexcasting/loot_tables/blocks/akashic_leaves1.json @@ -427,7 +428,10 @@ e05da321f00ce09c6f4ad3f6da95ae3dc93e7748 data/hexcasting/loot_tables/blocks/akas ff25315e494e3b79667a1fa90d22a80d0eb6d208 data/hexcasting/loot_tables/blocks/akashic_log_stripped.json 7400ffa5214a5d7ed34be2ac2ffcc2b50cdf299c data/hexcasting/loot_tables/blocks/akashic_panel.json f59f016a4fa4edaad0b2731f8f1bb2c7b9299ede data/hexcasting/loot_tables/blocks/akashic_planks.json +a8f202947467960dcc634ca7cc65b8911a5c2399 data/hexcasting/loot_tables/blocks/akashic_pressure_plate.json 22517cb8c8063a6a2752cd80f63f224c88bc2ede data/hexcasting/loot_tables/blocks/akashic_record.json +abb4c70d044fed6af763b75bdc50fe2624e83625 data/hexcasting/loot_tables/blocks/akashic_slab.json +5128da5769f0a1a9045488e32ac453069d6431f5 data/hexcasting/loot_tables/blocks/akashic_stairs.json 0ddb27503a7266d126661bad496047a069a07670 data/hexcasting/loot_tables/blocks/akashic_tile.json 659b7e6d539474357532c1207b21354e19cbd4b1 data/hexcasting/loot_tables/blocks/akashic_trapdoor.json 1590fee356080d4dd3f4e0718d87269bdd7f3519 data/hexcasting/loot_tables/blocks/akashic_wood.json @@ -544,7 +548,7 @@ d1b8725bbfc01e2d9a02ef84c911fef89b3636a9 data/hexcasting/tags/items/wands.json c25784941d6416744fb2ca2d43a3203e5c3e7c8a data/minecraft/tags/blocks/leaves.json f3c6b6917e504e1c3d5d8875f7cce6f311e791d2 data/minecraft/tags/blocks/logs.json f3c6b6917e504e1c3d5d8875f7cce6f311e791d2 data/minecraft/tags/blocks/logs_that_burn.json -7c08784f2de139be380b5299f8ea8b8c78126ed8 data/minecraft/tags/blocks/mineable/axe.json +cb5721fcb4a8f7bf14adf6ab560378a250128aba data/minecraft/tags/blocks/mineable/axe.json c25784941d6416744fb2ca2d43a3203e5c3e7c8a data/minecraft/tags/blocks/mineable/hoe.json eb4bfbd7fc7632a5c16aa1d50d6090a1f466069b data/minecraft/tags/blocks/mineable/pickaxe.json f55afc2c05d93b5a44bc9fd73c5e81e71b183965 data/minecraft/tags/blocks/mineable/shovel.json diff --git a/src/generated/resources/data/hexcasting/advancements/enlightenment.json b/src/generated/resources/data/hexcasting/advancements/enlightenment.json index 6262d68e..817aee0d 100644 --- a/src/generated/resources/data/hexcasting/advancements/enlightenment.json +++ b/src/generated/resources/data/hexcasting/advancements/enlightenment.json @@ -20,7 +20,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json index 0ec5f91a..214bf87c 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json index d97f1835..17714fa1 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json index 363d63de..675eec77 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json index 0bf1ed27..d415e909 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json index 68a6dea9..11f02807 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json index 6ef63302..94b84ee9 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_bookshelf.json b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_bookshelf.json index f9a06f32..1d8cc370 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_bookshelf.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_bookshelf.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_connector.json b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_connector.json index ab717d35..2963c28e 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_connector.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/akashic_connector.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_directrix.json b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_directrix.json index 3871d213..112e9b61 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_directrix.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_directrix.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_impetus.json b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_impetus.json index 8280247a..7248e179 100644 --- a/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_impetus.json +++ b/src/generated/resources/data/hexcasting/advancements/recipes/hexcasting/empty_impetus.json @@ -10,7 +10,7 @@ "trigger": "hexcasting:overcast", "conditions": { "health_used": { - "min": 17.95 + "min": 0.8 }, "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": { "min": 0.1, diff --git a/src/generated/resources/data/hexcasting/advancements/root.json b/src/generated/resources/data/hexcasting/advancements/root.json index d3ee9841..8160a074 100644 --- a/src/generated/resources/data/hexcasting/advancements/root.json +++ b/src/generated/resources/data/hexcasting/advancements/root.json @@ -16,29 +16,14 @@ "background": "minecraft:textures/block/calcite.png" }, "criteria": { - "on_thingy": { - "trigger": "minecraft:tick", + "has_charged_amethyst": { + "trigger": "minecraft:inventory_changed", "conditions": { - "player": [ + "items": [ { - "condition": "minecraft:entity_properties", - "predicate": { - "stepping_on": { - "position": { - "y": { - "min": -64.0, - "max": 30.0 - } - }, - "block": { - "blocks": [ - "minecraft:amethyst_block", - "minecraft:calcite" - ] - } - } - }, - "entity": "this" + "items": [ + "hexcasting:charged_amethyst" + ] } ] } @@ -46,7 +31,7 @@ }, "requirements": [ [ - "on_thingy" + "has_charged_amethyst" ] ] } \ No newline at end of file diff --git a/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_dust.json b/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_dust.json index 8a821062..665afbb9 100644 --- a/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_dust.json +++ b/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_dust.json @@ -24,7 +24,7 @@ "function": "minecraft:set_count", "count": { "type": "minecraft:uniform", - "min": 1.0, + "min": 2.0, "max": 4.0 }, "add": false @@ -36,4 +36,4 @@ } ], "type": "paucal:add_item" -} \ No newline at end of file +} diff --git a/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_shard_reducer.json b/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_shard_reducer.json index d4846240..0228fd42 100644 --- a/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_shard_reducer.json +++ b/src/generated/resources/data/hexcasting/loot_modifiers/amethyst_cluster_shard_reducer.json @@ -18,6 +18,6 @@ } } ], - "modifier": -2.0, + "modifier": -0.5, "type": "hexcasting:amethyst_shard_reducer" -} \ No newline at end of file +} diff --git a/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_button.json b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_button.json new file mode 100644 index 00000000..732abe88 --- /dev/null +++ b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_button.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "name": "akashic_button", + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "hexcasting:akashic_button" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_pressure_plate.json b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_pressure_plate.json new file mode 100644 index 00000000..3b009866 --- /dev/null +++ b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_pressure_plate.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "name": "akashic_pressure_plate", + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "hexcasting:akashic_pressure_plate" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_slab.json b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_slab.json new file mode 100644 index 00000000..c44a7363 --- /dev/null +++ b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_slab.json @@ -0,0 +1,35 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "name": "akashic_slab", + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "hexcasting:akashic_slab" + } + ], + "functions": [ + { + "function": "minecraft:set_count", + "conditions": [ + { + "condition": "minecraft:block_state_property", + "block": "hexcasting:akashic_slab", + "properties": { + "type": "double" + } + } + ], + "count": 2.0, + "add": false + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_stairs.json b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_stairs.json new file mode 100644 index 00000000..134d2b07 --- /dev/null +++ b/src/generated/resources/data/hexcasting/loot_tables/blocks/akashic_stairs.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "name": "akashic_stairs", + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "hexcasting:akashic_stairs" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json index 9bb914fd..5ae1fa0a 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -14,6 +14,7 @@ "hexcasting:akashic_door", "hexcasting:akashic_trapdoor", "hexcasting:akashic_slab", + "hexcasting:akashic_stairs", "hexcasting:akashic_button" ] } \ No newline at end of file diff --git a/src/main/java/at/petrak/hexcasting/HexMod.kt b/src/main/java/at/petrak/hexcasting/HexMod.kt index 2619495f..14161533 100644 --- a/src/main/java/at/petrak/hexcasting/HexMod.kt +++ b/src/main/java/at/petrak/hexcasting/HexMod.kt @@ -11,18 +11,23 @@ import at.petrak.hexcasting.common.blocks.HexBlocks import at.petrak.hexcasting.common.casting.RegisterPatterns import at.petrak.hexcasting.common.casting.operators.spells.great.OpFlight import at.petrak.hexcasting.common.command.HexCommands +import at.petrak.hexcasting.common.command.PatternResLocArgument import at.petrak.hexcasting.common.entities.HexEntities import at.petrak.hexcasting.common.items.HexItems import at.petrak.hexcasting.common.lib.HexCapabilityHandler import at.petrak.hexcasting.common.lib.HexSounds import at.petrak.hexcasting.common.misc.Brainsweeping +import at.petrak.hexcasting.common.misc.PlayerPositionRecorder import at.petrak.hexcasting.common.network.HexMessages import at.petrak.hexcasting.common.particles.HexParticles +import at.petrak.hexcasting.common.recipe.HexComposting import at.petrak.hexcasting.common.recipe.HexCustomRecipes import at.petrak.hexcasting.common.recipe.HexRecipeSerializers import at.petrak.hexcasting.datagen.HexDataGenerators import at.petrak.hexcasting.datagen.lootmods.HexLootModifiers import at.petrak.hexcasting.server.TickScheduler +import net.minecraft.commands.synchronization.ArgumentTypes +import net.minecraft.commands.synchronization.EmptyArgumentSerializer import net.minecraftforge.api.distmarker.Dist import net.minecraftforge.common.ForgeConfigSpec import net.minecraftforge.eventbus.api.SubscribeEvent @@ -55,6 +60,8 @@ object HexMod { CLIENT_CONFIG_SPEC = ForgeConfigSpec.Builder() .configure { builder: ForgeConfigSpec.Builder? -> HexConfig.Client(builder) }.right + ArgumentTypes.register("hexcasting:pattern", PatternResLocArgument::class.java, EmptyArgumentSerializer(PatternResLocArgument::id)) + // mod lifecycle val modBus = thedarkcolour.kotlinforforge.forge.MOD_BUS // game events @@ -77,6 +84,9 @@ object HexMod { modBus.register(HexStatistics::class.java) modBus.register(HexRecipeSerializers::class.java) + modBus.register(HexComposting::class.java) + + evBus.register(PlayerPositionRecorder::class.java) evBus.register(HexCommands::class.java) evBus.register(TickScheduler) evBus.register(HexCapabilityHandler::class.java) diff --git a/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java b/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java index ac3f4305..7abdd2c8 100644 --- a/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java +++ b/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java @@ -35,7 +35,7 @@ public class OvercastTrigger extends SimpleCriterionTrigger { var manaToHealth = HexConfig.manaToHealthRate.get(); var healthUsed = manaGenerated / manaToHealth; - return inst.test(manaGenerated, healthUsed, player.getHealth() - (float) healthUsed); + return inst.test(manaGenerated, healthUsed / player.getMaxHealth(), player.getHealth() - (float) healthUsed); }); } diff --git a/src/main/java/at/petrak/hexcasting/api/cap/HexCapabilities.java b/src/main/java/at/petrak/hexcasting/api/cap/HexCapabilities.java index c920dc2e..7e1f0e13 100644 --- a/src/main/java/at/petrak/hexcasting/api/cap/HexCapabilities.java +++ b/src/main/java/at/petrak/hexcasting/api/cap/HexCapabilities.java @@ -1,9 +1,12 @@ package at.petrak.hexcasting.api.cap; +import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityToken; +import java.util.Optional; + public final class HexCapabilities { public static final Capability MANA = CapabilityManager.get(new CapabilityToken<>() { @@ -14,4 +17,10 @@ public final class HexCapabilities { }); public static final Capability COLOR = CapabilityManager.get(new CapabilityToken<>() { }); + + public static Optional getCapability(ItemStack stack, Capability cap) { + if (stack.isEmpty()) + return Optional.empty(); + return stack.getCapability(cap).resolve(); + } } diff --git a/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java b/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java index 08cb508b..cd15d519 100644 --- a/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java +++ b/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.circle; import at.petrak.hexcasting.api.misc.FrozenColorizer; +import at.petrak.hexcasting.api.misc.ManaConstants; import at.petrak.hexcasting.api.mod.HexApiItems; import at.petrak.hexcasting.api.mod.HexApiSounds; import at.petrak.hexcasting.api.mod.HexConfig; @@ -37,6 +38,8 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.util.LazyOptional; @@ -115,21 +118,22 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple this.stepCircle(); } - public List> getScryingLensOverlay(BlockState state, BlockPos pos, - LocalPlayer observer, ClientLevel world, InteractionHand lensHand) { - var out = new ArrayList>(); + @OnlyIn(Dist.CLIENT) + public void applyScryingLensOverlay(List> lines, + BlockState state, BlockPos pos, + LocalPlayer observer, ClientLevel world, + Direction hitFace, InteractionHand lensHand) { if (world.getBlockEntity(pos) instanceof BlockEntityAbstractImpetus beai) { - var dustCount = (float) beai.getMana() / (float) HexConfig.dustManaAmount.get(); + var dustCount = (float) beai.getMana() / (float) ManaConstants.DUST_UNIT; var dustCmp = new TranslatableComponent("hexcasting.tooltip.lens.impetus.mana", String.format("%.2f", dustCount)); - out.add(new Pair<>(new ItemStack(HexApiItems.AMETHYST_DUST), dustCmp)); + lines.add(new Pair<>(new ItemStack(HexApiItems.AMETHYST_DUST), dustCmp)); var mishap = this.getLastMishap(); if (mishap != null) { - out.add(new Pair<>(new ItemStack(Items.MUSIC_DISC_11), mishap)); + lines.add(new Pair<>(new ItemStack(Items.MUSIC_DISC_11), mishap)); } } - return out; } @NotNull @@ -173,7 +177,7 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple if (tag.contains(TAG_ACTIVATOR, Tag.TAG_INT_ARRAY) && tag.contains(TAG_COLORIZER, Tag.TAG_COMPOUND) && tag.contains(TAG_NEXT_BLOCK, Tag.TAG_COMPOUND) && - tag.contains(TAG_TRACKED_BLOCKS, Tag.TAG_COMPOUND)) { + tag.contains(TAG_TRACKED_BLOCKS, Tag.TAG_LIST)) { this.activator = tag.getUUID(TAG_ACTIVATOR); this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER)); this.nextBlock = NbtUtils.readBlockPos(tag.getCompound(TAG_NEXT_BLOCK)); diff --git a/src/main/java/at/petrak/hexcasting/api/client/ScryingLensOverlayRegistry.java b/src/main/java/at/petrak/hexcasting/api/client/ScryingLensOverlayRegistry.java index 6f1ae8b3..da8323f9 100644 --- a/src/main/java/at/petrak/hexcasting/api/client/ScryingLensOverlayRegistry.java +++ b/src/main/java/at/petrak/hexcasting/api/client/ScryingLensOverlayRegistry.java @@ -1,21 +1,30 @@ package at.petrak.hexcasting.api.client; +import com.google.common.collect.Lists; import com.mojang.datafixers.util.Pair; +import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; import java.util.Vector; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -26,16 +35,53 @@ import java.util.concurrent.ConcurrentMap; */ @OnlyIn(Dist.CLIENT) public final class ScryingLensOverlayRegistry { - private static final ConcurrentMap ID_LOOKUP = new ConcurrentHashMap<>(); + private static final ConcurrentMap ID_LOOKUP = new ConcurrentHashMap<>(); // vectors are thread-safe! - private static final List> PREDICATE_LOOKUP = new Vector<>(); + private static final List> PREDICATE_LOOKUP = new Vector<>(); + + // implemented as a map to allow for weak dereferencing + private static final Map> comparatorData = new WeakHashMap<>(); + + public static void receiveComparatorValue(BlockPos pos, int value) { + LocalPlayer player = Minecraft.getInstance().player; + if (player != null) { + if (pos == null || value == -1) + comparatorData.remove(player); + else + comparatorData.put(player, new Pair<>(pos, value)); + } + } + + public static int getComparatorValue(boolean onlyRealComparators) { + var mc = Minecraft.getInstance(); + var player = mc.player; + var level = mc.level; + var result = mc.hitResult; + + if (player == null || level == null || result == null || result.getType() != HitResult.Type.BLOCK) + return -1; + + var comparatorValue = comparatorData.get(player); + if (comparatorValue == null) + return -1; + + var pos = ((BlockHitResult)result).getBlockPos(); + if (!pos.equals(comparatorValue.getFirst())) + return -1; + + var state = mc.level.getBlockState(pos); + if ((onlyRealComparators && !state.is(Blocks.COMPARATOR)) || (!onlyRealComparators && !state.hasAnalogOutputSignal())) + return -1; + + return comparatorValue.getSecond(); + } /** * Add the block to display things when the player is holding a lens and looking at it. * * @throws IllegalArgumentException if the block is already registered. */ - public static void addDisplayer(Block block, Displayer displayer) { + public static void addDisplayer(Block block, OverlayBuilder displayer) { addDisplayer(block.getRegistryName(), displayer); } @@ -44,7 +90,7 @@ public final class ScryingLensOverlayRegistry { * * @throws IllegalArgumentException if the block ID is already registered. */ - public static void addDisplayer(ResourceLocation blockID, Displayer displayer) { + public static void addDisplayer(ResourceLocation blockID, OverlayBuilder displayer) { if (ID_LOOKUP.containsKey(blockID)) { throw new IllegalArgumentException("Already have a displayer for " + blockID); } @@ -57,47 +103,51 @@ public final class ScryingLensOverlayRegistry { * These have a lower priority than the standard ID-based displays, so if an ID and predicate both match, * this won't be displayed. */ - public static void addPredicateDisplayer(Predicate predicate, Displayer displayer) { + public static void addPredicateDisplayer(OverlayPredicate predicate, OverlayBuilder displayer) { PREDICATE_LOOKUP.add(new Pair<>(predicate, displayer)); } /** * Internal use only. */ - public static @Nullable List> getLines(BlockState state, BlockPos pos, - LocalPlayer observer, ClientLevel world, - @Nullable InteractionHand lensHand) { + public static @NotNull List> getLines(BlockState state, BlockPos pos, + LocalPlayer observer, ClientLevel world, + Direction hitFace, @Nullable InteractionHand lensHand) { + List> lines = Lists.newArrayList(); var idLookedup = ID_LOOKUP.get(state.getBlock().getRegistryName()); if (idLookedup != null) { - return idLookedup.getLines(state, pos, observer, world, lensHand); + idLookedup.addLines(lines, state, pos, observer, world, hitFace, lensHand); } for (var pair : PREDICATE_LOOKUP) { - if (pair.getFirst().test(state, pos, observer, world, lensHand)) { - return pair.getSecond().getLines(state, pos, observer, world, lensHand); + if (pair.getFirst().test(state, pos, observer, world, hitFace, lensHand)) { + pair.getSecond().addLines(lines, state, pos, observer, world, hitFace, lensHand); } } - return null; + return lines; } /** * Return the lines displayed by the cursor: an item and some text. *

- * The ItemStack can be null; if it is, the text isn't shifted over for it. + * The ItemStack can be empty; if it is, the text isn't shifted over for it. */ @FunctionalInterface - public interface Displayer { - List> getLines(BlockState state, BlockPos pos, LocalPlayer observer, - ClientLevel world, - @Nullable InteractionHand lensHand); + public interface OverlayBuilder { + void addLines(List> lines, + BlockState state, BlockPos pos, LocalPlayer observer, + ClientLevel world, + Direction hitFace, @Nullable InteractionHand lensHand); } /** * Predicate for matching on a block state. */ @FunctionalInterface - public interface Predicate { - boolean test(BlockState state, BlockPos pos, LocalPlayer observer, ClientLevel world, @Nullable InteractionHand lensHand); + public interface OverlayPredicate { + boolean test(BlockState state, BlockPos pos, LocalPlayer observer, + ClientLevel world, + Direction hitFace, @Nullable InteractionHand lensHand); } } diff --git a/src/main/java/at/petrak/hexcasting/api/item/DataHolderItem.java b/src/main/java/at/petrak/hexcasting/api/item/DataHolderItem.java index dee9e52f..33b4f214 100644 --- a/src/main/java/at/petrak/hexcasting/api/item/DataHolderItem.java +++ b/src/main/java/at/petrak/hexcasting/api/item/DataHolderItem.java @@ -1,6 +1,8 @@ package at.petrak.hexcasting.api.item; import at.petrak.hexcasting.api.spell.SpellDatum; +import at.petrak.hexcasting.api.utils.NBTHelper; +import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.chat.Component; @@ -13,6 +15,8 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public interface DataHolderItem { + String TAG_OVERRIDE_VISUALLY = "VisualOverride"; + @Nullable CompoundTag readDatumTag(ItemStack stack); @Nullable @@ -49,6 +53,10 @@ public interface DataHolderItem { if (pIsAdvanced.isAdvanced()) { pTooltipComponents.add(NbtUtils.toPrettyComponent(datumTag)); } + } else if (NBTHelper.hasString(pStack, DataHolderItem.TAG_OVERRIDE_VISUALLY)) { + pTooltipComponents.add(new TranslatableComponent("hexcasting.spelldata.onitem", + new TranslatableComponent("hexcasting.spelldata.anything").withStyle(ChatFormatting.LIGHT_PURPLE))); + } } } diff --git a/src/main/java/at/petrak/hexcasting/api/misc/FrozenColorizer.java b/src/main/java/at/petrak/hexcasting/api/misc/FrozenColorizer.java index 616e0a64..a8cba786 100644 --- a/src/main/java/at/petrak/hexcasting/api/misc/FrozenColorizer.java +++ b/src/main/java/at/petrak/hexcasting/api/misc/FrozenColorizer.java @@ -55,7 +55,7 @@ public record FrozenColorizer(ItemStack item, UUID owner) { } public static boolean isColorizer(ItemStack stack) { - return stack.getCapability(HexCapabilities.COLOR).isPresent(); + return HexCapabilities.getCapability(stack, HexCapabilities.COLOR).isPresent(); } /** @@ -89,7 +89,7 @@ public record FrozenColorizer(ItemStack item, UUID owner) { * @return an AARRGGBB color. */ public int getRawColor(float time, Vec3 position) { - var maybeColorizer = item.getCapability(HexCapabilities.COLOR).resolve(); + var maybeColorizer = HexCapabilities.getCapability(this.item, HexCapabilities.COLOR); if (maybeColorizer.isPresent()) { Colorizer colorizer = maybeColorizer.get(); return colorizer.color(owner, time, position); diff --git a/src/main/java/at/petrak/hexcasting/api/misc/ManaConstants.java b/src/main/java/at/petrak/hexcasting/api/misc/ManaConstants.java new file mode 100644 index 00000000..7a2111df --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/api/misc/ManaConstants.java @@ -0,0 +1,7 @@ +package at.petrak.hexcasting.api.misc; + +public final class ManaConstants { + public static final int DUST_UNIT = 10000; + public static final int SHARD_UNIT = 5 * DUST_UNIT; + public static final int CRYSTAL_UNIT = 10 * DUST_UNIT; +} diff --git a/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java b/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java index aa821e2d..311d6d75 100644 --- a/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java +++ b/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.api.mod; +import at.petrak.hexcasting.api.misc.ManaConstants; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Tier; import net.minecraft.world.item.Tiers; @@ -16,13 +17,13 @@ public class HexConfig { public HexConfig(ForgeConfigSpec.Builder builder) { builder.push("Mana Amounts"); dustManaAmount = builder.comment("How much mana a single Amethyst Dust item is worth") - .defineInRange("dustManaAmount", 10_000, 0, Integer.MAX_VALUE); + .defineInRange("dustManaAmount", ManaConstants.DUST_UNIT, 0, Integer.MAX_VALUE); shardManaAmount = builder.comment("How much mana a single Amethyst Shard item is worth") - .defineInRange("shardManaAmount", 50_000, 0, Integer.MAX_VALUE); + .defineInRange("shardManaAmount", ManaConstants.SHARD_UNIT, 0, Integer.MAX_VALUE); chargedCrystalManaAmount = builder.comment("How much mana a single Charged Amethyst Crystal item is worth") - .defineInRange("chargedCrystalManaAmount", 100_000, 0, Integer.MAX_VALUE); + .defineInRange("chargedCrystalManaAmount", ManaConstants.CRYSTAL_UNIT, 0, Integer.MAX_VALUE); manaToHealthRate = builder.comment("How many points of mana a half-heart is worth when casting from HP") - .defineInRange("manaToHealthRate", 200_000.0 / 20.0, 0.0, Double.POSITIVE_INFINITY); + .defineInRange("manaToHealthRate", 2 * ManaConstants.CRYSTAL_UNIT / 20.0, 0.0, Double.POSITIVE_INFINITY); builder.pop(); } @@ -33,7 +34,7 @@ public class HexConfig { public Client(ForgeConfigSpec.Builder builder) { patternPointSpeedMultiplier = builder.comment( "How fast the point showing you the stroke order on patterns moves") - .defineInRange("manaToHealthRate", 1.0, 0.0, Double.POSITIVE_INFINITY); + .defineInRange("patternPointSpeed", 1.0, 0.0, Double.POSITIVE_INFINITY); ctrlTogglesOffStrokeOrder = builder.comment( "Whether the ctrl key will instead turn *off* the color gradient on patterns") .define("ctrlTogglesOffStrokeOrder", false); diff --git a/src/main/java/at/petrak/hexcasting/api/mod/HexStatistics.java b/src/main/java/at/petrak/hexcasting/api/mod/HexStatistics.java index 38886613..24ee73ce 100644 --- a/src/main/java/at/petrak/hexcasting/api/mod/HexStatistics.java +++ b/src/main/java/at/petrak/hexcasting/api/mod/HexStatistics.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.mod; import at.petrak.hexcasting.HexMod; +import at.petrak.hexcasting.api.misc.ManaConstants; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.stats.StatFormatter; @@ -19,10 +20,10 @@ public class HexStatistics { @SubscribeEvent public static void register(RegistryEvent.Register evt) { MANA_USED = makeCustomStat("mana_used", - manamount -> StatFormatter.DEFAULT.format(manamount / HexConfig.dustManaAmount.get()) + manamount -> StatFormatter.DEFAULT.format(manamount / ManaConstants.DUST_UNIT) ); MANA_OVERCASTED = makeCustomStat("mana_overcasted", - manamount -> StatFormatter.DEFAULT.format(manamount / HexConfig.dustManaAmount.get()) + manamount -> StatFormatter.DEFAULT.format(manamount / ManaConstants.DUST_UNIT) ); PATTERNS_DRAWN = makeCustomStat("patterns_drawn", StatFormatter.DEFAULT); SPELLS_CAST = makeCustomStat("spells_cast", StatFormatter.DEFAULT); diff --git a/src/main/java/at/petrak/hexcasting/api/player/HexPlayerDataHelper.java b/src/main/java/at/petrak/hexcasting/api/player/HexPlayerDataHelper.java index acd7fc6b..9839e31c 100644 --- a/src/main/java/at/petrak/hexcasting/api/player/HexPlayerDataHelper.java +++ b/src/main/java/at/petrak/hexcasting/api/player/HexPlayerDataHelper.java @@ -33,7 +33,7 @@ public class HexPlayerDataHelper { public static final String TAG_FLIGHT_ALLOWED = "hexcasting:flight_allowed"; public static final String TAG_FLIGHT_TIME = "hexcasting:flight_time"; public static final String TAG_FLIGHT_ORIGIN = "hexcasting:flight_origin"; - public static final String TAG_FLIGHT_DIMENSION = "hexcasting:flight_origin"; + public static final String TAG_FLIGHT_DIMENSION = "hexcasting:flight_dimension"; public static final String TAG_FLIGHT_RADIUS = "hexcasting:flight_radius"; public static final String TAG_HARNESS = "hexcasting:spell_harness"; @@ -100,6 +100,7 @@ public class HexPlayerDataHelper { } else { tag.remove(TAG_FLIGHT_TIME); tag.remove(TAG_FLIGHT_ORIGIN); + tag.remove(TAG_FLIGHT_DIMENSION); tag.remove(TAG_FLIGHT_RADIUS); } } @@ -148,7 +149,7 @@ public class HexPlayerDataHelper { var timeLeft = tag.getInt(TAG_FLIGHT_TIME); var origin = HexUtils.DeserializeVec3FromNBT(tag.getLongArray(TAG_FLIGHT_ORIGIN)); var radius = tag.getDouble(TAG_FLIGHT_RADIUS); - var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(tag.getString(TAG_SENTINEL_DIMENSION))); + var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION))); return new FlightAbility(true, timeLeft, dimension, origin, radius); } return FlightAbility.deny(); diff --git a/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt b/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt index 65b30c1b..ddd0de65 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt @@ -14,7 +14,7 @@ interface ConstManaOperator : Operator { fun execute(args: List>, ctx: CastingContext): List> - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) @@ -24,6 +24,6 @@ interface ConstManaOperator : Operator { val sideEffects = mutableListOf(OperatorSideEffect.ConsumeMana(this.manaCost)) - return OperationResult(stack, sideEffects) + return OperationResult(stack, local, sideEffects) } } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt b/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt index 6494d92e..09845dbb 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt @@ -5,4 +5,4 @@ import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect /** * What happens when an operator is through? */ -data class OperationResult(val newStack: List>, val sideEffects: List) +data class OperationResult(val newStack: List>, val newLocalIota: SpellDatum<*>, val sideEffects: List) diff --git a/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt b/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt index 0b6abb1d..ed134a2f 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt @@ -23,7 +23,7 @@ interface Operator { * * A particle effect at the cast site and various messages and advancements are done automagically. */ - fun operate(stack: MutableList>, ctx: CastingContext): OperationResult + fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult /** * Do you need to be enlightened to use this operator? diff --git a/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt b/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt index a7949bba..d1be7c6d 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt @@ -1,10 +1,11 @@ package at.petrak.hexcasting.api.spell +import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.math.HexPattern +import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.HexUtils.serializeToNBT -import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType +import at.petrak.hexcasting.api.utils.getList import net.minecraft.ChatFormatting import net.minecraft.nbt.* import net.minecraft.network.chat.Component @@ -144,7 +145,7 @@ class SpellDatum private constructor(val payload: T) { TAG_DOUBLE -> SpellDatum(nbt.getDouble(key)) TAG_VEC3 -> SpellDatum(HexUtils.DeserializeVec3FromNBT(nbt.getLongArray(key))) TAG_LIST -> { - val arr = nbt.getList(key, Tag.TAG_COMPOUND.toInt()) + val arr = nbt.getList(key, Tag.TAG_COMPOUND) val out = ArrayList>(arr.size) for (subtag in arr) { // this is safe because otherwise we wouldn't have been able to get the list before @@ -188,7 +189,7 @@ class SpellDatum private constructor(val payload: T) { TAG_LIST -> { val out = TextComponent("[").withStyle(ChatFormatting.WHITE) - val arr = nbt.getList(key, Tag.TAG_COMPOUND.toInt()) + val arr = nbt.getList(key, Tag.TAG_COMPOUND) for ((i, subtag) in arr.withIndex()) { // this is safe because otherwise we wouldn't have been able to get the list before out.append(DisplayFromTag(subtag as CompoundTag)) @@ -259,6 +260,19 @@ class SpellDatum private constructor(val payload: T) { ValidTypes.any { clazz -> clazz.isAssignableFrom(checkee.javaClass) } } + @JvmStatic + fun GetTagName(datumType: DatumType): String { + return when (datumType) { + DatumType.ENTITY -> TAG_ENTITY + DatumType.WIDGET -> TAG_WIDGET + DatumType.LIST -> TAG_LIST + DatumType.PATTERN -> TAG_PATTERN + DatumType.DOUBLE -> TAG_DOUBLE + DatumType.VEC -> TAG_VEC3 + DatumType.OTHER, DatumType.EMPTY -> "" + } + } + } } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt b/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt index 03ed2fe5..aedfea12 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt @@ -7,30 +7,32 @@ import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs interface SpellOperator : Operator { val argc: Int - val hasCastingSound: Boolean get() = true + fun hasCastingSound(ctx: CastingContext): Boolean = true + + fun awardsCastingStat(ctx: CastingContext): Boolean = true fun execute( args: List>, ctx: CastingContext ): Triple>? - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) for (_i in 0 until this.argc) stack.removeLast() - val executeResult = this.execute(args, ctx) ?: return OperationResult(stack, listOf()) + val executeResult = this.execute(args, ctx) ?: return OperationResult(stack, local, listOf()) val (spell, mana, particles) = executeResult val sideEffects = mutableListOf( OperatorSideEffect.ConsumeMana(mana), - OperatorSideEffect.AttemptSpell(spell, this.isGreat, this.hasCastingSound) + OperatorSideEffect.AttemptSpell(spell, this.isGreat, this.hasCastingSound(ctx), this.awardsCastingStat(ctx)) ) for (spray in particles) { sideEffects.add(OperatorSideEffect.Particles(spray)) } - return OperationResult(stack, sideEffects) + return OperationResult(stack, local, sideEffects) } } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt b/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt index a28ec029..a6331c04 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt @@ -16,9 +16,12 @@ import at.petrak.hexcasting.api.spell.Widget import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.mishaps.Mishap import at.petrak.hexcasting.api.spell.mishaps.MishapDisallowedSpell +import at.petrak.hexcasting.api.spell.mishaps.MishapError import at.petrak.hexcasting.api.spell.mishaps.MishapTooManyCloseParens import at.petrak.hexcasting.api.utils.HexDamageSources import at.petrak.hexcasting.api.utils.ManaHelper +import at.petrak.hexcasting.api.utils.asCompound +import at.petrak.hexcasting.api.utils.getList import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag @@ -34,6 +37,7 @@ import kotlin.math.min */ class CastingHarness private constructor( var stack: MutableList>, + var localIota: SpellDatum<*>, var parenCount: Int, var parenthesized: List, var escapeNext: Boolean, @@ -45,7 +49,7 @@ class CastingHarness private constructor( constructor( ctx: CastingContext, prepackagedColorizer: FrozenColorizer? = null - ) : this(mutableListOf(), 0, mutableListOf(), false, ctx, prepackagedColorizer) + ) : this(mutableListOf(), SpellDatum.make(Widget.NULL), 0, mutableListOf(), false, ctx, prepackagedColorizer) /** * Given a pattern, do all the updating/side effects/etc required. @@ -81,7 +85,8 @@ class CastingHarness private constructor( if (HexConfig.Server.actionDenyList.get().contains(operatorIdPair.second.toString())) { throw MishapDisallowedSpell() } - val (stack2, sideEffectsUnmut) = operatorIdPair.first.operate(this.stack.toMutableList(), this.ctx) + val (stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(this.stack.toMutableList(), this.localIota, this.ctx) + this.localIota = local2 // Stick a poofy particle effect at the caster position val sideEffects = sideEffectsUnmut.toMutableList() if (this.ctx.spellCircle == null) @@ -108,6 +113,12 @@ class CastingHarness private constructor( this.getFunctionalData(), listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.second))), ) + } catch (exception: Exception) { + exception.printStackTrace() + return CastResult( + this.getFunctionalData(), + listOf(OperatorSideEffect.DoMishap(MishapError(exception), Mishap.Context(newPat, operatorIdPair?.second))) + ) } } @@ -274,8 +285,8 @@ class CastingHarness private constructor( } } else { val casterStack = this.ctx.caster.getItemInHand(this.ctx.castingHand) - val casterManaHolder = casterStack.getCapability(HexCapabilities.MANA).resolve() - val casterSpellHolder = casterStack.getCapability(HexCapabilities.SPELL).resolve() + val casterManaHolder = HexCapabilities.getCapability(casterStack, HexCapabilities.MANA) + val casterSpellHolder = HexCapabilities.getCapability(casterStack, HexCapabilities.SPELL) val ipsCanDrawFromInv = if (casterSpellHolder.isPresent) { if (casterManaHolder.isPresent) { val manaAvailable = casterManaHolder.get().mana @@ -340,6 +351,8 @@ class CastingHarness private constructor( stackTag.add(datum.serializeToNBT()) out.put(TAG_STACK, stackTag) + out.put(TAG_LOCAL, localIota.serializeToNBT()) + out.putInt(TAG_PAREN_COUNT, this.parenCount) out.putBoolean(TAG_ESCAPE_NEXT, this.escapeNext) @@ -358,25 +371,29 @@ class CastingHarness private constructor( companion object { const val TAG_STACK = "stack" + const val TAG_LOCAL = "local" const val TAG_PAREN_COUNT = "open_parens" const val TAG_PARENTHESIZED = "parenthesized" const val TAG_ESCAPE_NEXT = "escape_next" const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer" @JvmStatic - fun DeserializeFromNBT(nbt: Tag, ctx: CastingContext): CastingHarness { + fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness { return try { val stack = mutableListOf>() - val stackTag = (nbt as CompoundTag).getList(TAG_STACK, Tag.TAG_COMPOUND.toInt()) + val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND) for (subtag in stackTag) { - val datum = SpellDatum.DeserializeFromNBT(subtag as CompoundTag, ctx.world) + val datum = SpellDatum.DeserializeFromNBT(subtag.asCompound, ctx.world) stack.add(datum) } + val localTag = nbt.getCompound(TAG_LOCAL) + val localIota = SpellDatum.DeserializeFromNBT(localTag, ctx.world) + val parenthesized = mutableListOf() - val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND.toInt()) + val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND) for (subtag in parenTag) { - parenthesized.add(HexPattern.DeserializeFromNBT(subtag as CompoundTag)) + parenthesized.add(HexPattern.DeserializeFromNBT(subtag.asCompound)) } val parenCount = nbt.getInt(TAG_PAREN_COUNT) @@ -388,7 +405,7 @@ class CastingHarness private constructor( null } - CastingHarness(stack, parenCount, parenthesized, escapeNext, ctx, colorizer) + CastingHarness(stack, localIota, parenCount, parenthesized, escapeNext, ctx, colorizer) } catch (exn: Exception) { CastingHarness(ctx) } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/casting/OperatorSideEffect.kt b/src/main/java/at/petrak/hexcasting/api/spell/casting/OperatorSideEffect.kt index de533e50..71a0b6eb 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/casting/OperatorSideEffect.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/casting/OperatorSideEffect.kt @@ -22,7 +22,7 @@ sealed class OperatorSideEffect { abstract fun performEffect(harness: CastingHarness): Boolean /** Try to cast a spell */ - data class AttemptSpell(val spell: RenderedSpell, val isGreat: Boolean, val hasCastingSound: Boolean = true) : OperatorSideEffect() { + data class AttemptSpell(val spell: RenderedSpell, val isGreat: Boolean, val hasCastingSound: Boolean = true, val awardStat: Boolean = true) : OperatorSideEffect() { override fun performEffect(harness: CastingHarness): Boolean { return if (this.isGreat && !harness.ctx.isCasterEnlightened) { harness.ctx.caster.sendMessage( @@ -33,7 +33,8 @@ sealed class OperatorSideEffect { true } else { this.spell.cast(harness.ctx) - harness.ctx.caster.awardStat(HexStatistics.SPELLS_CAST) + if (awardStat) + harness.ctx.caster.awardStat(HexStatistics.SPELLS_CAST) false } } @@ -53,8 +54,7 @@ sealed class OperatorSideEffect { } } - data class Particles(val spray: ParticleSpray) : - OperatorSideEffect() { + data class Particles(val spray: ParticleSpray) : OperatorSideEffect() { override fun performEffect(harness: CastingHarness): Boolean { this.spray.sprayParticles(harness.ctx.world, harness.getColorizer()) diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapAlreadyBrainswept.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapAlreadyBrainswept.kt index 647ddd10..3527a804 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapAlreadyBrainswept.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapAlreadyBrainswept.kt @@ -14,7 +14,7 @@ class MishapAlreadyBrainswept(val villager: Villager) : Mishap() { dyeColor(DyeColor.GREEN) override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { - villager.hurt(HexDamageSources.OVERCAST, villager.health) + villager.hurt(HexDamageSources.overcastDamageFrom(ctx.caster), villager.health) } override fun particleSpray(ctx: CastingContext): ParticleSpray { diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBlock.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBlock.kt index 80dd1bcf..a2f6c2be 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBlock.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBlock.kt @@ -1,9 +1,9 @@ package at.petrak.hexcasting.api.spell.mishaps +import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.misc.FrozenColorizer import net.minecraft.core.BlockPos import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent @@ -16,7 +16,7 @@ class MishapBadBlock(val pos: BlockPos, val expected: Component) : Mishap() { dyeColor(DyeColor.LIME) override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { - ctx.world.explode(null, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, 2f, Explosion.BlockInteraction.NONE) + ctx.world.explode(null, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, 0.25f, Explosion.BlockInteraction.NONE) } override fun particleSpray(ctx: CastingContext): ParticleSpray { diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBrainsweep.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBrainsweep.kt index f57a59ce..2d440533 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBrainsweep.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadBrainsweep.kt @@ -1,9 +1,9 @@ package at.petrak.hexcasting.api.spell.mishaps +import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.utils.HexDamageSources import net.minecraft.core.BlockPos import net.minecraft.network.chat.Component @@ -16,7 +16,7 @@ class MishapBadBrainsweep(val villager: Villager, val pos: BlockPos) : Mishap() dyeColor(DyeColor.GREEN) override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { - villager.hurt(HexDamageSources.OVERCAST, villager.health) + villager.hurt(HexDamageSources.overcastDamageFrom(ctx.caster), villager.health) } override fun particleSpray(ctx: CastingContext): ParticleSpray { diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadItem.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadItem.kt index 2e7d8aab..cbf7568f 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadItem.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapBadItem.kt @@ -13,14 +13,14 @@ class MishapBadItem(val item: ItemEntity, val wanted: Component) : Mishap() { dyeColor(DyeColor.BROWN) override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { - item.deltaMovement = item.deltaMovement.add((Math.random() - 0.5) * 0.05, 1.0, (Math.random() - 0.5) * 0.05) + item.deltaMovement = item.deltaMovement.add((Math.random() - 0.5) * 0.05, 0.75, (Math.random() - 0.5) * 0.05) } override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component { return if (item.item.isEmpty) error("no_item", actionName(errorCtx.action), wanted) else - error("bad_item", actionName(errorCtx.action), wanted, item.item) + error("bad_item", actionName(errorCtx.action), wanted, item.item.count, item.item.displayName) } companion object { diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt new file mode 100644 index 00000000..0b9b55ff --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt @@ -0,0 +1,18 @@ +package at.petrak.hexcasting.api.spell.mishaps + +import at.petrak.hexcasting.api.misc.FrozenColorizer +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.casting.CastingContext +import net.minecraft.network.chat.Component +import net.minecraft.world.item.DyeColor + +class MishapError(val exception: Exception) : Mishap() { + override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer = + dyeColor(DyeColor.BLACK) + + override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { + } + + override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = + error("unknown", actionName(errorCtx.action), exception) +} diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt index 892c5024..1ec27261 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt @@ -1,9 +1,9 @@ package at.petrak.hexcasting.api.spell.mishaps -import at.petrak.hexcasting.api.spell.SpellDatum -import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.Widget import at.petrak.hexcasting.api.misc.FrozenColorizer +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.Widget +import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.math.HexPattern import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent @@ -53,7 +53,7 @@ class MishapInvalidIota( ItemEntity::class.java.isAssignableFrom(cls) -> "entity.item" Player::class.java.isAssignableFrom(cls) -> "entity.player" - Villager::class.java.isAssignableFrom(cls) -> "entity.player" + Villager::class.java.isAssignableFrom(cls) -> "entity.villager" LivingEntity::class.java.isAssignableFrom(cls) -> "entity.living" Entity::class.java.isAssignableFrom(cls) -> "entity" diff --git a/src/main/java/at/petrak/hexcasting/api/utils/HexDamageSources.java b/src/main/java/at/petrak/hexcasting/api/utils/HexDamageSources.java index ba0c8bb3..ed460b62 100644 --- a/src/main/java/at/petrak/hexcasting/api/utils/HexDamageSources.java +++ b/src/main/java/at/petrak/hexcasting/api/utils/HexDamageSources.java @@ -1,10 +1,19 @@ package at.petrak.hexcasting.api.utils; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.EntityDamageSource; +import net.minecraft.world.entity.Entity; public final class HexDamageSources { public static final DamageSource OVERCAST = new DamageSource("hexcasting.overcast") .bypassArmor() .bypassMagic() .setMagic(); + + public static DamageSource overcastDamageFrom(Entity cause) { + return new EntityDamageSource("hexcasting.overcast", cause) + .bypassArmor() + .bypassMagic() + .setMagic(); + } } diff --git a/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt b/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt index ac1134bd..22234e89 100644 --- a/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt +++ b/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt @@ -18,7 +18,7 @@ object HexUtils { LongArrayTag(longArrayOf(this.x.toRawBits(), this.y.toRawBits(), this.z.toRawBits())) @JvmStatic - fun DeserializeVec3FromNBT(tag: LongArray): Vec3 = + fun DeserializeVec3FromNBT(tag: LongArray): Vec3 = if (tag.size != 3) Vec3.ZERO else Vec3( Double.fromBits(tag[0]), Double.fromBits(tag[1]), @@ -30,7 +30,7 @@ object HexUtils { LongArrayTag(longArrayOf(this.x.toDouble().toRawBits(), this.y.toDouble().toRawBits())) @JvmStatic - fun DeserializeVec2FromNBT(tag: LongArray): Vec2 = + fun DeserializeVec2FromNBT(tag: LongArray): Vec2 = if (tag.size != 2) Vec2.ZERO else Vec2( Double.fromBits(tag[0]).toFloat(), Double.fromBits(tag[1]).toFloat(), diff --git a/src/main/java/at/petrak/hexcasting/api/utils/ManaHelper.kt b/src/main/java/at/petrak/hexcasting/api/utils/ManaHelper.kt index ca0244e3..d75ac01d 100644 --- a/src/main/java/at/petrak/hexcasting/api/utils/ManaHelper.kt +++ b/src/main/java/at/petrak/hexcasting/api/utils/ManaHelper.kt @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.utils import at.petrak.hexcasting.api.cap.HexCapabilities +import at.petrak.hexcasting.api.cap.ManaHolder import net.minecraft.util.Mth import net.minecraft.world.item.ItemStack import kotlin.math.roundToInt @@ -8,7 +9,7 @@ import kotlin.math.roundToInt object ManaHelper { @JvmStatic fun isManaItem(stack: ItemStack): Boolean { - return stack.getCapability(HexCapabilities.MANA).map { it.canProvide() }.orElse(false) && extractMana(stack, simulate = true) > 0 + return HexCapabilities.getCapability(stack, HexCapabilities.MANA).map(ManaHolder::canProvide).orElse(false) && extractMana(stack, simulate = true) > 0 } /** @@ -22,7 +23,7 @@ object ManaHelper { @JvmStatic @JvmOverloads fun extractMana(stack: ItemStack, cost: Int = -1, drainForBatteries: Boolean = false, simulate: Boolean = false): Int { - val manaCapability = stack.getCapability(HexCapabilities.MANA).resolve() + val manaCapability = HexCapabilities.getCapability(stack, HexCapabilities.MANA) if (!manaCapability.isPresent) return 0 @@ -39,8 +40,8 @@ object ManaHelper { * Sorted from least important to most important */ fun compare(astack: ItemStack, bstack: ItemStack): Int { - val aMana = astack.getCapability(HexCapabilities.MANA).resolve() - val bMana = bstack.getCapability(HexCapabilities.MANA).resolve() + val aMana = HexCapabilities.getCapability(astack, HexCapabilities.MANA) + val bMana = HexCapabilities.getCapability(bstack, HexCapabilities.MANA) return if (astack.item != bstack.item) { aMana.map { it.consumptionPriority }.orElse(0) - bMana.map { it.consumptionPriority }.orElse(0) diff --git a/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt b/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt new file mode 100644 index 00000000..fc5dc92d --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt @@ -0,0 +1,237 @@ +@file:JvmName("NBTHelper") +package at.petrak.hexcasting.api.utils + +import net.minecraft.nbt.* +import net.minecraft.world.item.ItemStack +import java.util.* + +private inline fun T?.getIf(key: K, predicate: T?.(K) -> Boolean, get: T.(K) -> E): E? = + getIf(key, predicate, get, null) + +private inline fun T?.getIf(key: K, predicate: T?.(K) -> Boolean, get: T.(K) -> E, default: E): E { + if (this != null && predicate(key)) + return get(key) + return default +} + +// ======================================================================================================== CompoundTag + +// Checks for containment + +fun CompoundTag?.hasNumber(key: String) = contains(key, Tag.TAG_ANY_NUMERIC) +fun CompoundTag?.hasByte(key: String) = contains(key, Tag.TAG_BYTE) +fun CompoundTag?.hasShort(key: String) = contains(key, Tag.TAG_SHORT) +fun CompoundTag?.hasInt(key: String) = contains(key, Tag.TAG_INT) +fun CompoundTag?.hasLong(key: String) = contains(key, Tag.TAG_LONG) +fun CompoundTag?.hasFloat(key: String) = contains(key, Tag.TAG_FLOAT) +fun CompoundTag?.hasDouble(key: String) = contains(key, Tag.TAG_DOUBLE) +fun CompoundTag?.hasLongArray(key: String) = contains(key, Tag.TAG_LONG_ARRAY) +fun CompoundTag?.hasIntArray(key: String) = contains(key, Tag.TAG_INT_ARRAY) +fun CompoundTag?.hasByteArray(key: String) = contains(key, Tag.TAG_BYTE_ARRAY) +fun CompoundTag?.hasCompound(key: String) = contains(key, Tag.TAG_COMPOUND) +fun CompoundTag?.hasString(key: String) = contains(key, Tag.TAG_STRING) +fun CompoundTag?.hasList(key: String) = contains(key, Tag.TAG_LIST) +fun CompoundTag?.hasList(key: String, objType: Int) = hasList(key, objType.toByte()) +fun CompoundTag?.hasList(key: String, objType: Byte) = hasList(key) && (get(key) as ListTag).elementType == objType +fun CompoundTag?.hasUUID(key: String) = this != null && hasUUID(key) + +fun CompoundTag?.contains(key: String, id: Byte) = contains(key, id.toInt()) +fun CompoundTag?.contains(key: String, id: Int) = this != null && contains(key, id) +fun CompoundTag?.contains(key: String) = this != null && contains(key) + +// Puts + +fun CompoundTag?.putBoolean(key: String, value: Boolean) = this?.putBoolean(key, value) +fun CompoundTag?.putByte(key: String, value: Byte) = this?.putByte(key, value) +fun CompoundTag?.putShort(key: String, value: Short) = this?.putShort(key, value) +fun CompoundTag?.putInt(key: String, value: Int) = this?.putInt(key, value) +fun CompoundTag?.putLong(key: String, value: Long) = this?.putLong(key, value) +fun CompoundTag?.putFloat(key: String, value: Float) = this?.putFloat(key, value) +fun CompoundTag?.putDouble(key: String, value: Double) = this?.putDouble(key, value) +fun CompoundTag?.putLongArray(key: String, value: LongArray) = this?.putLongArray(key, value) +fun CompoundTag?.putIntArray(key: String, value: IntArray) = this?.putIntArray(key, value) +fun CompoundTag?.putByteArray(key: String, value: ByteArray) = this?.putByteArray(key, value) +fun CompoundTag?.putCompound(key: String, value: CompoundTag) = put(key, value) +fun CompoundTag?.putString(key: String, value: String) = this?.putString(key, value) +fun CompoundTag?.putList(key: String, value: ListTag) = put(key, value) +fun CompoundTag?.putUUID(key: String, value: UUID) = this?.putUUID(key, value) +fun CompoundTag?.put(key: String, value: Tag) = this?.put(key, value) + +// Remove + +fun CompoundTag?.remove(key: String) = this?.remove(key) + +// Gets + +@JvmOverloads +fun CompoundTag?.getBoolean(key: String, defaultExpected: Boolean = false) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getBoolean, defaultExpected) +@JvmOverloads +fun CompoundTag?.getByte(key: String, defaultExpected: Byte = 0) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getByte, defaultExpected) +@JvmOverloads +fun CompoundTag?.getShort(key: String, defaultExpected: Short = 0) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getShort, defaultExpected) +@JvmOverloads +fun CompoundTag?.getInt(key: String, defaultExpected: Int = 0) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getInt, defaultExpected) +@JvmOverloads +fun CompoundTag?.getLong(key: String, defaultExpected: Long = 0) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getLong, defaultExpected) +@JvmOverloads +fun CompoundTag?.getFloat(key: String, defaultExpected: Float = 0f) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getFloat, defaultExpected) +@JvmOverloads +fun CompoundTag?.getDouble(key: String, defaultExpected: Double = 0.0) = getIf(key, CompoundTag?::hasNumber, CompoundTag::getDouble, defaultExpected) + +fun CompoundTag?.getLongArray(key: String) = getIf(key, CompoundTag?::hasLongArray, CompoundTag::getLongArray) +fun CompoundTag?.getIntArray(key: String) = getIf(key, CompoundTag?::hasIntArray, CompoundTag::getIntArray) +fun CompoundTag?.getByteArray(key: String) = getIf(key, CompoundTag?::hasByteArray, CompoundTag::getByteArray) +fun CompoundTag?.getCompound(key: String): CompoundTag? = getIf(key, CompoundTag?::hasCompound, CompoundTag::getCompound) +fun CompoundTag?.getString(key: String) = getIf(key, CompoundTag?::hasString, CompoundTag::getString) +fun CompoundTag?.getList(key: String, objType: Byte) = getList(key, objType.toInt()) +fun CompoundTag?.getList(key: String, objType: Int) = getIf(key, { hasList(key, objType) }) { getList(it, objType) } +fun CompoundTag?.getUUID(key: String) = getIf(key, CompoundTag?::hasUUID, CompoundTag::getUUID) +fun CompoundTag?.get(key: String) = getIf(key, CompoundTag?::contains, CompoundTag::get) + +@JvmSynthetic +@JvmName("getListByByte") +fun CompoundTag.getList(key: String, objType: Byte): ListTag = getList(key, objType.toInt()) + +// Get-or-create + +fun CompoundTag.getOrCreateCompound(key: String) = getCompound(key) ?: CompoundTag().also { putCompound(key, this) } + +// ================================================================================================================ Tag + +val Tag.asBoolean get() = asByte == 0.toByte() +val Tag.asByte get() = (this as? NumericTag)?.asByte ?: 0.toByte() +val Tag.asShort get() = (this as? NumericTag)?.asShort ?: 0.toShort() +val Tag.asInt get() = (this as? NumericTag)?.asInt ?: 0 +val Tag.asLong get() = (this as? NumericTag)?.asLong ?: 0L +val Tag.asFloat get() = (this as? NumericTag)?.asFloat ?: 0F +val Tag.asDouble get() = (this as? NumericTag)?.asDouble ?: 0.0 + +val Tag.asLongArray: LongArray + get() = when (this) { + is LongArrayTag -> this.asLongArray + is IntArrayTag -> { + val array = this.asIntArray + LongArray(array.size) { array[it].toLong() } + } + is ByteArrayTag -> { + val array = this.asByteArray + LongArray(array.size) { array[it].toLong() } + } + else -> LongArray(0) + } + +val Tag.asIntArray: IntArray + get() = when (this) { + is IntArrayTag -> this.asIntArray + is LongArrayTag -> { + val array = this.asLongArray + IntArray(array.size) { array[it].toInt() } + } + is ByteArrayTag -> { + val array = this.asByteArray + IntArray(array.size) { array[it].toInt() } + } + else -> IntArray(0) + } + +val Tag.asByteArray: ByteArray + get() = when (this) { + is ByteArrayTag -> this.asByteArray + is LongArrayTag -> { + val array = this.asLongArray + ByteArray(array.size) { array[it].toByte() } + } + is IntArrayTag -> { + val array = this.asIntArray + ByteArray(array.size) { array[it].toByte() } + } + else -> ByteArray(0) + } + +val Tag.asCompound get() = this as? CompoundTag ?: CompoundTag() +// asString is defined in Tag +val Tag.asList get() = this as? ListTag ?: ListTag() +val Tag.asUUID: UUID get() = if (this is IntArrayTag && this.size == 4) NbtUtils.loadUUID(this) else UUID(0, 0) + +// ========================================================================================================== ItemStack + +// Checks for containment + +fun ItemStack.hasNumber(key: String) = tag.hasNumber(key) +fun ItemStack.hasByte(key: String) = tag.hasByte(key) +fun ItemStack.hasShort(key: String) = tag.hasShort(key) +fun ItemStack.hasInt(key: String) = tag.hasInt(key) +fun ItemStack.hasLong(key: String) = tag.hasLong(key) +fun ItemStack.hasFloat(key: String) = tag.hasFloat(key) +fun ItemStack.hasDouble(key: String) = tag.hasDouble(key) +fun ItemStack.hasLongArray(key: String) = tag.hasLongArray(key) +fun ItemStack.hasIntArray(key: String) = tag.hasIntArray(key) +fun ItemStack.hasByteArray(key: String) = tag.hasByteArray(key) +fun ItemStack.hasCompound(key: String) = tag.hasCompound(key) +fun ItemStack.hasString(key: String) = tag.hasString(key) +fun ItemStack.hasList(key: String) = tag.hasList(key) +fun ItemStack.hasList(key: String, objType: Int) = tag.hasList(key, objType) +fun ItemStack.hasList(key: String, objType: Byte) = tag.hasList(key, objType) +fun ItemStack.hasUUID(key: String) = tag.hasUUID(key) + +@JvmName("contains") +fun ItemStack.containsTag(key: String) = tag.contains(key) +@JvmName("contains") +fun ItemStack.containsTag(key: String, id: Byte) = tag.contains(key, id) +@JvmName("contains") +fun ItemStack.containsTag(key: String, id: Int) = tag.contains(key, id) + +// Puts + +fun ItemStack.putBoolean(key: String, value: Boolean) = orCreateTag.putBoolean(key, value) +fun ItemStack.putByte(key: String, value: Byte) = orCreateTag.putByte(key, value) +fun ItemStack.putShort(key: String, value: Short) = orCreateTag.putShort(key, value) +fun ItemStack.putInt(key: String, value: Int) = orCreateTag.putInt(key, value) +fun ItemStack.putLong(key: String, value: Long) = orCreateTag.putLong(key, value) +fun ItemStack.putFloat(key: String, value: Float) = orCreateTag.putFloat(key, value) +fun ItemStack.putDouble(key: String, value: Double) = orCreateTag.putDouble(key, value) + +fun ItemStack.putLongArray(key: String, value: LongArray) = orCreateTag.putLongArray(key, value) +fun ItemStack.putIntArray(key: String, value: IntArray) = orCreateTag.putIntArray(key, value) +fun ItemStack.putByteArray(key: String, value: ByteArray) = orCreateTag.putByteArray(key, value) +fun ItemStack.putCompound(key: String, value: CompoundTag) = putTag(key, value) +fun ItemStack.putString(key: String, value: String) = orCreateTag.putString(key, value) +fun ItemStack.putList(key: String, value: ListTag) = putTag(key, value) +fun ItemStack.putUUID(key: String, value: UUID) = orCreateTag.putUUID(key, value) +@JvmName("put") +fun ItemStack.putTag(key: String, value: Tag) = orCreateTag.put(key, value) + +// Remove + +fun ItemStack.remove(key: String) = removeTagKey(key) + +// Gets + +@JvmOverloads +fun ItemStack.getBoolean(key: String, defaultExpected: Boolean = false) = tag.getBoolean(key, defaultExpected) +@JvmOverloads +fun ItemStack.getByte(key: String, defaultExpected: Byte = 0) = tag.getByte(key, defaultExpected) +@JvmOverloads +fun ItemStack.getShort(key: String, defaultExpected: Short = 0) = tag.getShort(key, defaultExpected) +@JvmOverloads +fun ItemStack.getInt(key: String, defaultExpected: Int = 0) = tag.getInt(key, defaultExpected) +@JvmOverloads +fun ItemStack.getLong(key: String, defaultExpected: Long = 0) = tag.getLong(key, defaultExpected) +@JvmOverloads +fun ItemStack.getFloat(key: String, defaultExpected: Float = 0f) = tag.getFloat(key, defaultExpected) +@JvmOverloads +fun ItemStack.getDouble(key: String, defaultExpected: Double = 0.0) = tag.getDouble(key, defaultExpected) + +fun ItemStack.getLongArray(key: String) = tag.getLongArray(key) +fun ItemStack.getIntArray(key: String) = tag.getIntArray(key) +fun ItemStack.getByteArray(key: String) = tag.getByteArray(key) +fun ItemStack.getCompound(key: String) = tag.getCompound(key) +fun ItemStack.getString(key: String) = tag.getString(key) +fun ItemStack.getList(key: String, objType: Int) = tag.getList(key, objType) +fun ItemStack.getUUID(key: String) = tag.getUUID(key) +@JvmName("get") +fun ItemStack.getTag(key: String) = tag.get(key) + +// Get-or-create + +fun ItemStack.getOrCreateCompound(key: String): CompoundTag = getOrCreateTagElement(key) diff --git a/src/main/java/at/petrak/hexcasting/client/ClientTickCounter.java b/src/main/java/at/petrak/hexcasting/client/ClientTickCounter.java index 7ca571e7..6b5ed7ae 100644 --- a/src/main/java/at/petrak/hexcasting/client/ClientTickCounter.java +++ b/src/main/java/at/petrak/hexcasting/client/ClientTickCounter.java @@ -3,16 +3,32 @@ package at.petrak.hexcasting.client; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -// I can't find a better way to do this :( public class ClientTickCounter { - private static long tickCount = 0; + public static long ticksInGame = 0L; + public static float partialTicks = 0.0F; + public static float delta = 0.0F; + public static float total = 0.0F; @SubscribeEvent - public static void onTick(TickEvent.ClientTickEvent evt) { - tickCount++; + public static void onRenderTick(TickEvent.RenderTickEvent evt) { + if (evt.phase == TickEvent.Phase.START) { + partialTicks = evt.renderTickTime; + } else { + calcDelta(); + } + } + @SubscribeEvent + public static void onTickEnd(TickEvent.ClientTickEvent evt) { + if (evt.phase == TickEvent.Phase.END) { + ++ticksInGame; + partialTicks = 0.0F; + calcDelta(); + } } - public static long getTickCount() { - return tickCount; + private static void calcDelta() { + float oldTotal = total; + total = (float)ticksInGame + partialTicks; + delta = total - oldTotal; } } diff --git a/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java b/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java index 77ddf616..92e5c6e6 100644 --- a/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java +++ b/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java @@ -1,30 +1,37 @@ package at.petrak.hexcasting.client; import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry; +import at.petrak.hexcasting.api.player.HexPlayerDataHelper; import at.petrak.hexcasting.api.player.Sentinel; import at.petrak.hexcasting.common.items.HexItems; -import at.petrak.hexcasting.api.player.HexPlayerDataHelper; +import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.locale.Language; +import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Style; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderLevelLastEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; +import java.util.List; import java.util.function.BiConsumer; public class HexAdditionalRenderers { @@ -42,7 +49,7 @@ public class HexAdditionalRenderers { @SubscribeEvent public static void overlayGui(RenderGameOverlayEvent.Post evt) { if (evt.getType() == RenderGameOverlayEvent.ElementType.ALL) { - tryRenderScryingLensOverlay(evt.getMatrixStack(), evt.getPartialTicks()); + tryRenderScryingLensOverlay(evt.getMatrixStack()); } } @@ -59,7 +66,7 @@ public class HexAdditionalRenderers { sentinel.position().y - playerPos.y, sentinel.position().z - playerPos.z); - var time = mc.level.getLevelData().getGameTime() + partialTicks; + var time = ClientTickCounter.total / 2; var bobSpeed = 1f / 20; var magnitude = 0.1f; ps.translate(0, Mth.sin(bobSpeed * time) * magnitude, 0); @@ -148,19 +155,24 @@ public class HexAdditionalRenderers { // My internet is really shaky right now but thank god Patchi already does this exact thing // cause it's a dependency so i have the .class files downloaded - private static void tryRenderScryingLensOverlay(PoseStack ps, float partialTicks) { + private static void tryRenderScryingLensOverlay(PoseStack ps) { var mc = Minecraft.getInstance(); + LocalPlayer player = mc.player; + ClientLevel level = mc.level; + if (player == null || level == null) + return; + boolean foundLens = false; InteractionHand lensHand = null; for (var hand : InteractionHand.values()) { - if (mc.player.getItemInHand(hand).is(HexItems.SCRYING_LENS.get())) { + if (player.getItemInHand(hand).is(HexItems.SCRYING_LENS.get())) { lensHand = hand; foundLens = true; break; } } - if (!foundLens && mc.player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS.get())) { + if (!foundLens && player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS.get())) { foundLens = true; } @@ -169,38 +181,55 @@ public class HexAdditionalRenderers { } var hitRes = mc.hitResult; - if (hitRes instanceof BlockHitResult bhr) { + if (hitRes != null && hitRes.getType() == HitResult.Type.BLOCK) { + var bhr = (BlockHitResult) hitRes; var pos = bhr.getBlockPos(); - var bs = mc.level.getBlockState(pos); + var bs = level.getBlockState(pos); - var lines = ScryingLensOverlayRegistry.getLines(bs, pos, mc.player, mc.level, lensHand); - if (lines != null) { - var window = mc.getWindow(); + var lines = ScryingLensOverlayRegistry.getLines(bs, pos, player, level, bhr.getDirection(), lensHand); + + int totalHeight = 8; + List>> actualLines = Lists.newArrayList(); + + var window = mc.getWindow(); + var maxWidth = (int) (window.getGuiScaledWidth() / 2f * 0.8f); + + for (var pair : lines) { + totalHeight += mc.font.lineHeight + 6; + var text = pair.getSecond(); + var textLines = mc.font.getSplitter().splitLines(text, maxWidth, Style.EMPTY); + + actualLines.add(Pair.of(pair.getFirst(), textLines)); + + if (textLines.size() > 1) { + totalHeight += mc.font.lineHeight * (textLines.size() - 1); + } + } + + if (!lines.isEmpty()) { var x = window.getGuiScaledWidth() / 2f + 8f; - var y = window.getGuiScaledHeight() / 2f; + var y = window.getGuiScaledHeight() / 2f - totalHeight; ps.pushPose(); ps.translate(x, y, 0); - var maxWidth = (int) (window.getGuiScaledWidth() / 2f * 0.8f); - - for (var pair : lines) { - + for (var pair : actualLines) { var stack = pair.getFirst(); - if (stack != null) { + if (!stack.isEmpty()) { // this draws centered in the Y ... RenderLib.renderItemStackInGui(ps, pair.getFirst(), 0, 0); } - float tx = stack == null ? 0 : 18; + float tx = stack.isEmpty() ? 0 : 18; float ty = 5; // but this draws where y=0 is the baseline var text = pair.getSecond(); - var textLines = mc.font.getSplitter().splitLines(text, maxWidth, Style.EMPTY); - for (var line : textLines) { + for (var line : text) { var actualLine = Language.getInstance().getVisualOrder(line); mc.font.drawShadow(ps, actualLine, tx, ty, 0xffffffff); - ps.translate(0, 9, 0); + ps.translate(0, mc.font.lineHeight, 0); } + if (text.isEmpty()) + ps.translate(0, mc.font.lineHeight, 0); ps.translate(0, 6, 0); } diff --git a/src/main/java/at/petrak/hexcasting/client/HexTooltips.java b/src/main/java/at/petrak/hexcasting/client/HexTooltips.java index 5dc70ad2..513e24da 100644 --- a/src/main/java/at/petrak/hexcasting/client/HexTooltips.java +++ b/src/main/java/at/petrak/hexcasting/client/HexTooltips.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.client; +import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.client.gui.PatternTooltipGreeble; import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; import at.petrak.hexcasting.common.items.HexItems; @@ -8,6 +9,7 @@ import at.petrak.hexcasting.common.items.ItemSlate; import at.petrak.hexcasting.api.spell.math.HexPattern; import com.mojang.datafixers.util.Either; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemStack; @@ -35,23 +37,22 @@ public class HexTooltips { ItemStack stack = evt.getItemStack(); if (!stack.isEmpty()) { if (stack.is(HexItems.SCROLL.get())) { - var tag = stack.getOrCreateTag(); - if (tag.contains(ItemScroll.TAG_PATTERN, Tag.TAG_COMPOUND)) { - var pattern = HexPattern.DeserializeFromNBT(tag.getCompound(ItemScroll.TAG_PATTERN)); + CompoundTag patternTag = NBTHelper.getCompound(stack, ItemScroll.TAG_PATTERN); + if (patternTag != null) { + var pattern = HexPattern.DeserializeFromNBT(patternTag); evt.getTooltipElements().add(Either.right(new PatternTooltipGreeble( pattern, - tag.contains(ItemScroll.TAG_OP_ID, Tag.TAG_STRING) + NBTHelper.contains(stack, ItemScroll.TAG_OP_ID, Tag.TAG_STRING) ? PatternTooltipGreeble.ANCIENT_BG : PatternTooltipGreeble.PRISTINE_BG))); } } else if (stack.is(HexItems.SLATE.get()) && ItemSlate.hasPattern(stack)) { - var tag = stack.getOrCreateTag() - .getCompound("BlockEntityTag") - .getCompound(BlockEntitySlate.TAG_PATTERN); - var pattern = HexPattern.DeserializeFromNBT(tag); - evt.getTooltipElements().add(Either.right(new PatternTooltipGreeble( - pattern, - PatternTooltipGreeble.SLATE_BG))); - + var tag = NBTHelper.getCompound(NBTHelper.getOrCreateCompound(stack, "BlockEntityTag"), BlockEntitySlate.TAG_PATTERN); + if (tag != null) { + var pattern = HexPattern.DeserializeFromNBT(tag); + evt.getTooltipElements().add(Either.right(new PatternTooltipGreeble( + pattern, + PatternTooltipGreeble.SLATE_BG))); + } } } } diff --git a/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java b/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java index 88ddada6..3c723880 100644 --- a/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java +++ b/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java @@ -5,9 +5,10 @@ import at.petrak.hexcasting.api.circle.BlockEntityAbstractImpetus; import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry; import at.petrak.hexcasting.api.item.DataHolderItem; import at.petrak.hexcasting.api.item.ManaHolderItem; -import at.petrak.hexcasting.api.mod.HexConfig; +import at.petrak.hexcasting.api.misc.ManaConstants; import at.petrak.hexcasting.api.spell.SpellDatum; import at.petrak.hexcasting.api.spell.Widget; +import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.client.be.BlockEntityAkashicBookshelfRenderer; import at.petrak.hexcasting.client.be.BlockEntitySlateRenderer; import at.petrak.hexcasting.client.entity.WallScrollRenderer; @@ -28,64 +29,39 @@ import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRenderers; import net.minecraft.client.renderer.item.ItemProperties; -import net.minecraft.network.chat.Component; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.util.Mth; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.ComparatorBlock; -import net.minecraft.world.level.block.RepeaterBlock; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.properties.ComparatorMode; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.level.material.MaterialColor; import net.minecraftforge.client.event.EntityRenderersEvent; import net.minecraftforge.client.event.ParticleFactoryRegisterEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; +import java.util.function.UnaryOperator; public class RegisterClientStuff { @SubscribeEvent public static void init(FMLClientSetupEvent evt) { evt.enqueueWork(() -> { - for (DataHolderItem dataHolder : new DataHolderItem[]{ HexItems.FOCUS.get(), HexItems.SPELLBOOK.get() }) { - ItemProperties.register((Item) dataHolder, ItemFocus.DATATYPE_PRED, - (stack, level, holder, holderID) -> { - var datum = dataHolder.readDatumTag(stack); - if (datum != null) { - var typename = datum.getAllKeys().iterator().next(); - return switch (typename) { - case SpellDatum.TAG_ENTITY -> 1f; - case SpellDatum.TAG_DOUBLE -> 2f; - case SpellDatum.TAG_VEC3 -> 3f; - case SpellDatum.TAG_WIDGET -> 4f; - case SpellDatum.TAG_LIST -> 5f; - case SpellDatum.TAG_PATTERN -> 6f; - default -> 0f; // uh oh - }; - } - return 0f; - }); - ItemProperties.register((Item) dataHolder, ItemFocus.SEALED_PRED, - (stack, level, holder, holderID) -> dataHolder.canWrite(stack, SpellDatum.make(Widget.NULL)) ? 0f : 1f); - } - for (ItemPackagedSpell packager : new ItemPackagedSpell[]{ - HexItems.CYPHER.get(), - HexItems.TRINKET.get(), - HexItems.ARTIFACT.get(), - }) { - ItemProperties.register(packager, ItemPackagedSpell.HAS_PATTERNS_PRED, - (stack, level, holder, holderID) -> - packager.getPatterns(stack) != null ? 1f : 0f - ); - } + registerDataHolderOverrides(HexItems.FOCUS.get()); + registerDataHolderOverrides(HexItems.SPELLBOOK.get()); + + registerPackagedSpellOverrides(HexItems.CYPHER.get()); + registerPackagedSpellOverrides(HexItems.TRINKET.get()); + registerPackagedSpellOverrides(HexItems.ARTIFACT.get()); ItemProperties.register(HexItems.BATTERY.get(), ItemManaBattery.MANA_PREDICATE, (stack, level, holder, holderID) -> { @@ -96,58 +72,35 @@ public class RegisterClientStuff { (stack, level, holder, holderID) -> { var item = (ItemManaBattery) stack.getItem(); var max = item.getMaxMana(stack); - return (float) Math.sqrt((float) max / HexConfig.chargedCrystalManaAmount.get() / 10); + return (float) Math.sqrt((float) max / ManaConstants.CRYSTAL_UNIT / 10); }); ItemProperties.register(HexItems.SCROLL.get(), ItemScroll.ANCIENT_PREDICATE, - (stack, level, holder, holderID) -> stack.getOrCreateTag().contains(ItemScroll.TAG_OP_ID) ? 1f : 0f); + (stack, level, holder, holderID) -> NBTHelper.hasString(stack, ItemScroll.TAG_OP_ID) ? 1f : 0f); ItemProperties.register(HexItems.SLATE.get(), ItemSlate.WRITTEN_PRED, (stack, level, holder, holderID) -> ItemSlate.hasPattern(stack) ? 1f : 0f); - var wands = new Item[]{ - HexItems.WAND_OAK.get(), - HexItems.WAND_BIRCH.get(), - HexItems.WAND_SPRUCE.get(), - HexItems.WAND_JUNGLE.get(), - HexItems.WAND_DARK_OAK.get(), - HexItems.WAND_ACACIA.get(), - HexItems.WAND_AKASHIC.get(), - }; - for (var wand : wands) { - ItemProperties.register(wand, ItemWand.FUNNY_LEVEL_PREDICATE, - (stack, level, holder, holderID) -> { - var name = stack.getHoverName().getString().toLowerCase(Locale.ROOT); - if (name.contains("old")) { - return 1f; - } else if (name.contains("wand of the forest")) { - return 2f; - } else { - return 0f; - } - }); - } + registerWandOverrides(HexItems.WAND_OAK.get()); + registerWandOverrides(HexItems.WAND_BIRCH.get()); + registerWandOverrides(HexItems.WAND_SPRUCE.get()); + registerWandOverrides(HexItems.WAND_JUNGLE.get()); + registerWandOverrides(HexItems.WAND_DARK_OAK.get()); + registerWandOverrides(HexItems.WAND_ACACIA.get()); + registerWandOverrides(HexItems.WAND_AKASHIC.get()); HexTooltips.init(); }); - for (var cutout : new Block[]{ - HexBlocks.CONJURED_LIGHT.get(), - HexBlocks.CONJURED_BLOCK.get(), - HexBlocks.AKASHIC_DOOR.get(), - HexBlocks.AKASHIC_TRAPDOOR.get(), - HexBlocks.SCONCE.get(), - }) { - ItemBlockRenderTypes.setRenderLayer(cutout, RenderType.cutout()); - } + ItemBlockRenderTypes.setRenderLayer(HexBlocks.CONJURED_LIGHT.get(), RenderType.cutout()); + ItemBlockRenderTypes.setRenderLayer(HexBlocks.CONJURED_BLOCK.get(), RenderType.cutout()); + ItemBlockRenderTypes.setRenderLayer(HexBlocks.AKASHIC_DOOR.get(), RenderType.cutout()); + ItemBlockRenderTypes.setRenderLayer(HexBlocks.AKASHIC_TRAPDOOR.get(), RenderType.cutout()); + ItemBlockRenderTypes.setRenderLayer(HexBlocks.SCONCE.get(), RenderType.cutout()); - for (var mipped : new Block[]{ - HexBlocks.AKASHIC_LEAVES1.get(), - HexBlocks.AKASHIC_LEAVES2.get(), - HexBlocks.AKASHIC_LEAVES3.get(), - }) { - ItemBlockRenderTypes.setRenderLayer(mipped, RenderType.cutoutMipped()); - } + ItemBlockRenderTypes.setRenderLayer(HexBlocks.AKASHIC_LEAVES1.get(), RenderType.cutoutMipped()); + ItemBlockRenderTypes.setRenderLayer(HexBlocks.AKASHIC_LEAVES2.get(), RenderType.cutoutMipped()); + ItemBlockRenderTypes.setRenderLayer(HexBlocks.AKASHIC_LEAVES3.get(), RenderType.cutoutMipped()); ItemBlockRenderTypes.setRenderLayer(HexBlocks.AKASHIC_RECORD.get(), RenderType.translucent()); @@ -158,81 +111,188 @@ public class RegisterClientStuff { private static void addScryingLensStuff() { ScryingLensOverlayRegistry.addPredicateDisplayer( - (state, pos, observer, world, lensHand) -> state.getBlock() instanceof BlockAbstractImpetus, - (state, pos, observer, world, lensHand) -> { + (state, pos, observer, world, direction, lensHand) -> state.getBlock() instanceof BlockAbstractImpetus, + (lines, state, pos, observer, world, direction, lensHand) -> { if (world.getBlockEntity(pos) instanceof BlockEntityAbstractImpetus beai) { - return beai.getScryingLensOverlay(state, pos, observer, world, lensHand); - } else { - return List.of(); + beai.applyScryingLensOverlay(lines, state, pos, observer, world, direction, lensHand); } }); + ScryingLensOverlayRegistry.addDisplayer(Blocks.NOTE_BLOCK, + (lines, state, pos, observer, world, direction, lensHand) -> { + int note = state.getValue(NoteBlock.NOTE); + + float rCol = Math.max(0.0F, Mth.sin((note / 24F + 0.0F) * Mth.TWO_PI) * 0.65F + 0.35F); + float gCol = Math.max(0.0F, Mth.sin((note / 24F + 0.33333334F) * Mth.TWO_PI) * 0.65F + 0.35F); + float bCol = Math.max(0.0F, Mth.sin((note / 24F + 0.6666667F) * Mth.TWO_PI) * 0.65F + 0.35F); + + int noteColor = 0xFF_000000 | Mth.color(rCol, gCol, bCol); + + var instrument = state.getValue(NoteBlock.INSTRUMENT); + + lines.add(new Pair<>( + new ItemStack(Items.MUSIC_DISC_CHIRP), + new TextComponent(String.valueOf(instrument.ordinal())) + .withStyle(color(instrumentColor(instrument))))); + lines.add(new Pair<>( + new ItemStack(Items.NOTE_BLOCK), + new TextComponent(String.valueOf(note)) + .withStyle(color(noteColor)))); + }); + ScryingLensOverlayRegistry.addDisplayer(HexBlocks.AKASHIC_BOOKSHELF.get(), - (state, pos, observer, world, lensHand) -> { - if (!(world.getBlockEntity(pos) instanceof BlockEntityAkashicBookshelf tile)) { - return List.of(); - } - - var out = new ArrayList>(); - - var recordPos = tile.getRecordPos(); - var pattern = tile.getPattern(); - if (recordPos != null && pattern != null) { - out.add(new Pair<>(new ItemStack(HexBlocks.AKASHIC_RECORD.get()), new TranslatableComponent( - "hexcasting.tooltip.lens.akashic.bookshelf.location", - recordPos.toShortString() - ))); - if (world.getBlockEntity(recordPos) instanceof BlockEntityAkashicRecord record) { - out.add(new Pair<>(new ItemStack(Items.BOOK), record.getDisplayAt(pattern))); + (lines, state, pos, observer, world, direction, lensHand) -> { + if (world.getBlockEntity(pos) instanceof BlockEntityAkashicBookshelf tile) { + var recordPos = tile.getRecordPos(); + var pattern = tile.getPattern(); + if (recordPos != null && pattern != null) { + lines.add(new Pair<>(new ItemStack(HexBlocks.AKASHIC_RECORD.get()), new TranslatableComponent( + "hexcasting.tooltip.lens.akashic.bookshelf.location", + recordPos.toShortString() + ))); + if (world.getBlockEntity(recordPos) instanceof BlockEntityAkashicRecord record) { + lines.add(new Pair<>(new ItemStack(Items.BOOK), record.getDisplayAt(pattern))); + } } } - - return out; }); + ScryingLensOverlayRegistry.addDisplayer(HexBlocks.AKASHIC_RECORD.get(), - ((state, pos, observer, world, lensHand) -> { - if (!(world.getBlockEntity(pos) instanceof BlockEntityAkashicRecord tile)) { - return List.of(); + (lines, state, pos, observer, world, direction, lensHand) -> { + if (world.getBlockEntity(pos) instanceof BlockEntityAkashicRecord tile) { + int count = tile.getCount(); + + lines.add(new Pair<>(new ItemStack(HexBlocks.AKASHIC_BOOKSHELF.get()), new TranslatableComponent( + "hexcasting.tooltip.lens.akashic.record.count" + (count == 1 ? ".single" : ""), + count + ))); } - - int count = tile.getCount(); - - return List.of(new Pair<>(new ItemStack(HexBlocks.AKASHIC_BOOKSHELF.get()), new TranslatableComponent( - "hexcasting.tooltip.lens.akashic.record.count" + (count == 1 ? ".single" : ""), - count - ))); - })); - - ScryingLensOverlayRegistry.addDisplayer(Blocks.REDSTONE_WIRE, - (state, pos, observer, world, lensHand) -> List.of( - new Pair<>( - new ItemStack(Items.REDSTONE), - new TextComponent(String.valueOf(state.getValue(BlockStateProperties.POWER))) - .withStyle(ChatFormatting.RED)) - )); + }); ScryingLensOverlayRegistry.addDisplayer(Blocks.COMPARATOR, - (state, pos, observer, world, lensHand) -> List.of( - new Pair<>( + (lines, state, pos, observer, world, direction, lensHand) -> { + int comparatorValue = ScryingLensOverlayRegistry.getComparatorValue(true); + lines.add(new Pair<>( new ItemStack(Items.REDSTONE), - new TextComponent(String.valueOf(state.getDirectSignal(world, pos, state.getValue(BlockStateProperties.HORIZONTAL_FACING)))) - .withStyle(ChatFormatting.RED)), - new Pair<>( + new TextComponent(comparatorValue == -1 ? "" : String.valueOf(comparatorValue)) + .withStyle(redstoneColor(comparatorValue)))); + + boolean compare = state.getValue(ComparatorBlock.MODE) == ComparatorMode.COMPARE; + + lines.add(new Pair<>( new ItemStack(Items.REDSTONE_TORCH), new TextComponent( - state.getValue(ComparatorBlock.MODE) == ComparatorMode.COMPARE ? ">" : "-") - .withStyle(ChatFormatting.RED)))); + compare ? ">=" : "-") + .withStyle(redstoneColor(compare ? 0 : 15)))); + }); ScryingLensOverlayRegistry.addDisplayer(Blocks.REPEATER, - (state, pos, observer, world, lensHand) -> List.of( - new Pair<>( + (lines, state, pos, observer, world, direction, lensHand) -> lines.add(new Pair<>( + new ItemStack(Items.CLOCK), + new TextComponent(String.valueOf(state.getValue(RepeaterBlock.DELAY))) + .withStyle(ChatFormatting.YELLOW)))); + + ScryingLensOverlayRegistry.addPredicateDisplayer( + (state, pos, observer, world, direction, lensHand) -> state.isSignalSource() && !state.is(Blocks.COMPARATOR), + (lines, state, pos, observer, world, direction, lensHand) -> { + int signalStrength = 0; + if (state.getBlock() instanceof RedStoneWireBlock) + signalStrength = state.getValue(RedStoneWireBlock.POWER); + else { + for (Direction dir : Direction.values()) + signalStrength = Math.max(signalStrength, state.getSignal(world, pos, dir)); + } + + lines.add(0, new Pair<>( new ItemStack(Items.REDSTONE), - new TextComponent(String.valueOf(state.getValue(RepeaterBlock.POWERED) ? 15 : 0)) - .withStyle(ChatFormatting.RED)), - new Pair<>( - new ItemStack(Items.CLOCK), - new TextComponent(String.valueOf(state.getValue(RepeaterBlock.DELAY))) - .withStyle(ChatFormatting.YELLOW)))); + new TextComponent(String.valueOf(signalStrength)) + .withStyle(redstoneColor(signalStrength)))); + }); + + ScryingLensOverlayRegistry.addPredicateDisplayer( + (state, pos, observer, world, direction, lensHand) -> state.hasAnalogOutputSignal(), + (lines, state, pos, observer, world, direction, lensHand) -> { + int comparatorValue = ScryingLensOverlayRegistry.getComparatorValue(false); + lines.add( + new Pair<>( + new ItemStack(Items.COMPARATOR), + new TextComponent(comparatorValue == -1 ? "" : String.valueOf(comparatorValue)) + .withStyle(redstoneColor(comparatorValue)))); + }); + } + + private static UnaryOperator