diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 4cd1fe88c..66d7109fd 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ -patreon: srendi +ko_fi: srendi +github: SirEndii \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dde6f4283..425e8ab82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +For now, just a prototype changelog so I don't need to remember/search everything I did +### Added +- NBT Hashes for filters and item/fluid properties. Lightweight version of the fingerprints, cc also uses nbt hashes for everything nbt related + ## [1.19.2-0.7.37r] - 2024-10-06 ### Added diff --git a/README.md b/README.md index 74d5d8a3e..78c94213d 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ will close pull requests related to translations. [CurseForge]: https://www.curseforge.com/minecraft/mc-mods/advanced-peripherals [Actions]: https://github.com/Seniorendi/AdvancedPeripherals/actions [Crowdin]: https://crowdin.com/project/advanced-peripherals -[Discord]: https://discord.com/invite/QuF3hWDtWC +[Discord]: https://discord.intelligence-modding.de [Banner]: https://www.bisecthosting.com/images/CF/Advanced_Peripherals/BH_AP_Header.png 'Advanced Peripherals' [PeripheralsPlusOne]: https://github.com/rolandoislas/PeripheralsPlusOne diff --git a/build.gradle b/build.gradle index 4d6f7d61c..5cbf98fa4 100644 --- a/build.gradle +++ b/build.gradle @@ -3,17 +3,17 @@ import net.darkhax.curseforgegradle.TaskPublishCurseForge import java.text.SimpleDateFormat plugins { - id "maven-publish" + id 'checkstyle' + id 'com.github.breadmoirai.github-release' version '2.5.2' + id 'com.modrinth.minotaur' version '2.+' + id 'java' + id 'maven-publish' id 'net.darkhax.curseforgegradle' version '1.1.16' - id 'org.jetbrains.changelog' version '1.2.1' - id "com.modrinth.minotaur" version "2.+" - id "org.jetbrains.kotlin.jvm" version "1.6.10" id 'net.minecraftforge.gradle' version '[6.0.18,6.2)' + id 'org.jetbrains.changelog' version '1.2.1' + id 'org.jetbrains.kotlin.jvm' version '1.6.10' id 'org.parchmentmc.librarian.forgegradle' version '1.+' id 'org.spongepowered.mixin' version '0.7.+' - id "com.github.breadmoirai.github-release" version "2.5.2" - id 'checkstyle' - id 'java' } java { @@ -201,20 +201,18 @@ repositories { } } maven { - name = "Modmaven Jei" + name = "Modmaven" url = 'https://modmaven.dev/' content { - includeGroup("mezz.jei") includeGroup("appeng") includeGroup("mekanism") + includeGroup("mezz.jei") } } maven { name = "Create maven" url = "https://maven.tterrag.com/" content { - includeGroup("com.simibubi.create") - includeGroup("com.jozufozu.flywheel") includeGroup("com.tterrag.registrate") } } @@ -246,7 +244,17 @@ repositories { maven { url = "https://cursemaven.com" content { - includeGroup "curse.maven" + includeGroup("curse.maven") + } + } + maven { + url = "https://maven.valkyrienskies.org" + content { + includeGroup("org.valkyrienskies") + includeGroup("org.valkyrienskies.core") + includeGroup("com.github.LlamaLad7") + includeGroup("com.github.Rubydesic") + includeGroup("org.mapstruct") } } } @@ -313,23 +321,29 @@ dependencies { compileOnly fg.deobf("com.ldtteam:multipiston:${multipiston_version}") compileOnly fg.deobf("com.ldtteam:domum_ornamentum:${domumornamentum_version}:universal") compileOnly fg.deobf("com.ldtteam:blockui:${blockui_version}") - // IMPORTANT. This should be removed/uncommented when running `runData` - runtimeOnly fg.deobf("com.ldtteam:minecolonies:${minecolonies_version}") - runtimeOnly fg.deobf("com.ldtteam:structurize:${structurize_version}") - runtimeOnly fg.deobf("com.ldtteam:multipiston:${multipiston_version}") - runtimeOnly fg.deobf("com.ldtteam:domum_ornamentum:${domumornamentum_version}:universal") - runtimeOnly fg.deobf("com.ldtteam:blockui:${blockui_version}") - - //Patchouli + // IMPORTANT. This should be removed/commented when running `runData` + // Automated now, tho if you are not executing runData directly it's no help + if (!project.gradle.startParameter.taskNames.contains("runData")) { + runtimeOnly fg.deobf("com.ldtteam:minecolonies:${minecolonies_version}") + runtimeOnly fg.deobf("com.ldtteam:structurize:${structurize_version}") + runtimeOnly fg.deobf("com.ldtteam:multipiston:${multipiston_version}") + runtimeOnly fg.deobf("com.ldtteam:domum_ornamentum:${domumornamentum_version}:universal") + runtimeOnly fg.deobf("com.ldtteam:blockui:${blockui_version}") + } + + // Patchouli compileOnly fg.deobf("vazkii.patchouli:Patchouli:${patchouli_version}") runtimeOnly fg.deobf("vazkii.patchouli:Patchouli:${patchouli_version}") // Create - compileOnly fg.deobf("com.simibubi.create:create-${minecraft_version}:${create_version}:all") - runtimeOnly fg.deobf("com.simibubi.create:create-${minecraft_version}:${create_version}:all") + compileOnly fg.deobf("curse.maven:create-328085:${create_version}") + runtimeOnly fg.deobf("curse.maven:create-328085:${create_version}") - //Removed until fully ported - //testImplementation fg.deobf("site.siredvin.ttoolkit:ttoolkit-${minecraft_version}:${ttoolkit_version}") + // DimStorage + compileOnly fg.deobf("curse.maven:dimstorage-353882:${dimstorage_version}") + compileOnly fg.deobf("curse.maven:edivadlib-638508:${edivadlib_version}") + // runtimeOnly fg.deobf("curse.maven:dimstorage-353882:${dimstorage_version}") + // runtimeOnly fg.deobf("curse.maven:edivadlib-638508:${edivadlib_version}") //Powah compileOnly fg.deobf("curse.maven:powah-633483:${powah_version}") @@ -337,7 +351,7 @@ dependencies { runtimeOnly fg.deobf("me.shedaniel.cloth:cloth-config-forge:8.2.88") runtimeOnly fg.deobf("dev.architectury:architectury-forge:6.2.43") - // Crash utilities. Used to debug the chunky turtle. Can be uncommented if not needed + // Crash utilities. Used to debug the chunky turtle. Can be commented if not needed runtimeOnly fg.deobf("curse.maven:crash-utilities-371813:4406293") testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_version}" @@ -352,9 +366,30 @@ dependencies { // JEI implementation fg.deobf("mezz.jei:jei-${jei_version}") + // Jade + implementation fg.deobf("curse.maven:jade-324717:${jade_version}") + // Create Crafts & Additions compileOnly fg.deobf("curse.maven:createaddition-439890:5099757") // runtimeOnly fg.deobf("curse.maven:createaddition-439890:5099757") + + // Valkyrien Skies 2 + compileOnly("org.joml:joml:1.10.4") + compileOnly("org.joml:joml-primitives:1.10.0") + // compileOnly fg.deobf("org.valkyrienskies:valkyrienskies-119-common:${vs2_version}") + compileOnly fg.deobf("org.valkyrienskies:valkyrienskies-119-forge:${vs2_version}") { + transitive = false + } + compileOnly "org.valkyrienskies.core:api:${vs_core_version}" + compileOnly "org.valkyrienskies.core:api-game:${vs_core_version}" + compileOnly "org.valkyrienskies.core:util:${vs_core_version}" + compileOnly "org.valkyrienskies.core:impl:${vs_core_version}" + runtimeOnly fg.deobf("org.valkyrienskies:valkyrienskies-119-forge:${vs2_version}") { + transitive = false + } + runtimeOnly fg.deobf("curse.maven:valkyrien-skies-258371:${valkyrien_skies_version}") + runtimeOnly fg.deobf("curse.maven:eureka-ships-654384:${eureka_ships_version}") + runtimeOnly fg.deobf("curse.maven:clockwork-807792:${clockwork_version}") } @@ -389,12 +424,12 @@ task setupServer(type: Copy) { } ["Client", "Server"].forEach { name -> - tasks.register("test$name", JavaExec.class).configure { + tasks.register("test${name}", JavaExec.class).configure { it.group('In-game tests') it.description("Runs tests on a temporary Minecraft instance.") - it.dependsOn(setupServer, "prepareRunTest$name", "cleanTest$name", 'compileTestModJava') + it.dependsOn(setupServer, "prepareRunTest${name}", "cleanTest${name}", 'compileTestModJava') - JavaExec exec = tasks.getByName("runTest$name") + JavaExec exec = tasks.getByName("runTest${name}") exec.copyTo(it) it.setClasspath(exec.getClasspath()) it.mainClass = exec.mainClass @@ -433,6 +468,8 @@ jar { jar.finalizedBy('reobfJar') +compileKotlin.enabled = false + tasks.withType(Checkstyle) { reports { xml.required = false diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 7ca06cbc2..a379e1d45 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -37,7 +37,6 @@ - diff --git a/gradle.properties b/gradle.properties index 6b4647d35..b4e3848fa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -org.gradle.jvmargs=-Xmx4G org.gradle.daemon=false +org.gradle.jvmargs=-Xmx4G org.gradle.logging.level=info # Minecraft related @@ -7,46 +7,61 @@ mod_id=advancedperipherals # do not include mod_version/minecraft_version with equals sign anywhere else in the file (even in comments) # also do not add space around the equal sign # since we are using poor grep command to do automation :p -mod_version=0.7.38r +mod_version=0.8r minecraft_version=1.19.2 mod_artifact_suffix= -forge_version=43.3.8 + +forge_version=43.5.0 loader_version=43 + release_type=release + mappings_channel=parchment -mappings_version=2022.11.27-1.19.2 -jb_annotations=21.0.1 +mappings_version=2022.11.20-1.19.2 # Test dependencies -junit_version=5.7.2 hamcrest_version=2.2 +jb_annotations=21.0.1 +junit_version=5.7.2 kotlin_version=1.8.0 -kotlinx_coroutines_version=1.6.0-RC3 +kotlinx_coroutines_version=1.7.3 ttoolkit_version=0.1.3 # Mod dependencies cc_version=1.101.3 -curios_version=1.19.2-5.1.4.1 -minecolonies_version=1.19.2-1.1.473-BETA -appliedenergistics_version=12.9.5 -patchouli_version=1.19.2-77 -refinedstorage_version=1.11.6 + +ae2additions_version=4646599 +ae2things_version=4367610 +appliedenergistics_version=12.9.12 +appliedmekanistics_version=4734608 botania_version=1.19.2-440-FORGE -create_version=0.5.1.f-46 +clockwork_version=5171528 +#v0.5.1 +create_version=5797604 createca_version=5099757 +curios_version=1.19.2-5.1.4.1 +dimstorage_version=3927875 +eureka_ships_version=5321628 +kotlinforforge_version=3.12.0 mekanism_version=1.19.2-10.3.9.13 -ae2things_version=4367610 +minecolonies_version=1.19.2-1.1.473-BETA +patchouli_version=1.19.2-77 powah_version=4183078 -ae2additions_version=4646599 -kotlinforforge_version=3.12.0 -appliedmekanistics_version=4734608 +refinedstorage_version=1.11.7 +valkyrien_skies_version=4994898 +vs2_version=2.1.2-beta.1+a04911c932 +vs_core_version=1.1.0+2a62e6a823 # Mod dependencies which are needed for other mods # For minecolonies -structurize_version=1.19.2-1.0.649-BETA -multipiston_version=1.19.2-1.2.21-ALPHA blockui_version=1.19.2-0.0.102-ALPHA domumornamentum_version=1.19-1.0.141-BETA +multipiston_version=1.19.2-1.2.21-ALPHA +structurize_version=1.19.2-1.0.649-BETA + +# For DimStorage +edivadlib_version=3927847 -# Mod dependencies for testing stuff(Only used in the dev environment) -jei_version=1.19.2-forge:11.6.0.1016 \ No newline at end of file +# Mod dependencies for testing stuff (Only used in the dev environment) +jade_version=4914105 +jei_version=1.19.2-forge:11.6.0.1016 diff --git a/qodana.yaml b/qodana.yaml index dfc5cbb26..f2df31528 100644 --- a/qodana.yaml +++ b/qodana.yaml @@ -16,7 +16,8 @@ exclude: - src/test/resources/* - src/testMod/resources/* - src/server-files/resources/* -include: - name: CheckDependencyLicenses + +include: - name: TrivialIf - name: NullableProblems \ No newline at end of file diff --git a/src/generated/resources/.cache/03e4de26f1265135874f8cdcaebc09d9c08eb42b b/src/generated/resources/.cache/03e4de26f1265135874f8cdcaebc09d9c08eb42b new file mode 100644 index 000000000..9c274278b --- /dev/null +++ b/src/generated/resources/.cache/03e4de26f1265135874f8cdcaebc09d9c08eb42b @@ -0,0 +1,3 @@ +// 1.19.2 2025-03-15T16:18:50.46663 Tags for minecraft:item +de4b4f45ec18b2b1f0db1c36882981042e20ee23 data/advancedperipherals/tags/items/p2p_attunements/cable_p2p_tunnel.json +72eba3b11f69e16c87488f7c4ba7cfdad42c378e data/advancedperipherals/tags/items/smart_glasses.json diff --git a/src/generated/resources/.cache/2db41954e490230d51b10affff25ee2ee27b8d5b b/src/generated/resources/.cache/2db41954e490230d51b10affff25ee2ee27b8d5b index f319707e2..8e30d22ee 100644 --- a/src/generated/resources/.cache/2db41954e490230d51b10affff25ee2ee27b8d5b +++ b/src/generated/resources/.cache/2db41954e490230d51b10affff25ee2ee27b8d5b @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-19T14:31:39.6951106 AP POI Type Tags +// 1.19.2 2025-03-15T16:18:50.465796 AP POI Type Tags d3d6b837660a4e213f287ad9d11e12368b90cd8e data/minecraft/tags/point_of_interest_type/acquirable_job_site.json diff --git a/src/generated/resources/.cache/5a761efb7472ef97566e41e81451930a004134bf b/src/generated/resources/.cache/5a761efb7472ef97566e41e81451930a004134bf index cb8219ecf..5483d6bb3 100644 --- a/src/generated/resources/.cache/5a761efb7472ef97566e41e81451930a004134bf +++ b/src/generated/resources/.cache/5a761efb7472ef97566e41e81451930a004134bf @@ -1,4 +1,4 @@ -// 1.19.2 2023-07-19T14:31:39.6751301 Turtle Upgrades +// 1.19.2 2025-03-15T16:18:50.466321 Turtle Upgrades b8f19ae0fb5bb898facc08e3787e0f96c8211881 data/advancedperipherals/computercraft/turtle_upgrades/chatty_turtle.json fe98c60e7d61139aacf2d0872873e610aac8a37b data/advancedperipherals/computercraft/turtle_upgrades/chunky_turtle.json ae619da638ad89d7302d832d6c09e2c87401c539 data/advancedperipherals/computercraft/turtle_upgrades/compass_turtle.json @@ -10,4 +10,5 @@ c9b2df2d4fed11f60a8e6f8da77b2fa53dd13572 data/advancedperipherals/computercraft/ 42fc2b9a2601ef44d617cb18302c2c4fff31d282 data/advancedperipherals/computercraft/turtle_upgrades/overpowered_husbandry_automata.json fa7743922ef6b4dd3e633f2857e4047d533f13b5 data/advancedperipherals/computercraft/turtle_upgrades/overpowered_weak_automata.json 4054c59ceb099f17c4555fd5f36b2f8b4109f624 data/advancedperipherals/computercraft/turtle_upgrades/player_turtle.json +fa6624d0dab03bd26c2cccecad51848d5071ecd3 data/advancedperipherals/computercraft/turtle_upgrades/saddle_turtle.json c8059a2717cfac5b02898658c4d2d52fbd5710d4 data/advancedperipherals/computercraft/turtle_upgrades/weak_automata.json diff --git a/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 b/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 index b767c20d4..ca3f6253d 100644 --- a/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 +++ b/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 @@ -1,14 +1,17 @@ -// 1.19.2 2024-01-15T20:01:57.516745 LootTables -d865e8ac35302c486faf5c7122569c554186186d data/advancedperipherals/loot_tables/blocks/block_reader.json -a6f896cc3dbd8da12737825ec71e32970f54025c data/advancedperipherals/loot_tables/blocks/chat_box.json -f50f506ae1987537f76be4c05a81689b25798f91 data/advancedperipherals/loot_tables/blocks/colony_integrator.json -1d1b858d09538dc66bab2c33a2f9c58361a9c472 data/advancedperipherals/loot_tables/blocks/energy_detector.json -317004b1358ef9bf83957d2d6796529a226161c7 data/advancedperipherals/loot_tables/blocks/environment_detector.json -d5a3964f518b138cbd7305c819a36af3d9340e4a data/advancedperipherals/loot_tables/blocks/geo_scanner.json -8aa1deea908fd02f049e047c8ca16679bbef68a2 data/advancedperipherals/loot_tables/blocks/inventory_manager.json -9a2898a63e2e0c087ce8eba211c63d1c8b9fd4aa data/advancedperipherals/loot_tables/blocks/me_bridge.json -973770040bacb61482adb9739fd1d977f16c107f data/advancedperipherals/loot_tables/blocks/nbt_storage.json -b4b80e8c9d62b53d9252cdfc5918c077d3a01f6e data/advancedperipherals/loot_tables/blocks/peripheral_casing.json -58b6adbea5d4ae43ed9af0b627df2b8a4907acde data/advancedperipherals/loot_tables/blocks/player_detector.json -a58aebcc52684302968e7af4f50a12aff93aaf2d data/advancedperipherals/loot_tables/blocks/redstone_integrator.json -0ef1678f88b8fcb744bfd95261f66745340be8f4 data/advancedperipherals/loot_tables/blocks/rs_bridge.json +// 1.19.2 2025-03-15T16:18:50.465594 LootTables +618b63c020ab64890c8a2d2506dd61cd30259a44 data/advancedperipherals/loot_tables/blocks/block_reader.json +0923665563d05307a7fa7d711a2d7a994a31eb6e data/advancedperipherals/loot_tables/blocks/chat_box.json +bf2a80256cfba0bd8c0283d493882e5816882f1f data/advancedperipherals/loot_tables/blocks/colony_integrator.json +cff4b81aa381bc0d1172b0a4c8bb35c1b954a018 data/advancedperipherals/loot_tables/blocks/distance_detector.json +1c5dbe1a8e07e040a3c2893a002cd535ee41dc20 data/advancedperipherals/loot_tables/blocks/energy_detector.json +8cc03eca1d191f725bc558836f26a85a466cb127 data/advancedperipherals/loot_tables/blocks/environment_detector.json +12589e7642b383029457d97a64637494ea8507a3 data/advancedperipherals/loot_tables/blocks/fluid_detector.json +421a3ece56485bd46374844639bfd606ce4665ec data/advancedperipherals/loot_tables/blocks/gas_detector.json +a2ae352dce564b878daecf47026f268dd432fbcf data/advancedperipherals/loot_tables/blocks/geo_scanner.json +807d449d02c0af701f84d3e806ebac20d3a1f91c data/advancedperipherals/loot_tables/blocks/inventory_manager.json +bb9b442dfad1d5f31397585c8394c85243fa169a data/advancedperipherals/loot_tables/blocks/me_bridge.json +52b1fe2e265be456ebf48d7e0d9ebcc8c994176f data/advancedperipherals/loot_tables/blocks/nbt_storage.json +2651e6053857a31f5bccc360969924848a197ad5 data/advancedperipherals/loot_tables/blocks/peripheral_casing.json +6b5058b6bc49689bf2b858b89f3981a4bb681750 data/advancedperipherals/loot_tables/blocks/player_detector.json +6af6542c7b64aa22dbfcdb01299daf4911827a49 data/advancedperipherals/loot_tables/blocks/redstone_integrator.json +b221c6a82da0875264a112b54f847ac6a1f36797 data/advancedperipherals/loot_tables/blocks/rs_bridge.json diff --git a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e index 949aa05ae..5b054c33c 100644 --- a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e +++ b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -1,4 +1,5 @@ -// 1.19.2 2024-01-15T20:01:57.5157458 Recipes +// 1.19.2 2025-03-15T16:18:50.466743 Recipes +045608027e4a5ea2d7dee7f402346b8e69f21675 data/advancedperipherals/advancements/recipes/advancedperipheralstab/armor/smart_glasses_netherite.json db2dada2fdf42ca1bbf47f1eb075d1f9de89dfa8 data/advancedperipherals/advancements/recipes/advancedperipheralstab/block_reader.json 77c55e8500be4a344ca563a8bf7642257cdc7b8b data/advancedperipherals/advancements/recipes/advancedperipheralstab/chat_box.json 96208b06b0c3c125762cd517506a5ffb6b1d55ac data/advancedperipherals/advancements/recipes/advancedperipheralstab/chunk_controller.json @@ -16,6 +17,7 @@ d27c1267208fd9036c5c45f7f6cbd4f6f67b3845 data/advancedperipherals/advancements/r d8870644bb7d48c5ae33dcea2afbcfa106729d7b data/advancedperipherals/advancements/recipes/advancedperipheralstab/player_detector.json 7acff70533792bd089a655f8f24cdea6995aac0c data/advancedperipherals/advancements/recipes/advancedperipheralstab/redstone_integrator.json fc0c3d99bec43318802f357083c7d98fde92567f data/advancedperipherals/advancements/recipes/advancedperipheralstab/weak_automata_core.json +66999fea36aa4113567753f104630f6490dda6ba data/advancedperipherals/recipes/armor/smart_glasses_netherite.json b10b5cbcc668438001744d5b90d9838ab4d293cb data/advancedperipherals/recipes/block_reader.json 3c9618832fe0ac32cac0f04fbc5afad225418239 data/advancedperipherals/recipes/chat_box.json a78adfcca4c7579b143aac5648a7eca9085c0dba data/advancedperipherals/recipes/chunk_controller.json @@ -25,8 +27,8 @@ f1f468c732f8c802c27776d3fd7aac432bcac8e3 data/advancedperipherals/recipes/comput 55c257e4e8548d1453a7ab96c547d64c22b3e1d6 data/advancedperipherals/recipes/environment_detector.json 2ddf64c122165bcd3a277db8a1c7e96b4d510c67 data/advancedperipherals/recipes/geo_scanner.json ebe70aa9fe80c5b962c13aa1fbadc32269ba81b9 data/advancedperipherals/recipes/inventory_manager.json -809bc6929cf5eab72648e8f1fb565b58749fec12 data/advancedperipherals/recipes/memory_card.json 82895838af6c6aea0c60e3a3fbf71073ab684167 data/advancedperipherals/recipes/me_bridge.json +809bc6929cf5eab72648e8f1fb565b58749fec12 data/advancedperipherals/recipes/memory_card.json 8a73c4eb66e7a1cdc8e51d33466cf5a30da9270e data/advancedperipherals/recipes/nbt_storage.json 360432f30d61291066aa8c54692629f7a92e178d data/advancedperipherals/recipes/overpowered_end_automata_core.json 4ea6e90d13a61d90ad245539d20020ff9cb843e1 data/advancedperipherals/recipes/overpowered_husbandry_automata_core.json diff --git a/src/generated/resources/.cache/ae219fa7c7d3297c14e454863eac3998a4eab78c b/src/generated/resources/.cache/ae219fa7c7d3297c14e454863eac3998a4eab78c index b9e492ca6..4a3bf0dbb 100644 --- a/src/generated/resources/.cache/ae219fa7c7d3297c14e454863eac3998a4eab78c +++ b/src/generated/resources/.cache/ae219fa7c7d3297c14e454863eac3998a4eab78c @@ -1,6 +1,7 @@ -// 1.19.2 2023-07-19T14:31:39.6815264 Pocket Computer Upgrades +// 1.19.2 2025-03-15T16:18:50.46512 Pocket Computer Upgrades b672635324c0df354e587efc81d0b19a581eae2f data/advancedperipherals/computercraft/pocket_upgrades/chatty_pocket.json 30b8f663613c7ce77048fd69631afcc11a682276 data/advancedperipherals/computercraft/pocket_upgrades/colony_pocket.json +661dc77bd0442bfb2a5ed80cff271071817bb22d data/advancedperipherals/computercraft/pocket_upgrades/distance_pocket.json d4647159c2f2693a9c5e8d12bf740635751d29a8 data/advancedperipherals/computercraft/pocket_upgrades/environment_pocket.json 8216a0a7d8ebe3ae738c8fc3626df25eb0a2e07a data/advancedperipherals/computercraft/pocket_upgrades/geoscanner_pocket.json a38aa83593f7ad0ace98e01bb3b5f06f272ef734 data/advancedperipherals/computercraft/pocket_upgrades/player_pocket.json diff --git a/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 b/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 index 54d53cf45..005d0e248 100644 --- a/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 +++ b/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 @@ -1,9 +1,12 @@ -// 1.19.2 2024-01-15T20:01:57.5177444 Block States: advancedperipherals +// 1.19.2 2025-03-15T16:18:50.466039 Block States: advancedperipherals 5e28ce1be9a6996d982641e5df1fa7162090b8cc assets/advancedperipherals/blockstates/block_reader.json f42bdde60f84fdb312f7cf3b2be461d9c11ebdc8 assets/advancedperipherals/blockstates/chat_box.json 1227aa092fcf1327547ace6ccc9db230e45891b0 assets/advancedperipherals/blockstates/colony_integrator.json +83144ea6122b3abe70777458ac913b6f217c27cc assets/advancedperipherals/blockstates/distance_detector.json 67420f28031606ca03db9a044141bb22b0fa78b7 assets/advancedperipherals/blockstates/energy_detector.json 340b5baa62e5e6a2c35a05b4411be5937ac2bbb8 assets/advancedperipherals/blockstates/environment_detector.json +f40e0ac205d0473908fd957d035dd747dc64e26a assets/advancedperipherals/blockstates/fluid_detector.json +bbefa012be11f3735da4d9deb1f0d2402c761cd8 assets/advancedperipherals/blockstates/gas_detector.json 57c00996bcf1d783116a9210842f246612089555 assets/advancedperipherals/blockstates/geo_scanner.json d1fe6188b0b0ce8779cb9795a746177858cbaa41 assets/advancedperipherals/blockstates/inventory_manager.json 7f82e776900e3d120cb1a06ec975731905dcaff7 assets/advancedperipherals/blockstates/me_bridge.json @@ -13,15 +16,18 @@ ff12c7217911184266589813a2c8f9b0d46cfd65 assets/advancedperipherals/blockstates/ 726cf2599b0c765bcfacda88a1943be74f985877 assets/advancedperipherals/blockstates/redstone_integrator.json 6b176e8fdb048f7b6678bfbc1c4baf2bcfa67a1f assets/advancedperipherals/blockstates/rs_bridge.json 544ff1ecb58622350b58940036b4b1908e1146da assets/advancedperipherals/models/block/block_reader.json -b28693973b6bbbb61e0c1ffc59e8ca98d8bb7e97 assets/advancedperipherals/models/block/chat_box.json -8361da86b709e26f17374dfd46637940894a2212 assets/advancedperipherals/models/block/colony_integrator.json -96ef564804fdc2b5184462747935f52baa35c651 assets/advancedperipherals/models/block/energy_detector.json -41556ddf5c5e67def6efd8e2e0645718d950af25 assets/advancedperipherals/models/block/environment_detector.json -ba233597a497c1032d884fc3058e27b9d965725e assets/advancedperipherals/models/block/geo_scanner.json -fb58e0b712f1f6ce1b2ea4dcfa0747905cf6ed95 assets/advancedperipherals/models/block/inventory_manager.json -75b59d2b73a96a27e3d4a1ed3b9a928b7dff102e assets/advancedperipherals/models/block/me_bridge.json -a647b86b8a7862af738136c9375a5d27d3b08860 assets/advancedperipherals/models/block/nbt_storage.json -36b6ac01be085492aa6298eeb89e6ecaa3cb6f82 assets/advancedperipherals/models/block/peripheral_casing.json -40369caaaf2f593d786a9c64284647fed8ae3a47 assets/advancedperipherals/models/block/player_detector.json -bed2ba2ba497ccde06c99712483fe220c277b4be assets/advancedperipherals/models/block/redstone_integrator.json -019c10d5062b5e7ae3e641527b9badab7a50878d assets/advancedperipherals/models/block/rs_bridge.json +fbaa69d6c98549d3f2d4a1c7bebd9b6b80d56621 assets/advancedperipherals/models/block/chat_box.json +68f9d37bd85649937150ba0bb8f4496bb2ef218d assets/advancedperipherals/models/block/colony_integrator.json +80b30400b6ebac490a1abaad965f33c1b62c19e9 assets/advancedperipherals/models/block/distance_detector.json +b4c6645fda79d960e9201e2a60eb1c8063a07d18 assets/advancedperipherals/models/block/energy_detector.json +eca505b2bd8db5f1d13f1e28093db329b70af978 assets/advancedperipherals/models/block/environment_detector.json +f6ab51bcfc829c7db490f691e8eb491e5e7028f3 assets/advancedperipherals/models/block/fluid_detector.json +35bbc0e2edf74f6e27029cc23465e203d459f234 assets/advancedperipherals/models/block/gas_detector.json +46ebb4c9a31e224bac13ad20334469c0b55d285c assets/advancedperipherals/models/block/geo_scanner.json +2142aaccd0a0bc56aaa2091128466d2c9a733aab assets/advancedperipherals/models/block/inventory_manager.json +f089dda9e6ac12d638707fd24d099ccd56a54ccc assets/advancedperipherals/models/block/me_bridge.json +65afcae128339b244508dc66620c6c00729fce8e assets/advancedperipherals/models/block/nbt_storage.json +f6cb0dda1ce8217563903d2dfaf5ef0297939750 assets/advancedperipherals/models/block/peripheral_casing.json +5a1679b4dcc8da2d8c67674216d242456bb51366 assets/advancedperipherals/models/block/player_detector.json +d08b8946e1eb01cc9c8af4fa297b582614d1034b assets/advancedperipherals/models/block/redstone_integrator.json +41cf7d22016a995aeda9df9d9cbf1d4069b99f9e assets/advancedperipherals/models/block/rs_bridge.json diff --git a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 42f19ff63..577e18447 100644 --- a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2024-01-15T20:01:57.5147447 Languages: en_us -d2006c7f1d9c5f1f768b50a3c445dc8b566bf9dd assets/advancedperipherals/lang/en_us.json +// 1.19.2 2025-03-15T16:18:50.465918 Languages: en_us +fe52123263b91f49093d74278e8709484e4dfe59 assets/advancedperipherals/lang/en_us.json diff --git a/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 b/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 index 042110e02..032d093dc 100644 --- a/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 +++ b/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 @@ -1,4 +1,4 @@ -// 1.19.2 2024-01-15T20:01:57.5177444 Block tags +// 1.19.2 2025-03-15T16:18:50.466493 Block tags e1f71dcb4f9e7e36e29b0ad09d6520dc3adfa4a6 data/forge/tags/blocks/needs_wood_tool.json -dcbdeb0bc268b24e9970e4bada12e8e8da97b8d5 data/minecraft/tags/blocks/mineable/pickaxe.json -1017ee5cf2a99941ddfc00c2c5e07a19644470b6 data/minecraft/tags/blocks/needs_iron_tool.json +03322cd493601129eaad6ba7c2a6d808023dfac1 data/minecraft/tags/blocks/mineable/pickaxe.json +277fe59db076a3eab3c97080531ad345f8ca5f3d data/minecraft/tags/blocks/needs_iron_tool.json diff --git a/src/generated/resources/assets/advancedperipherals/blockstates/distance_detector.json b/src/generated/resources/assets/advancedperipherals/blockstates/distance_detector.json new file mode 100644 index 000000000..4201dd6d7 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/blockstates/distance_detector.json @@ -0,0 +1,57 @@ +{ + "variants": { + "orientation=down_east": { + "model": "advancedperipherals:block/distance_detector", + "x": 90, + "y": 90 + }, + "orientation=down_north": { + "model": "advancedperipherals:block/distance_detector", + "x": 90 + }, + "orientation=down_south": { + "model": "advancedperipherals:block/distance_detector", + "x": 90, + "y": 180 + }, + "orientation=down_west": { + "model": "advancedperipherals:block/distance_detector", + "x": 90, + "y": 270 + }, + "orientation=east_up": { + "model": "advancedperipherals:block/distance_detector", + "y": 90 + }, + "orientation=north_up": { + "model": "advancedperipherals:block/distance_detector" + }, + "orientation=south_up": { + "model": "advancedperipherals:block/distance_detector", + "y": 180 + }, + "orientation=up_east": { + "model": "advancedperipherals:block/distance_detector", + "x": 270, + "y": 90 + }, + "orientation=up_north": { + "model": "advancedperipherals:block/distance_detector", + "x": 270 + }, + "orientation=up_south": { + "model": "advancedperipherals:block/distance_detector", + "x": 270, + "y": 180 + }, + "orientation=up_west": { + "model": "advancedperipherals:block/distance_detector", + "x": 270, + "y": 270 + }, + "orientation=west_up": { + "model": "advancedperipherals:block/distance_detector", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/blockstates/fluid_detector.json b/src/generated/resources/assets/advancedperipherals/blockstates/fluid_detector.json new file mode 100644 index 000000000..6641af423 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/blockstates/fluid_detector.json @@ -0,0 +1,57 @@ +{ + "variants": { + "orientation=down_east": { + "model": "advancedperipherals:block/fluid_detector", + "x": 90, + "y": 90 + }, + "orientation=down_north": { + "model": "advancedperipherals:block/fluid_detector", + "x": 90 + }, + "orientation=down_south": { + "model": "advancedperipherals:block/fluid_detector", + "x": 90, + "y": 180 + }, + "orientation=down_west": { + "model": "advancedperipherals:block/fluid_detector", + "x": 90, + "y": 270 + }, + "orientation=east_up": { + "model": "advancedperipherals:block/fluid_detector", + "y": 90 + }, + "orientation=north_up": { + "model": "advancedperipherals:block/fluid_detector" + }, + "orientation=south_up": { + "model": "advancedperipherals:block/fluid_detector", + "y": 180 + }, + "orientation=up_east": { + "model": "advancedperipherals:block/fluid_detector", + "x": 270, + "y": 90 + }, + "orientation=up_north": { + "model": "advancedperipherals:block/fluid_detector", + "x": 270 + }, + "orientation=up_south": { + "model": "advancedperipherals:block/fluid_detector", + "x": 270, + "y": 180 + }, + "orientation=up_west": { + "model": "advancedperipherals:block/fluid_detector", + "x": 270, + "y": 270 + }, + "orientation=west_up": { + "model": "advancedperipherals:block/fluid_detector", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/blockstates/gas_detector.json b/src/generated/resources/assets/advancedperipherals/blockstates/gas_detector.json new file mode 100644 index 000000000..aee9fc55d --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/blockstates/gas_detector.json @@ -0,0 +1,57 @@ +{ + "variants": { + "orientation=down_east": { + "model": "advancedperipherals:block/gas_detector", + "x": 90, + "y": 90 + }, + "orientation=down_north": { + "model": "advancedperipherals:block/gas_detector", + "x": 90 + }, + "orientation=down_south": { + "model": "advancedperipherals:block/gas_detector", + "x": 90, + "y": 180 + }, + "orientation=down_west": { + "model": "advancedperipherals:block/gas_detector", + "x": 90, + "y": 270 + }, + "orientation=east_up": { + "model": "advancedperipherals:block/gas_detector", + "y": 90 + }, + "orientation=north_up": { + "model": "advancedperipherals:block/gas_detector" + }, + "orientation=south_up": { + "model": "advancedperipherals:block/gas_detector", + "y": 180 + }, + "orientation=up_east": { + "model": "advancedperipherals:block/gas_detector", + "x": 270, + "y": 90 + }, + "orientation=up_north": { + "model": "advancedperipherals:block/gas_detector", + "x": 270 + }, + "orientation=up_south": { + "model": "advancedperipherals:block/gas_detector", + "x": 270, + "y": 180 + }, + "orientation=up_west": { + "model": "advancedperipherals:block/gas_detector", + "x": 270, + "y": 270 + }, + "orientation=west_up": { + "model": "advancedperipherals:block/gas_detector", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/lang/en_us.json b/src/generated/resources/assets/advancedperipherals/lang/en_us.json index ed66cc743..9a61a7d44 100644 --- a/src/generated/resources/assets/advancedperipherals/lang/en_us.json +++ b/src/generated/resources/assets/advancedperipherals/lang/en_us.json @@ -2,25 +2,28 @@ "advancedperipherals.name": "Advanced Peripherals", "advancements.advancedperipherals.base_toolkit": "Gentleman's set!", "advancements.advancedperipherals.base_toolkit.description": "Collect a redstone integrator, inventory manager and energy detector. How did you even play without this?", - "advancements.advancedperipherals.end_automata_core": "End automata core", + "advancements.advancedperipherals.end_automata_core": "End Automata Core", "advancements.advancedperipherals.end_automata_core.description": "If you can code gps-free position location with this, you're a powerful human being", - "advancements.advancedperipherals.husbandry_automata_core": "Husbandry automata core", + "advancements.advancedperipherals.husbandry_automata_core": "Husbandry Automata Core", "advancements.advancedperipherals.husbandry_automata_core.description": "Is this core gluten-free?", "advancements.advancedperipherals.nbt_toolkit": "No secrets", "advancements.advancedperipherals.nbt_toolkit.description": "Collect a NBT storage and block reader. Now, all the world's secrets are open to you!", - "advancements.advancedperipherals.overpowered_automata_core": "Overpowered automata core", + "advancements.advancedperipherals.overpowered_automata_core": "Overpowered Automata Core", "advancements.advancedperipherals.overpowered_automata_core.description": "Can you handle so much power?", "advancements.advancedperipherals.root": "Advanced Peripherals", "advancements.advancedperipherals.root.description": "Every journey starts with the first block", "advancements.advancedperipherals.sense_toolkit": "The truth can't hide forever", "advancements.advancedperipherals.sense_toolkit.description": "Collect a geo scanner and environmental detector. There are no limits for observability!", - "advancements.advancedperipherals.weak_automata_core": "First automata core", + "advancements.advancedperipherals.weak_automata_core": "First Automata Core", "advancements.advancedperipherals.weak_automata_core.description": "Does the afterlife exist in minecraft?", "block.advancedperipherals.block_reader": "Block Reader", "block.advancedperipherals.chat_box": "Chat Box", "block.advancedperipherals.colony_integrator": "Colony Integrator", + "block.advancedperipherals.distance_detector": "Distance Detector", "block.advancedperipherals.energy_detector": "Energy Detector", "block.advancedperipherals.environment_detector": "Environment Detector", + "block.advancedperipherals.fluid_detector": "Fluid Detector", + "block.advancedperipherals.gas_detector": "Gas Detector", "block.advancedperipherals.geo_scanner": "Geo Scanner", "block.advancedperipherals.inventory_manager": "Inventory Manager", "block.advancedperipherals.me_bridge": "ME Bridge", @@ -29,21 +32,32 @@ "block.advancedperipherals.player_detector": "Player Detector", "block.advancedperipherals.redstone_integrator": "Redstone Integrator", "block.advancedperipherals.rs_bridge": "RS Bridge", + "curios.identifier.glasses": "Glasses", "entity.minecraft.villager.advancedperipherals.computer_scientist": "Computer Scientist", + "item.advancedperipherals.cable_p2p_tunnel": "Cable P2P Tunnel", "item.advancedperipherals.chunk_controller": "Chunk Controller", "item.advancedperipherals.computer_tool": "Computer Tool", "item.advancedperipherals.end_automata_core": "End Automata Core", + "item.advancedperipherals.hotkey_module": "Hotkey Module", "item.advancedperipherals.husbandry_automata_core": "Husbandry Automata Core", + "item.advancedperipherals.keyboard": "Wireless Keyboard", "item.advancedperipherals.memory_card": "Memory Card", + "item.advancedperipherals.nightvision_module": "Night Vision Module", + "item.advancedperipherals.overlay_module": "Overlay Module", "item.advancedperipherals.overpowered_end_automata_core": "Overpowered End Automata Core", "item.advancedperipherals.overpowered_husbandry_automata_core": "Overpowered Husbandry Automata Core", "item.advancedperipherals.overpowered_weak_automata_core": "Overpowered Weak Automata Core", + "item.advancedperipherals.smart_glasses": "Smart Glasses", + "item.advancedperipherals.smart_glasses_interface": "Smart Glasses Interface", + "item.advancedperipherals.smart_glasses_netherite": "Netherite reinforced Smart Glasses", + "item.advancedperipherals.tooltip.binding.bound_to": "&7Bound to &b%s&7.", + "item.advancedperipherals.tooltip.binding.bound_to_glasses": "&7Bound to Glasses with id &b%s&7.", "item.advancedperipherals.tooltip.block_reader": "&7Reads nbt data of blocks to interact with blocks which do not have computer support.", "item.advancedperipherals.tooltip.chat_box": "&7Interacts with the ingame chat, can read and write messages.", "item.advancedperipherals.tooltip.chunk_controller": "&7A crafting ingredient for the Chunky Turtle.", "item.advancedperipherals.tooltip.colony_integrator": "&7Interacts with Minecolonies to read data about your colony and citizens.", "item.advancedperipherals.tooltip.computer_tool": "&7This tool was made to tune our blocks. But for now, it's just a blue useless wrench.", - "item.advancedperipherals.tooltip.disabled": "&cThis item is disabled in the config, so you can craft it, but it'll not have any functionality.", + "item.advancedperipherals.tooltip.disabled": "&cThis item is disabled in config, so you can craft it, but it'll not have any functionality.", "item.advancedperipherals.tooltip.end_automata_core": "&7Upgrade for turtles, that allows basic interaction with the world and teleportation in one dimension.", "item.advancedperipherals.tooltip.energy_detector": "&7Can detect energy flow and acts as a resistor.", "item.advancedperipherals.tooltip.environment_detector": "&7This peripheral interacts with the minecraft world.", @@ -52,12 +66,11 @@ "item.advancedperipherals.tooltip.inventory_manager": "&7This block is able to send or receive specific items from a player inventory.", "item.advancedperipherals.tooltip.me_bridge": "&7The ME Bridge interacts with Applied Energistics to manage your items.", "item.advancedperipherals.tooltip.memory_card": "&7Can save the rights of a player to use it in an inventory manager.", - "item.advancedperipherals.tooltip.memory_card.bound": "&7Bound to &b%s&7.", "item.advancedperipherals.tooltip.nbt_storage": "&7Acts like a storage disk. Can store nbt based data.", "item.advancedperipherals.tooltip.overpowered_end_automata_core": "&7Improved version of the end automata core, that provides some overpowered uses! Be careful, the upgrade is very fragile.", "item.advancedperipherals.tooltip.overpowered_husbandry_automata_core": "&7Improved version of the husbandry automata core, that provides some overpowered uses! Be careful, the upgrade is very fragile.", "item.advancedperipherals.tooltip.overpowered_weak_automata_core": "&7Improved version of the weak automata core, that provides some overpowered uses! Be careful, the upgrade is very fragile.", - "item.advancedperipherals.tooltip.peripheral_casing": "&7An empty hull without the love it deserves. Used as a crafting ingredient", + "item.advancedperipherals.tooltip.peripheral_casing": "&7An empty hull without the love it deserves. Used as crafting ingredient", "item.advancedperipherals.tooltip.player_detector": "&7This peripheral can be used to interact with players, but don't be a stalker.", "item.advancedperipherals.tooltip.redstone_integrator": "&7This block is able to interact with redstone. Works exactly like the redstone api of an computer.", "item.advancedperipherals.tooltip.rs_bridge": "&7The RS Bridge interacts with Refined Storage to manage your items.", @@ -69,22 +82,31 @@ "keybind.advancedperipherals.description": "Show Description", "pocket.advancedperipherals.chatty_pocket": "Chatty", "pocket.advancedperipherals.colony_pocket": "Colony", + "pocket.advancedperipherals.distance_pocket": "Distance Detector", "pocket.advancedperipherals.environment_pocket": "Environment", "pocket.advancedperipherals.geoscanner_pocket": "Geo", "pocket.advancedperipherals.player_pocket": "Player Detector", - "text.advancedperipherals.added_player": "Added you to the memory card", - "text.advancedperipherals.automata_core_feed_by_player": "You're trying to feed an entity to a soul, but your own body refuses to do this. Maybe something more mechanical can do this?", - "text.advancedperipherals.removed_player": "Cleared the memory card", + "text.advancedperipherals.automata_core.feed_by_player": "You're trying to feed an entity to a soul, but your own body refuses to do this. Maybe something more mechanical can do this?", + "text.advancedperipherals.bind_keyboard": "Bounded the keyboard to %s", + "text.advancedperipherals.bind_memorycard": "Bounded the memory card to you", + "text.advancedperipherals.cleared_keyboard": "Cleared the keyboard", + "text.advancedperipherals.cleared_memorycard": "Cleared the memory card", + "text.advancedperipherals.keyboard.close": "Press ESC to close the Keyboard Screen", + "text.advancedperipherals.keyboard_notbound": "The keyboard it not bound", + "text.advancedperipherals.saddle_turtle.dismount_hint": "Controlling %1$s. Press %2$s and %3$s to dismount.", + "text.advancedperipherals.smart_glasses.modules": "Modules", + "text.advancedperipherals.smart_glasses.peripherals": "Peripherals", "turtle.advancedperipherals.chatty_turtle": "Chatty", "turtle.advancedperipherals.chunky_turtle": "Chunky", "turtle.advancedperipherals.compass_turtle": "Compass", - "turtle.advancedperipherals.end_automata": "End automata", + "turtle.advancedperipherals.end_automata": "End Automata", "turtle.advancedperipherals.environment_turtle": "Environment", "turtle.advancedperipherals.geoscanner_turtle": "Geo", - "turtle.advancedperipherals.husbandry_automata": "Husbandry automata", - "turtle.advancedperipherals.overpowered_end_automata": "Overpowered end automata", - "turtle.advancedperipherals.overpowered_husbandry_automata": "Overpowered husbandry automata", - "turtle.advancedperipherals.overpowered_weak_automata": "Overpowered weak automata", + "turtle.advancedperipherals.husbandry_automata": "Husbandry Automata", + "turtle.advancedperipherals.overpowered_end_automata": "Overpowered End Automata", + "turtle.advancedperipherals.overpowered_husbandry_automata": "Overpowered Husbandry Automata", + "turtle.advancedperipherals.overpowered_weak_automata": "Overpowered Weak Automata", "turtle.advancedperipherals.player_turtle": "Player Detector", - "turtle.advancedperipherals.weak_automata": "Weak automata" + "turtle.advancedperipherals.saddle_turtle": "Saddle", + "turtle.advancedperipherals.weak_automata": "Weak Automata" } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/chat_box.json b/src/generated/resources/assets/advancedperipherals/models/block/chat_box.json index 487d0eb4e..ba89671f2 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/chat_box.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/chat_box.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/chat_box", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/chat_box_front", - "particle": "advancedperipherals:block/chat_box_front" + "particle": "advancedperipherals:block/chat_box_front", + "up": "advancedperipherals:block/chat_box_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/colony_integrator.json b/src/generated/resources/assets/advancedperipherals/models/block/colony_integrator.json index 884006124..7f52aebb0 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/colony_integrator.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/colony_integrator.json @@ -2,8 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/colony_integrator", - "down": "minecraft:block/oak_log_top", - "particle": "advancedperipherals:block/colony_integrator", - "up": "minecraft:block/oak_log_top" + "down": "advancedperipherals:block/bottom", + "north": "advancedperipherals:block/colony_integrator_front", + "particle": "advancedperipherals:block/colony_integrator_front", + "up": "advancedperipherals:block/colony_integrator_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/distance_detector.json b/src/generated/resources/assets/advancedperipherals/models/block/distance_detector.json new file mode 100644 index 000000000..0cee7c371 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/distance_detector.json @@ -0,0 +1,12 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "down": "advancedperipherals:block/distance_detector_down", + "east": "advancedperipherals:block/distance_detector_east", + "north": "advancedperipherals:block/distance_detector_north", + "particle": "advancedperipherals:block/distance_detector_north", + "south": "advancedperipherals:block/distance_detector_south", + "up": "advancedperipherals:block/distance_detector_up", + "west": "advancedperipherals:block/distance_detector_west" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/energy_detector.json b/src/generated/resources/assets/advancedperipherals/models/block/energy_detector.json index d1b21431d..ebb28dd2e 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/energy_detector.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/energy_detector.json @@ -2,8 +2,11 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/energy_detector", + "down": "advancedperipherals:block/bottom", + "east": "advancedperipherals:block/energy_detector_east", "north": "advancedperipherals:block/energy_detector_front", "particle": "advancedperipherals:block/energy_detector_front", - "south": "advancedperipherals:block/energy_detector_back" + "south": "advancedperipherals:block/energy_detector_back", + "up": "advancedperipherals:block/energy_detector_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/environment_detector.json b/src/generated/resources/assets/advancedperipherals/models/block/environment_detector.json index e049a94d1..ce251a7af 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/environment_detector.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/environment_detector.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/environment_detector", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/environment_detector_front", - "particle": "advancedperipherals:block/environment_detector_front" + "particle": "advancedperipherals:block/environment_detector_front", + "up": "advancedperipherals:block/environment_detector_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/fluid_detector.json b/src/generated/resources/assets/advancedperipherals/models/block/fluid_detector.json new file mode 100644 index 000000000..6460c20e7 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/fluid_detector.json @@ -0,0 +1,12 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "advancedperipherals:block/fluid_detector", + "down": "advancedperipherals:block/bottom", + "east": "advancedperipherals:block/fluid_detector_east", + "north": "advancedperipherals:block/fluid_detector_front", + "particle": "advancedperipherals:block/fluid_detector_front", + "south": "advancedperipherals:block/fluid_detector_back", + "up": "advancedperipherals:block/fluid_detector_top" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/gas_detector.json b/src/generated/resources/assets/advancedperipherals/models/block/gas_detector.json new file mode 100644 index 000000000..c03bc40ae --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/gas_detector.json @@ -0,0 +1,12 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "advancedperipherals:block/gas_detector", + "down": "advancedperipherals:block/bottom", + "east": "advancedperipherals:block/gas_detector_east", + "north": "advancedperipherals:block/gas_detector_front", + "particle": "advancedperipherals:block/gas_detector_front", + "south": "advancedperipherals:block/gas_detector_back", + "up": "advancedperipherals:block/gas_detector_top" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/geo_scanner.json b/src/generated/resources/assets/advancedperipherals/models/block/geo_scanner.json index d81084e52..4870d8a6b 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/geo_scanner.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/geo_scanner.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/geo_scanner", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/geo_scanner_front", - "particle": "advancedperipherals:block/geo_scanner_front" + "particle": "advancedperipherals:block/geo_scanner_front", + "up": "advancedperipherals:block/geo_scanner_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/inventory_manager.json b/src/generated/resources/assets/advancedperipherals/models/block/inventory_manager.json index 16ac6a767..8431aaece 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/inventory_manager.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/inventory_manager.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/inventory_manager", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/inventory_manager_front", - "particle": "advancedperipherals:block/inventory_manager_front" + "particle": "advancedperipherals:block/inventory_manager_front", + "up": "advancedperipherals:block/inventory_manager_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/me_bridge.json b/src/generated/resources/assets/advancedperipherals/models/block/me_bridge.json index 0d5355f55..ab8392272 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/me_bridge.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/me_bridge.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/me_bridge", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/me_bridge_front", - "particle": "advancedperipherals:block/me_bridge_front" + "particle": "advancedperipherals:block/me_bridge_front", + "up": "advancedperipherals:block/me_bridge_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/nbt_storage.json b/src/generated/resources/assets/advancedperipherals/models/block/nbt_storage.json index 4472f8466..8545dbe6a 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/nbt_storage.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/nbt_storage.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/nbt_storage", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/nbt_storage_front", - "particle": "advancedperipherals:block/nbt_storage_front" + "particle": "advancedperipherals:block/nbt_storage_front", + "up": "advancedperipherals:block/nbt_storage_top" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/peripheral_casing.json b/src/generated/resources/assets/advancedperipherals/models/block/peripheral_casing.json index d6dd9f3cc..598971334 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/peripheral_casing.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/peripheral_casing.json @@ -2,6 +2,7 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/peripheral_casing", + "down": "advancedperipherals:block/bottom", "particle": "advancedperipherals:block/peripheral_casing" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/player_detector.json b/src/generated/resources/assets/advancedperipherals/models/block/player_detector.json index f3d2db295..c658c96c7 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/player_detector.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/player_detector.json @@ -1,12 +1,13 @@ { "parent": "minecraft:block/cube_all", "textures": { - "all": "advancedperipherals:block/player_detector", + "down": "advancedperipherals:block/bottom", "east": "advancedperipherals:block/player_detector_side", "north": "advancedperipherals:block/player_detector_front", "particle": "advancedperipherals:block/player_detector_front", "side": "advancedperipherals:block/player_detector_side", "south": "advancedperipherals:block/player_detector_side", + "up": "advancedperipherals:block/player_detector_top", "west": "advancedperipherals:block/player_detector_side" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/redstone_integrator.json b/src/generated/resources/assets/advancedperipherals/models/block/redstone_integrator.json index 2fa89aaa5..038dd8561 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/redstone_integrator.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/redstone_integrator.json @@ -1,8 +1,13 @@ { "parent": "minecraft:block/cube_all", "textures": { - "all": "advancedperipherals:block/redstone_integrator", + "down": "advancedperipherals:block/redstone_integrator_bottom", + "east": "advancedperipherals:block/redstone_integrator_side", "north": "advancedperipherals:block/redstone_integrator_front", - "particle": "advancedperipherals:block/redstone_integrator_front" + "particle": "advancedperipherals:block/redstone_integrator_front", + "side": "advancedperipherals:block/redstone_integrator_side", + "south": "advancedperipherals:block/redstone_integrator_side", + "up": "advancedperipherals:block/redstone_integrator_top", + "west": "advancedperipherals:block/redstone_integrator_side" } } \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/rs_bridge.json b/src/generated/resources/assets/advancedperipherals/models/block/rs_bridge.json index 10e0f003a..b7e3d476b 100644 --- a/src/generated/resources/assets/advancedperipherals/models/block/rs_bridge.json +++ b/src/generated/resources/assets/advancedperipherals/models/block/rs_bridge.json @@ -2,7 +2,9 @@ "parent": "minecraft:block/cube_all", "textures": { "all": "advancedperipherals:block/rs_bridge", + "down": "advancedperipherals:block/bottom", "north": "advancedperipherals:block/rs_bridge_front", - "particle": "advancedperipherals:block/rs_bridge_front" + "particle": "advancedperipherals:block/rs_bridge_front", + "up": "advancedperipherals:block/rs_bridge_top" } } \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/advancements/recipes/advancedperipheralstab/armor/smart_glasses_netherite.json b/src/generated/resources/data/advancedperipherals/advancements/recipes/advancedperipheralstab/armor/smart_glasses_netherite.json new file mode 100644 index 000000000..bb6e067ec --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/advancements/recipes/advancedperipheralstab/armor/smart_glasses_netherite.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": [ + "minecraft:netherite_ingot" + ] + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "advancedperipherals:armor/smart_glasses_netherite" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "advancedperipherals:armor/smart_glasses_netherite" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/computercraft/pocket_upgrades/distance_pocket.json b/src/generated/resources/data/advancedperipherals/computercraft/pocket_upgrades/distance_pocket.json new file mode 100644 index 000000000..0d83ccc1d --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/computercraft/pocket_upgrades/distance_pocket.json @@ -0,0 +1,4 @@ +{ + "type": "advancedperipherals:distance_pocket", + "item": "advancedperipherals:distance_detector" +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/computercraft/turtle_upgrades/saddle_turtle.json b/src/generated/resources/data/advancedperipherals/computercraft/turtle_upgrades/saddle_turtle.json new file mode 100644 index 000000000..0670d5c0b --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/computercraft/turtle_upgrades/saddle_turtle.json @@ -0,0 +1,4 @@ +{ + "type": "advancedperipherals:saddle_turtle", + "item": "minecraft:saddle" +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/distance_detector.json b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/distance_detector.json new file mode 100644 index 000000000..4da55fb18 --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/distance_detector.json @@ -0,0 +1,26 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], + "name": "advancedperipherals:distance_detector" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/fluid_detector.json b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/fluid_detector.json new file mode 100644 index 000000000..a57de0eab --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/fluid_detector.json @@ -0,0 +1,26 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], + "name": "advancedperipherals:fluid_detector" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/gas_detector.json b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/gas_detector.json new file mode 100644 index 000000000..be3a1af68 --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/gas_detector.json @@ -0,0 +1,26 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], + "name": "advancedperipherals:gas_detector" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/recipes/armor/smart_glasses_netherite.json b/src/generated/resources/data/advancedperipherals/recipes/armor/smart_glasses_netherite.json new file mode 100644 index 000000000..e46b01d51 --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/recipes/armor/smart_glasses_netherite.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "addition": { + "item": "minecraft:netherite_ingot" + }, + "base": { + "item": "advancedperipherals:smart_glasses" + }, + "result": { + "item": "advancedperipherals:smart_glasses_netherite" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/tags/items/p2p_attunements/cable_p2p_tunnel.json b/src/generated/resources/data/advancedperipherals/tags/items/p2p_attunements/cable_p2p_tunnel.json new file mode 100644 index 000000000..7fc8269c3 --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/tags/items/p2p_attunements/cable_p2p_tunnel.json @@ -0,0 +1,7 @@ +{ + "values": [ + "computercraft:cable", + "computercraft:wired_modem", + "computercraft:wired_modem_full" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/advancedperipherals/tags/items/smart_glasses.json b/src/generated/resources/data/advancedperipherals/tags/items/smart_glasses.json new file mode 100644 index 000000000..1f793687e --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/tags/items/smart_glasses.json @@ -0,0 +1,6 @@ +{ + "values": [ + "advancedperipherals:smart_glasses", + "advancedperipherals:smart_glasses_netherite" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index ada8618ef..67218e709 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -1,17 +1,20 @@ { "values": [ - "advancedperipherals:environment_detector", + "advancedperipherals:block_reader", "advancedperipherals:chat_box", - "advancedperipherals:player_detector", - "advancedperipherals:me_bridge", - "advancedperipherals:rs_bridge", + "advancedperipherals:colony_integrator", + "advancedperipherals:distance_detector", "advancedperipherals:energy_detector", - "advancedperipherals:peripheral_casing", + "advancedperipherals:environment_detector", + "advancedperipherals:fluid_detector", + "advancedperipherals:gas_detector", + "advancedperipherals:geo_scanner", "advancedperipherals:inventory_manager", + "advancedperipherals:me_bridge", + "advancedperipherals:nbt_storage", + "advancedperipherals:peripheral_casing", + "advancedperipherals:player_detector", "advancedperipherals:redstone_integrator", - "advancedperipherals:block_reader", - "advancedperipherals:geo_scanner", - "advancedperipherals:colony_integrator", - "advancedperipherals:nbt_storage" + "advancedperipherals:rs_bridge" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json index 002d1e917..5a4f0e2b8 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json @@ -1,16 +1,19 @@ { "values": [ - "advancedperipherals:environment_detector", + "advancedperipherals:block_reader", "advancedperipherals:chat_box", - "advancedperipherals:player_detector", - "advancedperipherals:me_bridge", - "advancedperipherals:rs_bridge", + "advancedperipherals:colony_integrator", + "advancedperipherals:distance_detector", "advancedperipherals:energy_detector", + "advancedperipherals:environment_detector", + "advancedperipherals:fluid_detector", + "advancedperipherals:gas_detector", + "advancedperipherals:geo_scanner", "advancedperipherals:inventory_manager", + "advancedperipherals:me_bridge", + "advancedperipherals:nbt_storage", + "advancedperipherals:player_detector", "advancedperipherals:redstone_integrator", - "advancedperipherals:block_reader", - "advancedperipherals:geo_scanner", - "advancedperipherals:colony_integrator", - "advancedperipherals:nbt_storage" + "advancedperipherals:rs_bridge" ] } \ No newline at end of file diff --git a/src/main/java/de/srendi/advancedperipherals/APCreativeTab.java b/src/main/java/de/srendi/advancedperipherals/APCreativeTab.java index dcdd0c566..8489c5f95 100644 --- a/src/main/java/de/srendi/advancedperipherals/APCreativeTab.java +++ b/src/main/java/de/srendi/advancedperipherals/APCreativeTab.java @@ -1,8 +1,8 @@ package de.srendi.advancedperipherals; -import de.srendi.advancedperipherals.common.setup.Blocks; +import de.srendi.advancedperipherals.common.setup.APBlocks; +import de.srendi.advancedperipherals.common.setup.APRegistration; import de.srendi.advancedperipherals.common.setup.CCRegistration; -import de.srendi.advancedperipherals.common.setup.Registration; import de.srendi.advancedperipherals.common.util.inventory.ItemUtil; import net.minecraft.core.NonNullList; import net.minecraft.resources.ResourceLocation; @@ -22,7 +22,7 @@ public APCreativeTab() { @Override public void fillItemList(NonNullList items) { - Registration.ITEMS.getEntries().stream().map(RegistryObject::get).forEach(item -> items.add(new ItemStack(item))); + APRegistration.ITEMS.getEntries().stream().map(RegistryObject::get).forEach(item -> items.add(new ItemStack(item))); items.addAll(pocketUpgrade(CCRegistration.ID.COLONY_POCKET)); items.addAll(pocketUpgrade(CCRegistration.ID.CHATTY_POCKET)); items.addAll(pocketUpgrade(CCRegistration.ID.PLAYER_POCKET)); @@ -32,6 +32,7 @@ public void fillItemList(NonNullList items) { items.addAll(turtleUpgrade(CCRegistration.ID.CHATTY_TURTLE)); items.addAll(turtleUpgrade(CCRegistration.ID.CHUNKY_TURTLE)); items.addAll(turtleUpgrade(CCRegistration.ID.COMPASS_TURTLE)); + items.addAll(turtleUpgrade(CCRegistration.ID.SADDLE_TURTLE)); items.addAll(turtleUpgrade(CCRegistration.ID.PLAYER_TURTLE)); items.addAll(turtleUpgrade(CCRegistration.ID.ENVIRONMENT_TURTLE)); items.addAll(turtleUpgrade(CCRegistration.ID.GEOSCANNER_TURTLE)); @@ -57,6 +58,6 @@ private static Collection turtleUpgrade(ResourceLocation pocketId) { @Override @NotNull public ItemStack makeIcon() { - return new ItemStack(Blocks.CHAT_BOX.get()); + return new ItemStack(APBlocks.CHAT_BOX.get()); } } diff --git a/src/main/java/de/srendi/advancedperipherals/AdvancedPeripherals.java b/src/main/java/de/srendi/advancedperipherals/AdvancedPeripherals.java index 40ab9c1a9..8f7a80ffd 100644 --- a/src/main/java/de/srendi/advancedperipherals/AdvancedPeripherals.java +++ b/src/main/java/de/srendi/advancedperipherals/AdvancedPeripherals.java @@ -1,16 +1,18 @@ package de.srendi.advancedperipherals; import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.addons.ae2.AE2Registries; import de.srendi.advancedperipherals.common.configuration.APConfig; -import de.srendi.advancedperipherals.common.setup.Registration; +import de.srendi.advancedperipherals.common.network.APNetworking; +import de.srendi.advancedperipherals.common.setup.APRegistration; import de.srendi.advancedperipherals.common.village.VillageStructures; -import de.srendi.advancedperipherals.network.APNetworking; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; @@ -26,6 +28,7 @@ public class AdvancedPeripherals { public static final Logger LOGGER = LogManager.getLogger(NAME); public static final Random RANDOM = new Random(); public static final APCreativeTab TAB = new APCreativeTab(); + public static final APAddons ADDONS = new APAddons(); public AdvancedPeripherals() { LOGGER.info("AdvancedPeripherals says hello!"); @@ -34,8 +37,10 @@ public AdvancedPeripherals() { APConfig.register(ModLoadingContext.get()); modBus.addListener(this::commonSetup); - Registration.register(); + modBus.addListener(this::onLoadComplete); + APRegistration.register(); MinecraftForge.EVENT_BUS.register(this); + new APAddons(); } public static void debug(String message) { @@ -48,16 +53,28 @@ public static void debug(String message, Level level) { LOGGER.log(level, "[DEBUG] {}", message); } + public static void exception(String message, Exception exception) { + if (APConfig.GENERAL_CONFIG.enableDebugMode.get()) { + LOGGER.error("[DEBUG]", exception); + } + } + public static ResourceLocation getRL(String resource) { return new ResourceLocation(MOD_ID, resource); } public void commonSetup(FMLCommonSetupEvent event) { - APAddons.commonSetup(); event.enqueueWork(() -> { APNetworking.init(); VillageStructures.init(); }); } + public void onLoadComplete(FMLLoadCompleteEvent event) { + event.enqueueWork(() -> { + if (APAddons.appliedEnergisticsLoaded) { + AE2Registries.finishRegister(); + } + }); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java b/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java new file mode 100644 index 000000000..0dfeb5c28 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java @@ -0,0 +1,85 @@ +package de.srendi.advancedperipherals.client; + +import com.mojang.blaze3d.platform.InputConstants; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.entity.TurtleSeatEntity; +import de.srendi.advancedperipherals.common.network.APNetworking; +import de.srendi.advancedperipherals.common.network.toserver.SaddleTurtleControlPacket; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.Input; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.client.event.MovementInputUpdateEvent; +import net.minecraftforge.client.event.RenderGuiOverlayEvent; +import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; +import net.minecraftforge.event.entity.EntityMountEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod.EventBusSubscriber(modid = AdvancedPeripherals.MOD_ID, value = Dist.CLIENT) +public class ClientEventSubscriber { + @SubscribeEvent + public static void renderingHuds(RenderGuiOverlayEvent.Pre event) { + if (ClientRegistry.SADDLE_TURTLE_OVERLAY.shouldRenderFuelBar() && event.getOverlay().id().equals(VanillaGuiOverlay.EXPERIENCE_BAR.id())) { + event.setCanceled(true); + return; + } + } + + private static boolean sneaking = false; + + @SubscribeEvent + public static void playerTryDismount(InputEvent.Key event) { + Minecraft minecraft = Minecraft.getInstance(); + boolean isShift = minecraft.options.keyShift.matches(event.getKey(), event.getScanCode()); + if (!isShift) { + return; + } + switch (event.getAction()) { + case InputConstants.PRESS: + sneaking = true; + if (ClientRegistry.SADDLE_TURTLE_OVERLAY.isPlayerControllingTurtle()) { + minecraft.options.keyShift.setDown(false); + } + break; + case InputConstants.RELEASE: + sneaking = false; + break; + } + } + + private static Input lastInput = new Input(); + private static boolean lastSneak = false; + + @SubscribeEvent + public static void playerMounting(EntityMountEvent event) { + if (event.isMounting() && event.getEntityMounting() == Minecraft.getInstance().player && event.getEntityBeingMounted() instanceof TurtleSeatEntity) { + // clear last key records + lastInput.up = false; + lastInput.down = false; + lastInput.left = false; + lastInput.right = false; + lastInput.jumping = false; + lastSneak = false; + } + } + + @SubscribeEvent + public static void playerMove(MovementInputUpdateEvent event) { + if (ClientRegistry.SADDLE_TURTLE_OVERLAY.isPlayerControllingTurtle()) { + Input input = event.getInput(); + if (sneaking == lastSneak && lastInput != null) { + if (lastInput.up == input.up && lastInput.down == input.down && lastInput.left == input.left && lastInput.right == input.right && lastInput.jumping == input.jumping) { + return; + } + } + lastInput.up = input.up; + lastInput.down = input.down; + lastInput.left = input.left; + lastInput.right = input.right; + lastInput.jumping = input.jumping; + lastSneak = sneaking; + APNetworking.sendToServer(new SaddleTurtleControlPacket(input.up, input.down, input.left, input.right, input.jumping, sneaking)); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java b/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java index 160836009..9afc8c2dd 100644 --- a/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java +++ b/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java @@ -3,15 +3,25 @@ import dan200.computercraft.api.client.ComputerCraftAPIClient; import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller; import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.common.container.InventoryManagerScreen; +import de.srendi.advancedperipherals.client.renderer.DistanceDetectorRenderer; +import de.srendi.advancedperipherals.client.screens.InventoryManagerScreen; +import de.srendi.advancedperipherals.client.screens.KeyboardScreen; +import de.srendi.advancedperipherals.client.screens.SaddleTurtleOverlay; +import de.srendi.advancedperipherals.client.screens.SmartGlassesScreen; +import de.srendi.advancedperipherals.client.smartglasses.OverlayModuleOverlay; +import de.srendi.advancedperipherals.client.smartglasses.OverlayObjectHolder; +import de.srendi.advancedperipherals.common.setup.APBlockEntityTypes; +import de.srendi.advancedperipherals.common.setup.APContainerTypes; import de.srendi.advancedperipherals.common.setup.CCRegistration; -import de.srendi.advancedperipherals.common.setup.ContainerTypes; import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.EntityRenderersEvent; import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; import net.minecraftforge.client.event.RegisterKeyMappingsEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -21,6 +31,9 @@ public class ClientRegistry { private static final String[] TURTLE_MODELS = new String[]{"turtle_chat_box_upgrade_left", "turtle_chat_box_upgrade_right", "turtle_environment_upgrade_left", "turtle_environment_upgrade_right", "turtle_player_upgrade_left", "turtle_player_upgrade_right", "turtle_geoscanner_upgrade_left", "turtle_geoscanner_upgrade_right"}; + public static final SaddleTurtleOverlay SADDLE_TURTLE_OVERLAY = new SaddleTurtleOverlay(); + public static final OverlayModuleOverlay OVERLAY_MODULE_OVERLAY = new OverlayModuleOverlay(); + @SubscribeEvent public static void registerModels(ModelEvent.RegisterAdditional event) { for (String model : TURTLE_MODELS) { @@ -30,10 +43,13 @@ public static void registerModels(ModelEvent.RegisterAdditional event) { @SubscribeEvent public static void onClientSetup(FMLClientSetupEvent event) { - MenuScreens.register(ContainerTypes.INVENTORY_MANAGER_CONTAINER.get(), InventoryManagerScreen::new); + MenuScreens.register(APContainerTypes.INVENTORY_MANAGER_CONTAINER.get(), InventoryManagerScreen::new); + MenuScreens.register(APContainerTypes.KEYBOARD_CONTAINER.get(), KeyboardScreen::new); + MenuScreens.register(APContainerTypes.SMART_GLASSES_CONTAINER.get(), SmartGlassesScreen::new); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.CHUNKY_TURTLE.get(), TurtleUpgradeModeller.flatItem()); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.COMPASS_TURTLE.get(), TurtleUpgradeModeller.flatItem()); + ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.SADDLE_TURTLE.get(), TurtleUpgradeModeller.flatItem()); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.CHAT_BOX_TURTLE.get(), TurtleUpgradeModeller.sided(new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_chat_box_upgrade_left"), "inventory"), new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_chat_box_upgrade_right"), "inventory"))); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.ENVIRONMENT_TURTLE.get(), TurtleUpgradeModeller.sided(new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_environment_upgrade_left"), "inventory"), new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_environment_upgrade_right"), "inventory"))); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.GEO_SCANNER_TURTLE.get(), TurtleUpgradeModeller.sided(new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_geoscanner_upgrade_left"), "inventory"), new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_geoscanner_upgrade_right"), "inventory"))); @@ -44,16 +60,24 @@ public static void onClientSetup(FMLClientSetupEvent event) { ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.HUSBANDRY_TURTLE.get(), new MetaTurtleUpgradeModeller<>()); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.END_TURTLE.get(), new MetaTurtleUpgradeModeller<>()); ComputerCraftAPIClient.registerTurtleUpgradeModeller(CCRegistration.WEAK_TURTLE.get(), new MetaTurtleUpgradeModeller<>()); + + ItemPropertiesRegistry.register(); + OverlayObjectHolder.registerDecodeObjects(); } @SubscribeEvent - public static void onClientSetup(RegisterKeyMappingsEvent event) { + public static void registeringKeymappings(RegisterKeyMappingsEvent event) { KeyBindings.register(event); } - //TODO change the icon of the curio icon - /*@SubscribeEvent - public static void onTextureStitching(TextureStitchEvent.Pre event) { - event.addSprite(new ResourceLocation(AdvancedPeripherals.MOD_ID, "item/empty_glasses_slot")); - }*/ + @SubscribeEvent + public static void registeringRenderers(EntityRenderersEvent.RegisterRenderers event) { + event.registerBlockEntityRenderer(APBlockEntityTypes.DISTANCE_DETECTOR.get(), DistanceDetectorRenderer::new); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void registeringOverlays(RegisterGuiOverlaysEvent event) { + event.registerAboveAll(SaddleTurtleOverlay.ID, SADDLE_TURTLE_OVERLAY); + event.registerAboveAll(OverlayModuleOverlay.ID, OVERLAY_MODULE_OVERLAY); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/client/ClientWorker.java b/src/main/java/de/srendi/advancedperipherals/client/ClientWorker.java new file mode 100644 index 000000000..f29e94db7 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/ClientWorker.java @@ -0,0 +1,34 @@ +package de.srendi.advancedperipherals.client; + +import de.srendi.advancedperipherals.AdvancedPeripherals; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Mod.EventBusSubscriber(value = Dist.CLIENT, modid = AdvancedPeripherals.MOD_ID) +public class ClientWorker { + + private static final Map tasks = new ConcurrentHashMap<>(); + + /** + * This method will put a task to current tick's end. + * If a task with given identifier is already exists, the task will be replaced. + */ + public static void put(final String id, final Runnable task) { + tasks.put(id, task); + } + + @SubscribeEvent + public static void clientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + tasks.forEach((id, runnable) -> { + tasks.remove(id, runnable); + runnable.run(); + }); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/ItemPropertiesRegistry.java b/src/main/java/de/srendi/advancedperipherals/client/ItemPropertiesRegistry.java new file mode 100644 index 000000000..00ef43539 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/ItemPropertiesRegistry.java @@ -0,0 +1,17 @@ +package de.srendi.advancedperipherals.client; + +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.setup.APItems; +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.resources.ResourceLocation; + +public class ItemPropertiesRegistry { + + public static void register() { + ItemProperties.register(APItems.MEMORY_CARD.get(), new ResourceLocation(AdvancedPeripherals.MOD_ID, "bounded"), (stack, level, entity, seed) -> { + boolean bounded = stack.getOrCreateTag().contains("owner"); + return bounded ? 1 : 0; + }); + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/KeyBindings.java b/src/main/java/de/srendi/advancedperipherals/client/KeyBindings.java index 2cbd46438..37cea5f0d 100644 --- a/src/main/java/de/srendi/advancedperipherals/client/KeyBindings.java +++ b/src/main/java/de/srendi/advancedperipherals/client/KeyBindings.java @@ -7,9 +7,11 @@ public class KeyBindings { public static final KeyMapping DESCRIPTION_KEYBINDING = new KeyMapping("keybind.advancedperipherals.description", GLFW.GLFW_KEY_LEFT_CONTROL, "keybind.advancedperipherals.category"); + public static final KeyMapping GLASSES_HOTKEY_KEYBINDING = new KeyMapping("keybind.advancedperipherals.glasses_hotkey", GLFW.GLFW_KEY_G, "keybind.advancedperipherals.category"); public static void register(RegisterKeyMappingsEvent event) { event.register(DESCRIPTION_KEYBINDING); + event.register(GLASSES_HOTKEY_KEYBINDING); } } diff --git a/src/main/java/de/srendi/advancedperipherals/client/RenderUtil.java b/src/main/java/de/srendi/advancedperipherals/client/RenderUtil.java new file mode 100644 index 000000000..4a4826238 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/RenderUtil.java @@ -0,0 +1,367 @@ +package de.srendi.advancedperipherals.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; +import com.mojang.math.Quaternion; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.InventoryMenu; + +public class RenderUtil { + + public static void drawBox(PoseStack poseStack, VertexConsumer buffer, float r, float g, float b, float a, float pX, float pY, float pZ, float xRot, float yRot, float zRot, float sX, float sY, float sZ) { + poseStack.pushPose(); + sX = sX / 16; //Sizes in pixels please + sY = sY / 16; + sZ = sZ / 16; + pX = pX / 16; + pY = pY / 16; + pZ = pZ / 16; + + poseStack.mulPose(new Quaternion(xRot, yRot, zRot, true)); + + drawPlane(poseStack, buffer, r, g, b, a, Direction.UP, pX, pY, pZ, sX, sY, sZ); + drawPlane(poseStack, buffer, r, g, b, a, Direction.DOWN, pX, pY, pZ, sX, sY, sZ); + drawPlane(poseStack, buffer, r, g, b, a, Direction.EAST, pX, pY, pZ, sX, sY, sZ); + drawPlane(poseStack, buffer, r, g, b, a, Direction.WEST, pX, pY, pZ, sX, sY, sZ); + drawPlane(poseStack, buffer, r, g, b, a, Direction.NORTH, pX, pY, pZ, sX, sY, sZ); + drawPlane(poseStack, buffer, r, g, b, a, Direction.SOUTH, pX, pY, pZ, sX, sY, sZ); + poseStack.popPose(); + } + + public static void drawPlane(PoseStack posestack, VertexConsumer buffer, float r, float g, float b, float a, Direction perspective, float pX, float pY, float pZ, float sX, float sY, float sZ) { + posestack.pushPose(); + + pX = pX + 0.5f; + pY = pY + 0.5f; + pZ = pZ + 0.5f; + + posestack.translate(pX, pY, pZ); + + Matrix4f matrix4f = posestack.last().pose(); + + sX = sX / 2; + sY = sY / 2; + sZ = sZ / 2; + + + if (perspective == Direction.UP) { + buffer.vertex(matrix4f, -sX, sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + } + if (perspective == Direction.DOWN) { + buffer.vertex(matrix4f, -sX, -sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, -sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + } + if (perspective == Direction.SOUTH) { + buffer.vertex(matrix4f, sX, -sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + } + if (perspective == Direction.NORTH) { + buffer.vertex(matrix4f, -sX, -sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, -sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + } + if (perspective == Direction.EAST) { + buffer.vertex(matrix4f, -sX, -sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, -sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + } + if (perspective == Direction.WEST) { + buffer.vertex(matrix4f, -sX, -sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, sZ).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + } + posestack.popPose(); + } + + public static void drawTorus(PoseStack poseStack, VertexConsumer consumer, float majorRadius, float minorRadius, double pX, double pY, double pZ, float xRot, float yRot, float zRot, float r, float g, float b, float a, int sides, int rings) { + poseStack.pushPose(); + poseStack.translate(pX, pY, pZ); + poseStack.mulPose(new Quaternion(xRot, yRot, zRot, true)); + + Matrix4f matrix4f = poseStack.last().pose(); + TextureAtlasSprite texture = Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(new ResourceLocation("block/crimson_stem")); + + float x, y, z; + float nx, ny, nz; + + float ringStep = (float) (2 * Math.PI / rings); + float sideStep = (float) (2 * Math.PI / sides); + float ringAngle, sideAngle; + + for (int i = 0; i < rings; ++i) { + ringAngle = i * ringStep; + float cosRingAngle = (float) Math.cos(ringAngle); + float sinRingAngle = (float) Math.sin(ringAngle); + + float nextRingAngle = (i + 1) * ringStep; + float nextCosRingAngle = (float) Math.cos(nextRingAngle); + float nextSinRingAngle = (float) Math.sin(nextRingAngle); + + // Calculate the center point of the minor circles + float centerX = majorRadius * cosRingAngle; + float centerY = majorRadius * sinRingAngle; + float nextCenterX = majorRadius * nextCosRingAngle; + float nextCenterY = majorRadius * nextSinRingAngle; + + for (int j = 0; j < sides; ++j) { + sideAngle = j * sideStep; + float cosSideAngle = (float) Math.cos(sideAngle); + float sinSideAngle = (float) Math.sin(sideAngle); + + float nextSideAngle = (j + 1) * sideStep; + float nextCosSideAngle = (float) Math.cos(nextSideAngle); + float nextSinSideAngle = (float) Math.sin(nextSideAngle); + + float s = j / sides; + float t = i / rings; + + float u1 = getU(s * sides, texture.getU1(), texture.getU0(), sides); + float u2 = getU((s + 1.0f / sides) * sides, texture.getU1(), texture.getU0(), sides); + float v1 = getV(t * rings, texture.getV1(), texture.getV0(), rings); + float v2 = getV((t + 1.0f / rings) * rings, texture.getV1(), texture.getV0(), rings); + + x = centerX + minorRadius * nextCosSideAngle * cosRingAngle; + y = centerY + minorRadius * nextCosSideAngle * sinRingAngle; + z = minorRadius * nextSinSideAngle; + + nx = x - centerX; + ny = y - centerY; + nz = z; + consumer.vertex(matrix4f, x, y, z).color(r, g, b, a).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx, ny, nz).endVertex(); + + // Calculate vertex positions + x = centerX + minorRadius * cosSideAngle * cosRingAngle; + y = centerY + minorRadius * cosSideAngle * sinRingAngle; + z = minorRadius * sinSideAngle; + + // Calculate normal + nx = x - centerX; + ny = y - centerY; + nz = z; + + consumer.vertex(matrix4f, x, y, z).color(r, g, b, a).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx, ny, nz).endVertex(); + + x = nextCenterX + minorRadius * cosSideAngle * nextCosRingAngle; + y = nextCenterY + minorRadius * cosSideAngle * nextSinRingAngle; + z = minorRadius * sinSideAngle; + + nx = x - nextCenterX; + ny = y - nextCenterY; + nz = z; + consumer.vertex(matrix4f, x, y, z).color(r, g, b, a).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx, ny, nz).endVertex(); + + + x = nextCenterX + minorRadius * nextCosSideAngle * nextCosRingAngle; + y = nextCenterY + minorRadius * nextCosSideAngle * nextSinRingAngle; + z = minorRadius * nextSinSideAngle; + + nx = x - nextCenterX; + ny = y - nextCenterY; + nz = z; + consumer.vertex(matrix4f, x, y, z).color(r, g, b, a).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx, ny, nz).endVertex(); + } + } + + poseStack.popPose(); + } + + public static void drawSphere(PoseStack poseStack, VertexConsumer consumer, float radius, double pX, double pY, double pZ, float xRot, float yRot, float zRot, float r, float g, float b, float a, int sectors, int stacks) { + poseStack.pushPose(); + poseStack.translate(pX, pY, pZ); + poseStack.mulPose(new Quaternion(xRot, yRot, zRot, true)); + + Matrix4f matrix4f = poseStack.last().pose(); + TextureAtlasSprite texture = Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(new ResourceLocation("block/dirt")); + + float z, xy; + float nx1, ny1, nz1, nx2, ny2, nz2, nx3, ny3, nz3, nx4, ny4, nz4, lengthInv = (1.0f / radius); // vertex normal + float s, t; + + float sectorStep = (float) (2 * Math.PI / sectors); + float stackStep = (float) (Math.PI / stacks); + float sectorAngle, stackAngle; + + for (int i = 1; i <= stacks; ++i) { + stackAngle = (float) (Math.PI / 2 - i * stackStep); + + xy = (float) (radius * Math.cos(stackAngle)); + z = (float) (radius * Math.sin(stackAngle)); + + for (int j = 0; j < sectors; ++j) { + + sectorAngle = j * sectorStep; + + float x1 = (float) (xy * Math.cos(sectorAngle)); + float y1 = (float) (xy * Math.sin(sectorAngle)); + + float x2 = (float) (xy * Math.cos(sectorAngle + sectorStep)); + float y2 = (float) (xy * Math.sin(sectorAngle + sectorStep)); + + float x3 = (float) (radius * Math.cos(stackAngle + stackStep) * Math.cos(sectorAngle + sectorStep)); + float y3 = (float) (radius * Math.cos(stackAngle + stackStep) * Math.sin(sectorAngle + sectorStep)); + float z3 = (float) (radius * Math.sin(stackAngle + stackStep)); + + float x4 = (float) (radius * Math.cos(stackAngle + stackStep) * Math.cos(sectorAngle)); + float y4 = (float) (radius * Math.cos(stackAngle + stackStep) * Math.sin(sectorAngle)); + float z4 = (float) (radius * Math.sin(stackAngle + stackStep)); + + nx1 = x1 * lengthInv; + ny1 = y1 * lengthInv; + nz1 = z * lengthInv; + + nx2 = x2 * lengthInv; + ny2 = y2 * lengthInv; + nz2 = z * lengthInv; + + nx3 = x3 * lengthInv; + ny3 = y3 * lengthInv; + nz3 = z3 * lengthInv; + + nx4 = x4 * lengthInv; + ny4 = y4 * lengthInv; + nz4 = z4 * lengthInv; + + s = j / sectors; + t = i / stacks; + + float u1 = getU(s * sectors, texture.getU1(), texture.getU0(), sectors); + float u2 = getU((s + 1.0d / sectors) * sectors, texture.getU1(), texture.getU0(), sectors); + float v1 = getV(t * stacks, texture.getV1(), texture.getV0(), stacks); + float v2 = getV((t + 1.0d / stacks) * stacks, texture.getV1(), texture.getV0(), stacks); + + // For a reason which I am too dumb to understand, the uv coords have a one pixel offset + // So... I just reverse it and it works + v1 -= (texture.getV1() - texture.getV0()) / stacks; + v2 -= (texture.getV1() - texture.getV0()) / stacks; + + consumer.vertex(matrix4f, x1, y1, z).color(r, g, b, a).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx1, ny1, nz1).endVertex(); + consumer.vertex(matrix4f, x2, y2, z).color(r, g, b, a).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx2, ny2, nz2).endVertex(); + consumer.vertex(matrix4f, x3, y3, z3).color(r, g, b, a).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx3, ny3, nz3).endVertex(); + consumer.vertex(matrix4f, x4, y4, z4).color(r, g, b, a).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(nx4, ny4, nz4).endVertex(); + + } + } + poseStack.popPose(); + + } + + private static float getU(double pU, float u1, float u0, float resolution) { + float f = u1 - u0; + return u0 + f * (float) pU / resolution; + } + + private static float getV(double pV, float v1, float v0, float resolution) { + float f = v1 - v0; + return v0 + f * (float) pV / resolution; + } + + public static void drawBox(PoseStack poseStack, VertexConsumer buffer, ResourceLocation texture, float pX, float pY, float pZ, float xRot, float yRot, float zRot, float sX, float sY, float sZ, float pUOffset, float pVOffset, float pWidth, float pHeight) { + poseStack.pushPose(); + sX = sX / 16; //Sizes in pixels please + sY = sY / 16; + sZ = sZ / 16; + pX = pX / 16; + pY = pY / 16; + pZ = pZ / 16; + + poseStack.mulPose(new Quaternion(xRot, yRot, zRot, true)); + + drawPlane(poseStack, buffer, texture, Direction.UP, pX, pY, pZ, sX, sY, sZ, pUOffset, pVOffset, pWidth, pHeight); + drawPlane(poseStack, buffer, texture, Direction.DOWN, pX, pY, pZ, sX, sY, sZ, pUOffset, pVOffset, pWidth, pHeight); + drawPlane(poseStack, buffer, texture, Direction.EAST, pX, pY, pZ, sX, sY, sZ, pUOffset, pVOffset, pWidth, pHeight); + drawPlane(poseStack, buffer, texture, Direction.WEST, pX, pY, pZ, sX, sY, sZ, pUOffset, pVOffset, pWidth, pHeight); + drawPlane(poseStack, buffer, texture, Direction.NORTH, pX, pY, pZ, sX, sY, sZ, pUOffset, pVOffset, pWidth, pHeight); + drawPlane(poseStack, buffer, texture, Direction.SOUTH, pX, pY, pZ, sX, sY, sZ, pUOffset, pVOffset, pWidth, pHeight); + poseStack.popPose(); + } + + public static void drawPlane(PoseStack poseStack, VertexConsumer buffer, ResourceLocation texture, Direction perspective, float pX, float pY, float pZ, float sX, float sY, float sZ, float pUOffset, float pVOffset, float pWidth, float pHeight) { + poseStack.pushPose(); + + pX = pX + 0.5f; + pY = pY + 0.5f; + pZ = pZ + 0.5f; + + poseStack.translate(pX, pY, pZ); + + Matrix4f matrix4f = poseStack.last().pose(); + + TextureAtlasSprite stillTexture = Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture); + + sX = sX / 2; + sY = sY / 2; + sZ = sZ / 2; + + float u1 = stillTexture.getU(pUOffset); + float u2 = stillTexture.getU(pWidth); + float v1 = stillTexture.getV(pVOffset); + float v2 = stillTexture.getV(pHeight); + + if (perspective == Direction.UP) { + buffer.vertex(matrix4f, -sX, sY, sZ).color(1, 1, 1, 1f).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, sZ).color(1, 1, 1, 1f).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, -sZ).color(1, 1, 1, 1f).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, -sZ).color(1, 1, 1, 1f).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + } + if (perspective == Direction.DOWN) { + buffer.vertex(matrix4f, -sX, -sY, sZ).color(1, 1, 1, 1f).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, -sY, -sZ).color(1, 1, 1, 1f).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, -sZ).color(1, 1, 1, 1f).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, sZ).color(1, 1, 1, 1f).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, -1f, 0f).endVertex(); + } + if (perspective == Direction.SOUTH) { + buffer.vertex(matrix4f, sX, -sY, sZ).color(1, 1, 1, 1f).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, -sZ).color(1, 1, 1, 1f).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, -sZ).color(1, 1, 1, 1f).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, sZ).color(1, 1, 1, 1f).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + } + if (perspective == Direction.NORTH) { + buffer.vertex(matrix4f, -sX, -sY, sZ).color(1, 1, 1, 1f).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, sZ).color(1, 1, 1, 1f).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, -sZ).color(1, 1, 1, 1f).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, -sY, -sZ).color(1, 1, 1, 1f).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(1f, 0f, 0f).endVertex(); + } + if (perspective == Direction.EAST) { + buffer.vertex(matrix4f, -sX, -sY, -sZ).color(1, 1, 1, 1f).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, -sZ).color(1, 1, 1, 1f).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, -sZ).color(1, 1, 1, 1f).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, -sZ).color(1, 1, 1, 1f).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + } + if (perspective == Direction.WEST) { + buffer.vertex(matrix4f, -sX, -sY, sZ).color(1, 1, 1, 1f).uv(u1, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, -sY, sZ).color(1, 1, 1, 1f).uv(u1, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, sX, sY, sZ).color(1, 1, 1, 1f).uv(u2, v1).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + buffer.vertex(matrix4f, -sX, sY, sZ).color(1, 1, 1, 1f).uv(u2, v2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(0xF000F0).normal(0f, 1f, 0f).endVertex(); + } + poseStack.popPose(); + } + + public static float getBlue(int hex) { + return (hex & 0xFF) / 255.0F; + } + + public static float getGreen(int hex) { + return (hex >> 8 & 0xFF) / 255.0F; + } + + public static float getRed(int hex) { + return (hex >> 16 & 0xFF) / 255.0F; + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/renderer/DistanceDetectorRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/renderer/DistanceDetectorRenderer.java new file mode 100644 index 000000000..a0b6f8a7c --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/renderer/DistanceDetectorRenderer.java @@ -0,0 +1,104 @@ +package de.srendi.advancedperipherals.client.renderer; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.common.blocks.base.BaseBlock; +import de.srendi.advancedperipherals.common.blocks.blockentities.DistanceDetectorEntity; +import de.srendi.advancedperipherals.common.util.EnumColor; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BeaconRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; + +public class DistanceDetectorRenderer implements BlockEntityRenderer { + + public DistanceDetectorRenderer(BlockEntityRendererProvider.Context pContext) { + super(); + } + + @Override + public void render(@NotNull DistanceDetectorEntity pBlockEntity, float pPartialTick, @NotNull PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pPackedOverlay) { + if (pBlockEntity.getShowLaser()) { + float distance = pBlockEntity.getCurrentDistance(); + float[] color = EnumColor.RED.getRgb(); + if (distance == -1) { + distance = pBlockEntity.getMaxRange(); + color = EnumColor.DARK_RED.getRgb(); + } + renderBeaconBeam(pBlockEntity, pPoseStack, pBufferSource, BeaconRenderer.BEAM_LOCATION, pPartialTick, 1, 0, distance + 0.5f, color, 0.05f, 0.09f); + } + } + + @Override + public boolean shouldRenderOffScreen(@NotNull DistanceDetectorEntity pBlockEntity) { + return true; + } + + @Override + public int getViewDistance() { + return 256; + } + + @Override + public boolean shouldRender(@NotNull DistanceDetectorEntity pBlockEntity, @NotNull Vec3 pCameraPos) { + return true; + } + + public static void renderBeaconBeam(DistanceDetectorEntity detectorEntity, PoseStack pPoseStack, MultiBufferSource pBufferSource, ResourceLocation pBeamLocation, float pPartialTick, float pTextureScale, int pYOffset, float pHeight, float[] pColors, float pBeamRadius, float pGlowRadius) { + long pGameTime = detectorEntity.getLevel().getGameTime(); + float maxX = pYOffset + pHeight; + Direction direction = detectorEntity.getBlockState().getValue(BaseBlock.ORIENTATION).front(); + pPoseStack.pushPose(); + pPoseStack.translate(0.5D, 0.5D, 0.5D); + float degrees = Math.floorMod(pGameTime, 360) + pPartialTick; + float reversedDegrees = pHeight < 0 ? degrees : -degrees; + float time = Mth.frac(reversedDegrees * 0.2F - Mth.floor(reversedDegrees * 0.1F)); + float r = pColors[0]; + float g = pColors[1]; + float b = pColors[2]; + pPoseStack.pushPose(); + pPoseStack.mulPose(direction.getRotation()); + pPoseStack.mulPose(Vector3f.YP.rotationDegrees(degrees * 2.25F - 45.0F)); + float f15 = -1.0F + time; + float f16 = pHeight * pTextureScale * (0.5F / pBeamRadius) + f15; + renderPart(pPoseStack, pBufferSource.getBuffer(RenderType.beaconBeam(pBeamLocation, false)), r, g, b, 1.0F, pYOffset, maxX, 0.0F, pBeamRadius, pBeamRadius, 0.0F, -pBeamRadius, 0.0F, 0.0F, -pBeamRadius, 0.0F, 1.0F, f16, f15); + pPoseStack.popPose(); + pPoseStack.mulPose(direction.getRotation()); + f15 = -1.0F + time; + f16 = pHeight * pTextureScale + f15; + renderPart(pPoseStack, pBufferSource.getBuffer(RenderType.beaconBeam(pBeamLocation, true)), r, g, b, 0.225F, pYOffset, maxX, -pGlowRadius, -pGlowRadius, pGlowRadius, -pGlowRadius, -pBeamRadius, pGlowRadius, pGlowRadius, pGlowRadius, 0.0F, 1.0F, f16, f15); + pPoseStack.popPose(); + } + + private static void renderPart(PoseStack pPoseStack, VertexConsumer pConsumer, float pRed, float pGreen, float pBlue, float pAlpha, int pMinY, float pMaxY, float pX0, float pZ0, float pX1, float pZ1, float pX2, float pZ2, float pX3, float pZ3, float pMinU, float pMaxU, float pMinV, float pMaxV) { + PoseStack.Pose posestackPose = pPoseStack.last(); + Matrix4f matrix4f = posestackPose.pose(); + Matrix3f matrix3f = posestackPose.normal(); + renderQuad(matrix4f, matrix3f, pConsumer, pRed, pGreen, pBlue, pAlpha, pMinY, pMaxY, pX0, pZ0, pX1, pZ1, pMinU, pMaxU, pMinV, pMaxV); + renderQuad(matrix4f, matrix3f, pConsumer, pRed, pGreen, pBlue, pAlpha, pMinY, pMaxY, pX3, pZ3, pX2, pZ2, pMinU, pMaxU, pMinV, pMaxV); + renderQuad(matrix4f, matrix3f, pConsumer, pRed, pGreen, pBlue, pAlpha, pMinY, pMaxY, pX1, pZ1, pX3, pZ3, pMinU, pMaxU, pMinV, pMaxV); + renderQuad(matrix4f, matrix3f, pConsumer, pRed, pGreen, pBlue, pAlpha, pMinY, pMaxY, pX2, pZ2, pX0, pZ0, pMinU, pMaxU, pMinV, pMaxV); + } + + private static void renderQuad(Matrix4f pPose, Matrix3f pNormal, VertexConsumer pConsumer, float pRed, float pGreen, float pBlue, float pAlpha, int pMinY, float pMaxY, float pMinX, float pMinZ, float pMaxX, float pMaxZ, float pMinU, float pMaxU, float pMinV, float pMaxV) { + addVertex(pPose, pNormal, pConsumer, pRed, pGreen, pBlue, pAlpha, pMaxY, pMinX, pMinZ, pMaxU, pMinV); + addVertex(pPose, pNormal, pConsumer, pRed, pGreen, pBlue, pAlpha, pMinY, pMinX, pMinZ, pMaxU, pMaxV); + addVertex(pPose, pNormal, pConsumer, pRed, pGreen, pBlue, pAlpha, pMinY, pMaxX, pMaxZ, pMinU, pMaxV); + addVertex(pPose, pNormal, pConsumer, pRed, pGreen, pBlue, pAlpha, pMaxY, pMaxX, pMaxZ, pMinU, pMinV); + } + + private static void addVertex(Matrix4f pPose, Matrix3f pNormal, VertexConsumer pConsumer, float pRed, float pGreen, float pBlue, float pAlpha, float pY, float pX, float pZ, float pU, float pV) { + pConsumer.vertex(pPose, pX, pY, pZ).color(pRed, pGreen, pBlue, pAlpha).uv(pU, pV).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(15728880).normal(pNormal, 0.0F, 1.0F, 0.0F).endVertex(); + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/container/InventoryManagerScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/InventoryManagerScreen.java similarity index 78% rename from src/main/java/de/srendi/advancedperipherals/common/container/InventoryManagerScreen.java rename to src/main/java/de/srendi/advancedperipherals/client/screens/InventoryManagerScreen.java index e4d88e29c..d1730b50b 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/container/InventoryManagerScreen.java +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/InventoryManagerScreen.java @@ -1,7 +1,8 @@ -package de.srendi.advancedperipherals.common.container; +package de.srendi.advancedperipherals.client.screens; import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.common.container.base.BaseScreen; +import de.srendi.advancedperipherals.client.screens.base.BaseScreen; +import de.srendi.advancedperipherals.common.container.InventoryManagerContainer; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; diff --git a/src/main/java/de/srendi/advancedperipherals/client/screens/KeyboardScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/KeyboardScreen.java new file mode 100644 index 000000000..e4898b1e4 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/KeyboardScreen.java @@ -0,0 +1,251 @@ +// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers +// SPDX-FileCopyrightText: 2025 The AdvancedPeripheral Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package de.srendi.advancedperipherals.client.screens; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import dan200.computercraft.client.gui.ClientInputHandler; +import dan200.computercraft.client.gui.widgets.WidgetTerminal; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.core.InputHandler; +import de.srendi.advancedperipherals.client.ClientWorker; +import de.srendi.advancedperipherals.common.container.KeyboardContainer; +import de.srendi.advancedperipherals.common.network.APNetworking; +import de.srendi.advancedperipherals.common.network.toserver.KeyboardMouseClickPacket; +import de.srendi.advancedperipherals.common.network.toserver.KeyboardMouseMovePacket; +import de.srendi.advancedperipherals.common.network.toserver.KeyboardMouseScrollPacket; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.glfw.GLFW; + +/** + * A simple screen but without any rendering calls. Used to unlock the mouse so we can freely write stuff + * + * We just create a terminal which is used to forward all the key presses and mouse clicks but we don't render it. + */ +public class KeyboardScreen extends Screen implements MenuAccess { + + protected final KeyboardContainer keyboardContainer; + protected final InputHandler input; + private final Terminal terminalData; + private WidgetTerminal terminal; + private MouseState mouseState = MouseState.RELEASED; + private boolean captureMouse; + private boolean regrabingMouse; + private final byte[] lastPosLock = new byte[0]; + private double lastX = 0; + private double lastY = 0; + private double lastScroll = 0; + + public KeyboardScreen(KeyboardContainer keyboardContainer, Inventory inv, Component titleIn) { + super(titleIn); + this.keyboardContainer = keyboardContainer; + this.input = new ClientInputHandler(keyboardContainer); + this.terminalData = new Terminal(0, 0, false); + } + + @Override + public KeyboardContainer getMenu() { + return this.keyboardContainer; + } + + @Override + public void render(@NotNull PoseStack poseStack, int x, int y, float partialTicks) { + super.render(poseStack, x, y, partialTicks); + + Minecraft minecraft = Minecraft.getInstance(); + float scale = 2f; + int screenWidth = minecraft.getWindow().getGuiScaledWidth(); + // Make the text a bit smaller on small screens + if (screenWidth <= 1080) + scale = 1f; + + poseStack.scale(scale, scale, 1); + Component text = Component.translatable("text.advancedperipherals.keyboard.close"); + float textX = (screenWidth / 2f - minecraft.font.width(text) * scale / 2f) / scale; + minecraft.font.drawShadow(poseStack, text, textX, 1, 0xFFFFFF); + } + + @Override + protected void init() { + if (this.isCapturingMouse()) { + this.grabMouse(); + } else { + this.grabMouseWithControl(); + } + this.passEvents = true; + KeyMapping.releaseAll(); + + super.init(); + this.minecraft.keyboardHandler.setSendRepeatsToGui(true); + + this.terminal = addWidget(new WidgetTerminal(terminalData, new ClientInputHandler(this.keyboardContainer), 0, 0)); + this.terminal.visible = false; + this.terminal.active = false; + setFocused(this.terminal); + } + + @Override + public final void removed() { + if (this.regrabingMouse) { + return; + } + super.removed(); + if (this.minecraft.player != null) { + this.keyboardContainer.removed(this.minecraft.player); + } + this.minecraft.keyboardHandler.setSendRepeatsToGui(false); + } + + @Override + public void onClose() { + // Don't allow closing using standard keys like E. Closing using ESCAPE is still possible due to the keyPressed method + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public void mouseMoved(double x, double y) { + if (this.mouseState != MouseState.CAPTURE) { + return; + } + ClientWorker.put("mouse_move", () -> { + synchronized (this.lastPosLock) { + double dx = x - this.lastX; + double dy = y - this.lastY; + APNetworking.sendToServer(new KeyboardMouseMovePacket(dx, dy)); + this.lastX = x; + this.lastY = y; + } + }); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + if (this.mouseState != MouseState.CAPTURE) { + return false; + } + APNetworking.sendToServer(new KeyboardMouseClickPacket(button, false)); + return true; + } + + @Override + public boolean mouseReleased(double x, double y, int button) { + if (this.mouseState != MouseState.CAPTURE) { + return false; + } + APNetworking.sendToServer(new KeyboardMouseClickPacket(button, true)); + return true; + } + + @Override + public boolean mouseScrolled(double x, double y, double direction) { + this.lastScroll += direction; + int scrolled = (int) this.lastScroll; + if (scrolled == 0) { + return true; + } + if (this.mouseState == MouseState.CAPTURE) { + ClientWorker.put("mouse_scroll", () -> { + if (this.mouseState != MouseState.CAPTURE) { + return; + } + this.lastScroll -= scrolled; + APNetworking.sendToServer(new KeyboardMouseScrollPacket(scrolled)); + }); + } else { + this.lastScroll -= scrolled; + minecraft.player.getInventory().swapPaint(scrolled); + } + return true; + } + + @Override + public final boolean keyPressed(int key, int scancode, int modifiers) { + if (key == GLFW.GLFW_KEY_ESCAPE) { + if (this.minecraft.player != null) { + this.minecraft.player.closeContainer(); + } else { + super.onClose(); + } + return true; + } + // Forward the tab key to the terminal, rather than moving between controls. + if (key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) { + return getFocused().keyPressed(key, scancode, modifiers); + } + + return super.keyPressed(key, scancode, modifiers); + } + + public boolean isCapturingMouse() { + return this.captureMouse; + } + + public void setCaptureMouse(boolean enable) { + this.captureMouse = enable; + if (enable) { + this.grabMouse(); + } else { + this.grabMouseWithControl(); + } + } + + private void grabMouseWithControl() { + if (this.mouseState == MouseState.NORMAL) { + return; + } + this.releaseMouse(); + this.regrabingMouse = true; + this.minecraft.mouseHandler.grabMouse(); + this.regrabingMouse = false; + this.minecraft.screen = this; + this.mouseState = MouseState.NORMAL; + } + + private void grabMouse() { + if (this.minecraft.mouseHandler.isMouseGrabbed()) { + this.minecraft.mouseHandler.releaseMouse(); + } + Window window = this.minecraft.getWindow(); + synchronized (this.lastPosLock) { + this.lastX = window.getScreenWidth() / 2; + this.lastY = window.getScreenHeight() / 2; + InputConstants.grabOrReleaseMouse(window.getWindow(), InputConstants.CURSOR_DISABLED, this.lastX, this.lastY); + } + this.mouseState = MouseState.CAPTURE; + } + + private void releaseMouse() { + if (this.mouseState == MouseState.RELEASED) { + return; + } + if (this.minecraft.mouseHandler.isMouseGrabbed()) { + this.minecraft.mouseHandler.releaseMouse(); + return; + } + Window window = this.minecraft.getWindow(); + synchronized (this.lastPosLock) { + this.lastX = window.getScreenWidth() / 2; + this.lastY = window.getScreenHeight() / 2; + InputConstants.grabOrReleaseMouse(window.getWindow(), InputConstants.CURSOR_NORMAL, this.lastX, this.lastY); + } + this.mouseState = MouseState.RELEASED; + } + + private enum MouseState { + RELEASED, NORMAL, CAPTURE + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/screens/SaddleTurtleOverlay.java b/src/main/java/de/srendi/advancedperipherals/client/screens/SaddleTurtleOverlay.java new file mode 100644 index 000000000..60bb4cccf --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/SaddleTurtleOverlay.java @@ -0,0 +1,156 @@ +package de.srendi.advancedperipherals.client.screens; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.entity.TurtleSeatEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.util.FormattedCharSequence; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.client.gui.overlay.IGuiOverlay; + +public class SaddleTurtleOverlay extends GuiComponent implements IGuiOverlay { + public static final String ID = "saddle_turtle_overlay"; + + private static final long ACTIVE_TIMEOUT = 5000; + + private ForgeGui gui; + private int screenWidth = 0; + private int screenHeight = 0; + + private int fuelLevel = 0; + private int fuelLimit = 0; + private int barColor = 0; + private long lastActived = 0; + + public SaddleTurtleOverlay() {} + + protected Font getFont() { + return this.gui.getMinecraft().font; + } + + protected int textWidth(String text) { + return getFont().width(text); + } + + protected int textWidth(FormattedText text) { + return getFont().width(text); + } + + protected int textWidth(FormattedCharSequence text) { + return getFont().width(text); + } + + public boolean isPlayerControllingTurtle() { + LocalPlayer player = Minecraft.getInstance().player; + return player != null && player.getVehicle() instanceof TurtleSeatEntity; + } + + public boolean isPlayerMountedOnTurtle() { + LocalPlayer player = Minecraft.getInstance().player; + return player != null && player.getRootVehicle() instanceof TurtleSeatEntity; + } + + public boolean shouldRenderFuelBar() { + if (this.lastActived == 0) { + return false; + } + if (!this.isPlayerMountedOnTurtle()) { + this.hide(); + return false; + } + return this.lastActived + ACTIVE_TIMEOUT > System.currentTimeMillis(); + } + + public void hide() { + this.fuelLevel = 0; + this.fuelLimit = 0; + this.barColor = 0; + this.lastActived = 0; + } + + public void keepAlive() { + this.lastActived = System.currentTimeMillis(); + } + + public void setFuelLevel(int level) { + if (level < 0) { + level = 0; + } + if (this.fuelLevel != level) { + this.fuelLevel = level; + this.keepAlive(); + } + } + + public void setFuelLimit(int limit) { + if (this.fuelLimit != limit) { + this.fuelLimit = limit; + this.keepAlive(); + } + } + + public void setBarColor(int color) { + if (this.barColor != color) { + this.barColor = color; + this.keepAlive(); + } + } + + private void renderFuelBar(PoseStack stack) { + // TODO: use a better looking bar here, and/or find someway to change the bar's color + RenderSystem.setShaderTexture(0, GuiComponent.GUI_ICONS_LOCATION); + int fontColor = 0x80ff20; + + int width = 182; + int left = this.screenWidth / 2 - 91; + int top = this.screenHeight - 32 + 3; + this.blit(stack, left, top, 0, 64, width, 5); + if (fuelLevel > 0 && fuelLimit > 0) { + int progWidth = fuelLevel * width / fuelLimit; + this.blit(stack, left, top, 0, 69, progWidth, 5); + } + + String text = fuelLimit > 0 ? String.format("%d / %d", fuelLevel, fuelLimit) : "Infinity"; + int x = (this.screenWidth - getFont().width(text)) / 2; + int y = this.screenHeight - 31; + getFont().draw(stack, text, (float)(x + 1), (float) y, 0); + getFont().draw(stack, text, (float)(x - 1), (float) y, 0); + getFont().draw(stack, text, (float) x, (float)(y + 1), 0); + getFont().draw(stack, text, (float) x, (float)(y - 1), 0); + getFont().draw(stack, text, (float) x, (float) y, fontColor); + } + + private void renderDismountHint(PoseStack stack) { + Minecraft minecraft = Minecraft.getInstance(); + Component name = Component.translatable("block.computercraft.turtle_normal.upgraded", Component.translatable("turtle.advancedperipherals.saddle_turtle")); + // TODO: get and render turtle's label if exists + Component text = Component.translatable("text.advancedperipherals.saddle_turtle.dismount_hint", + name, minecraft.options.keyShift.getTranslatedKeyMessage(), minecraft.options.keyInventory.getTranslatedKeyMessage()); + float top = 10; + float x = (float)(this.screenWidth / 2 - textWidth(text) / 2); + getFont().drawShadow(stack, text, x, top, 0xffffff); + } + + @Override + public void render(ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + if (!this.isPlayerMountedOnTurtle()) { + return; + } + + this.gui = gui; + this.screenWidth = screenWidth; + this.screenHeight = screenHeight; + + if (this.shouldRenderFuelBar()) { + this.renderFuelBar(poseStack); + } + if (this.isPlayerControllingTurtle()) { + this.renderDismountHint(poseStack); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/screens/SmartGlassesScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/SmartGlassesScreen.java new file mode 100644 index 000000000..c81884b59 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/SmartGlassesScreen.java @@ -0,0 +1,78 @@ +package de.srendi.advancedperipherals.client.screens; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import dan200.computercraft.client.gui.ComputerScreenBase; +import dan200.computercraft.client.gui.widgets.ComputerSidebar; +import dan200.computercraft.client.gui.widgets.WidgetTerminal; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.widgets.SmartGlassesSettingsSwitch; +import de.srendi.advancedperipherals.common.container.SmartGlassesContainer; +import de.srendi.advancedperipherals.common.smartglasses.SlotType; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.NotNull; + +public class SmartGlassesScreen extends ComputerScreenBase { + + private static final ResourceLocation BACKGROUND = new ResourceLocation(AdvancedPeripherals.MOD_ID, "textures/gui/smart_glasses_gui.png"); + public static final ResourceLocation SIDEBAR = new ResourceLocation(AdvancedPeripherals.MOD_ID, "textures/gui/corners_glasses.png"); + + private static final int TEX_WIDTH = 254; + private static final int TEX_HEIGHT = 217; + private SlotType currentType = SlotType.defaultType(); + + public SmartGlassesScreen(SmartGlassesContainer container, Inventory player, Component title) { + super(container, player, title, ContainerTurtle.BORDER); + + imageWidth = TEX_WIDTH + ComputerSidebar.WIDTH; + imageHeight = TEX_HEIGHT; + } + + @Override + protected void init() { + super.init(); + addRenderableWidget(new SmartGlassesSettingsSwitch(254, 147, SlotType.PERIPHERALS, this)); + addRenderableWidget(new SmartGlassesSettingsSwitch(254, 170, SlotType.MODULES, this)); + } + + @Override + protected WidgetTerminal createTerminal() { + return new WidgetTerminal(terminalData, input, leftPos + ContainerTurtle.BORDER + ComputerSidebar.WIDTH, topPos + ContainerTurtle.BORDER); + } + + @Override + protected void renderBg(@NotNull PoseStack transform, float partialTicks, int mouseX, int mouseY) { + RenderSystem.setShaderTexture(0, BACKGROUND); + blit(transform, leftPos + ComputerSidebar.WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT); + + if (currentType == SlotType.PERIPHERALS) + blit(transform, leftPos + ComputerSidebar.WIDTH + 222, topPos + 183, 186, 183, 18, 18); + + RenderSystem.setShaderTexture(0, SIDEBAR); + ComputerSidebar.renderBackground(transform, leftPos, topPos + sidebarYOffset); + } + + @Override + protected void renderTooltip(@NotNull PoseStack poseStack, int x, int y) { + super.renderTooltip(poseStack, x, y); + renderables.forEach(renderable -> { + if (renderable instanceof SmartGlassesSettingsSwitch smartGlassesSettingsSwitch) { + smartGlassesSettingsSwitch.renderTooltip(poseStack, x, y); + } + }); + } + + @Override + protected void renderLabels(@NotNull PoseStack poseStack, int x, int y) { + FormattedCharSequence formattedcharsequence = currentType.getName().getVisualOrderText(); + this.font.draw(poseStack, formattedcharsequence, (212 + ComputerSidebar.WIDTH - (float) this.font.width(formattedcharsequence) / 2), 133, 4210752); + } + + public void setCurrentType(SlotType currentType) { + this.currentType = currentType; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseItemScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseItemScreen.java similarity index 73% rename from src/main/java/de/srendi/advancedperipherals/common/container/base/BaseItemScreen.java rename to src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseItemScreen.java index 527878f10..a7e7e9476 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseItemScreen.java +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseItemScreen.java @@ -1,16 +1,18 @@ -package de.srendi.advancedperipherals.common.container.base; +package de.srendi.advancedperipherals.client.screens.base; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.container.base.BaseItemContainer; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.NotNull; public abstract class BaseItemScreen extends AbstractContainerScreen { - public BaseItemScreen(T screenContainer, Inventory inv, Component titleIn) { + protected BaseItemScreen(T screenContainer, Inventory inv, Component titleIn) { super(screenContainer, inv, titleIn); imageWidth = getSizeX(); @@ -18,14 +20,14 @@ public BaseItemScreen(T screenContainer, Inventory inv, Component titleIn) { } @Override - public void render(PoseStack matrixStack, int x, int y, float partialTicks) { + public void render(@NotNull PoseStack matrixStack, int x, int y, float partialTicks) { renderBackground(matrixStack); super.render(matrixStack, x, y, partialTicks); renderTooltip(matrixStack, x, y); } @Override - protected void renderBg(PoseStack matrixStack, float partialTicks, int x, int y) { + protected void renderBg(@NotNull PoseStack matrixStack, float partialTicks, int x, int y) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.setShaderTexture(0, getTexture()); diff --git a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseScreen.java similarity index 86% rename from src/main/java/de/srendi/advancedperipherals/common/container/base/BaseScreen.java rename to src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseScreen.java index f9311435e..9390fa902 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseScreen.java +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseScreen.java @@ -1,7 +1,8 @@ -package de.srendi.advancedperipherals.common.container.base; +package de.srendi.advancedperipherals.client.screens.base; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.container.base.BaseContainer; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.network.chat.Component; @@ -11,7 +12,7 @@ public abstract class BaseScreen extends AbstractContainerScreen { - public BaseScreen(T screenContainer, Inventory inv, Component titleIn) { + protected BaseScreen(T screenContainer, Inventory inv, Component titleIn) { super(screenContainer, inv, titleIn); imageWidth = getSizeX(); imageHeight = getSizeY(); diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleLevelRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleLevelRenderer.java new file mode 100644 index 000000000..1a8aa23c2 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleLevelRenderer.java @@ -0,0 +1,115 @@ +package de.srendi.advancedperipherals.client.smartglasses; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.client.smartglasses.objects.threedim.IThreeDObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.util.EnumColor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE, modid = AdvancedPeripherals.MOD_ID) +public class OverlayModuleLevelRenderer { + + @SubscribeEvent + public static void renderLevelState(RenderLevelStageEvent event) { + PoseStack posestack = event.getPoseStack(); + Vec3 view = Minecraft.getInstance().getEntityRenderDispatcher().camera.getPosition(); + + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) { + Map, List> batches = new HashMap<>(); + + for (RenderableObject object : OverlayObjectHolder.getObjects()) { + if (!object.isEnabled() || !(object.getRenderObject() instanceof IThreeDObjectRenderer)) + continue; + + ThreeDimensionalObject threeDimObject = (ThreeDimensionalObject) object; + + Class extends ThreeDimensionalObject> objectClass = threeDimObject.getClass(); + + if (batches.containsKey(objectClass)) { + batches.get(objectClass).add(threeDimObject); + continue; + } + + List newBatchArray = new ArrayList<>(); + newBatchArray.add(threeDimObject); + batches.put(objectClass, newBatchArray); + } + + for (List batch : batches.values()) { + ((IThreeDObjectRenderer) batch.get(0).getRenderObject()).renderBatch(batch, event, posestack, view, bufferbuilder); + } + + //TODO Everything below here is just for debugging and testing. Will be removed before we push to production + BlockPos blockPos = new BlockPos(2, 100, 0); + + float[] colors = EnumColor.DARK_PURPLE.getRgb(); + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + bufferbuilder.begin(RenderType.translucent().mode(), DefaultVertexFormat.POSITION_COLOR_NORMAL); + posestack.pushPose(); + + posestack.translate(-view.x + blockPos.getX(), -view.y + blockPos.getY(), -view.z + blockPos.getZ()); + + RenderUtil.drawPlane(posestack, bufferbuilder, colors[0], colors[1], colors[2], 0.8f, Direction.UP, 0f, 0.5f, 0f, 0.5f, 0f, 1f); + + BufferUploader.drawWithShader(bufferbuilder.end()); + posestack.popPose(); + + VertexConsumer boxVertexConsumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.entityCutout(InventoryMenu.BLOCK_ATLAS)); + //RenderSystem.setShader(GameRenderer::getPositionColorLightmapShader); + + //bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP); + posestack.pushPose(); + colors = EnumColor.WHITE.getRgb(); + + blockPos = new BlockPos(0, 100, 0); + posestack.translate(-view.x + blockPos.getX(), -view.y + blockPos.getY(), -view.z + blockPos.getZ()); + + RenderUtil.drawSphere(posestack, boxVertexConsumer, 2f, 0f, 0f, 0f, 270f, 0f, 0f, colors[0], colors[1], colors[2], 0.4f, 16, 128); + + //BufferUploader.drawWithShader(bufferbuilder.end()); + posestack.popPose(); + + boxVertexConsumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.entityCutout(InventoryMenu.BLOCK_ATLAS)); + + //bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_NORMAL); + posestack.pushPose(); + + colors = EnumColor.WHITE.getRgb(); + blockPos = new BlockPos(6, 100, 0); + posestack.translate(-view.x + blockPos.getX(), -view.y + blockPos.getY(), -view.z + blockPos.getZ()); + + RenderUtil.drawTorus(posestack, boxVertexConsumer, 1f, 0.4f, 0f, 0f, 0f, 0f, 0f, 0f, colors[0], colors[1], colors[2], 1f, 48, 48); + + //BufferUploader.drawWithShader(bufferbuilder.end()); + posestack.popPose(); + + } + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleOverlay.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleOverlay.java new file mode 100644 index 000000000..6ef3fab90 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleOverlay.java @@ -0,0 +1,56 @@ +package de.srendi.advancedperipherals.client.smartglasses; + +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.client.smartglasses.objects.twodim.ITwoDObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.RectangleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.TextObject; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.client.gui.overlay.IGuiOverlay; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +public class OverlayModuleOverlay implements IGuiOverlay { + public static final String ID = "overlay_module_overlay"; + + @Override + public void render(ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + poseStack.pushPose(); + + Map, List>> prioritizedBatches = new TreeMap<>(); + + for (RenderableObject object : OverlayObjectHolder.getObjects()) { + if (!object.isEnabled() || !(object.getRenderObject() instanceof ITwoDObjectRenderer)) { + continue; + } + + // We need to sort the objects by their weight, some things can't be rendered before something else. + // For example, when texts are rendered before our circles, rectangles, etc., the other objects can't be transparent anymore + int weight = object.getRenderObject().getWeight(); + Class extends RenderableObject> objectClass = object.getClass(); + + // Get or create the batch map for the current weight + Map, List> batchesForWeight = prioritizedBatches.computeIfAbsent(weight, k -> new HashMap<>()); + + List batch = batchesForWeight.computeIfAbsent(objectClass, k -> new ArrayList<>()); + + batch.add(object); + } + + for (Map, List> batchesForWeight : prioritizedBatches.values()) { + for (List batch : batchesForWeight.values()) { + + if (!batch.isEmpty()) { + ((ITwoDObjectRenderer) batch.get(0).getRenderObject()).renderBatch(batch, gui, poseStack, partialTick, screenWidth, screenHeight); + } + } + } + poseStack.popPose(); + + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayObjectHolder.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayObjectHolder.java new file mode 100644 index 000000000..e319679fd --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayObjectHolder.java @@ -0,0 +1,60 @@ +package de.srendi.advancedperipherals.client.smartglasses; + +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.ObjectDecodeRegistry; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BlockObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BoxObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.SphereObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.TorusObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.CircleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.ItemObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.LineObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.RectangleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.TextObject; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Static holder for client side renderable objects - will change + */ +public class OverlayObjectHolder { + + public static Map objects = new HashMap<>(); + + public static void addOrUpdateObject(RenderableObject object) { + objects.put(object.getId(), object); + } + + public static void addOrUpdateObjects(Collection objects) { + for (RenderableObject renderableObject : objects) { + addOrUpdateObject(renderableObject); + } + } + + public static void removeObject(int id) { + objects.remove(id); + } + + public static Collection getObjects() { + return objects.values(); + } + + public static void clear() { + objects.clear(); + } + + public static void registerDecodeObjects() { + ObjectDecodeRegistry.register(RectangleObject.TYPE_ID, RectangleObject::decode); + ObjectDecodeRegistry.register(CircleObject.TYPE_ID, CircleObject::decode); + ObjectDecodeRegistry.register(TextObject.TYPE_ID, TextObject::decode); + ObjectDecodeRegistry.register(ItemObject.TYPE_ID, ItemObject::decode); + ObjectDecodeRegistry.register(LineObject.TYPE_ID, LineObject::decode); + + ObjectDecodeRegistry.register(BoxObject.TYPE_ID, BoxObject::decode); + ObjectDecodeRegistry.register(BlockObject.TYPE_ID, BlockObject::decode); + ObjectDecodeRegistry.register(SphereObject.TYPE_ID, SphereObject::decode); + ObjectDecodeRegistry.register(TorusObject.TYPE_ID, TorusObject::decode); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/IObjectRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/IObjectRenderer.java new file mode 100644 index 000000000..aeefb36a9 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/IObjectRenderer.java @@ -0,0 +1,13 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects; + +public interface IObjectRenderer { + /** + * Get the weight of the renderer. Lower weight means higher priority and it will render first. + * Some things need to be rendered before others to prevent color and opacity issues. + * @return the weight of the renderer. + */ + default int getWeight() { + return 100; + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BlockRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BlockRenderer.java new file mode 100644 index 000000000..152f9c3fe --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BlockRenderer.java @@ -0,0 +1,65 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Quaternion; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BlockObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import de.srendi.advancedperipherals.common.util.RegistryUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.List; + +public class BlockRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + + bufferBuilder.begin(RenderType.solid().mode(), DefaultVertexFormat.BLOCK); + + BlockObject block = (BlockObject) obj; + + poseStack.translate(-view.x + block.getX(), -view.y + block.getY(), -view.z + block.getZ()); + poseStack.mulPose(new Quaternion(block.rotX, block.rotY, block.rotZ, true)); + poseStack.translate(-0.5f, -0.5f, -0.5f); + float alpha = block.opacity; + float red = RenderUtil.getRed(block.color); + float green = RenderUtil.getGreen(block.color); + float blue = RenderUtil.getBlue(block.color); + + RenderSystem.setShader(GameRenderer::getBlockShader); + RenderSystem.setShaderColor(red, green, blue, alpha); + + Block blockToRender = RegistryUtil.getRegistryEntry(block.block, ForgeRegistries.BLOCKS); + BlockPos blockPos = new BlockPos(obj.getX(), obj.getY(), obj.getZ()); + + if (blockToRender != null) + Minecraft.getInstance().getBlockRenderer().renderBatched(blockToRender.defaultBlockState(), blockPos, event.getCamera().getEntity().level, poseStack, bufferBuilder, false, event.getCamera().getEntity().level.random); + + poseStack.popPose(); + BufferUploader.drawWithShader(bufferBuilder.end()); + onPostRender(obj); + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + } + + + poseStack.popPose(); + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BoxRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BoxRenderer.java new file mode 100644 index 000000000..e773a6ec4 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BoxRenderer.java @@ -0,0 +1,47 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BoxObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public class BoxRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_NORMAL); + + BoxObject box = (BoxObject) obj; + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + float alpha = box.opacity; + float red = RenderUtil.getRed(box.color); + float green = RenderUtil.getGreen(box.color); + float blue = RenderUtil.getBlue(box.color); + + poseStack.translate(-view.x + box.getX(), -view.y + box.getY(), -view.z + box.getZ()); + RenderUtil.drawBox(poseStack, bufferBuilder, red, green, blue, alpha, box.x, box.y, box.z, obj.rotX, obj.rotY, obj.rotZ, obj.maxX, obj.maxY, obj.maxZ); + BufferUploader.drawWithShader(bufferBuilder.end()); + onPostRender(obj); + + poseStack.popPose(); + } + + poseStack.popPose(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/IThreeDObjectRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/IThreeDObjectRenderer.java new file mode 100644 index 000000000..119277f6f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/IThreeDObjectRenderer.java @@ -0,0 +1,30 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.client.smartglasses.objects.IObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public interface IThreeDObjectRenderer extends IObjectRenderer { + + void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder); + + default void onPostRender(ThreeDimensionalObject object) { + if (object.disableCulling) + RenderSystem.enableCull(); + if (object.disableDepthTest) + RenderSystem.enableDepthTest(); + } + + default void onPreRender(ThreeDimensionalObject object) { + if (object.disableCulling) + RenderSystem.disableCull(); + if (object.disableDepthTest) + RenderSystem.disableDepthTest(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/SphereRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/SphereRenderer.java new file mode 100644 index 000000000..71388a20e --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/SphereRenderer.java @@ -0,0 +1,49 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.SphereObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public class SphereRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + VertexConsumer boxVertexConsumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.entitySmoothCutout(TextureAtlas.LOCATION_BLOCKS)); + + SphereObject sphere = (SphereObject) obj; + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + float alpha = sphere.opacity; + float red = RenderUtil.getRed(sphere.color); + float green = RenderUtil.getRed(sphere.color); + float blue = RenderUtil.getRed(sphere.color); + + poseStack.translate(-view.x, -view.y, -view.z); + RenderUtil.drawSphere(poseStack, boxVertexConsumer, sphere.radius, sphere.x, sphere.y, sphere.z, sphere.rotX, sphere.rotY, sphere.rotZ, red, green, blue, alpha, sphere.sectors, sphere.stacks); + onPostRender(obj); + + poseStack.popPose(); + } + + + poseStack.popPose(); + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/TorusRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/TorusRenderer.java new file mode 100644 index 000000000..7921b8a71 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/TorusRenderer.java @@ -0,0 +1,47 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.TorusObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public class TorusRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_NORMAL); + + TorusObject torus = (TorusObject) obj; + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + float alpha = torus.opacity; + float red = RenderUtil.getRed(torus.color); + float green = RenderUtil.getGreen(torus.color); + float blue = RenderUtil.getBlue(torus.color); + + poseStack.translate(-view.x + torus.x, -view.y + torus.y, -view.z + torus.z); + RenderUtil.drawTorus(poseStack, bufferBuilder, torus.majorRadius, torus.minorRadius, 0, 0, 0, torus.rotX, torus.rotY, torus.rotZ, red, green, blue, alpha, torus.rings, torus.sides); + BufferUploader.drawWithShader(bufferBuilder.end()); + onPostRender(obj); + + poseStack.popPose(); + } + + poseStack.popPose(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/CircleRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/CircleRenderer.java new file mode 100644 index 000000000..5929b3e8e --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/CircleRenderer.java @@ -0,0 +1,189 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +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.math.Matrix4f; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.CircleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class CircleRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + for (RenderableObject obj : objects) { + + CircleObject circle = (CircleObject) obj; + + float alpha = circle.opacity; + float red = RenderUtil.getRed(circle.color); + float green = RenderUtil.getGreen(circle.color); + float blue = RenderUtil.getBlue(circle.color); + + drawCircle(poseStack, circle, red, green, blue, alpha); + } + } + + public void drawCircle(PoseStack t, CircleObject circle, float red, float green, float blue, float alpha) { + float r = circle.radius; + float cx = circle.x; + float cy = circle.y; + float cz = circle.z; + float rotX = circle.rotX; + float rotY = circle.rotY; + float rotZ = circle.rotZ; + float borderWidth = circle.borderWidth; + int segments = circle.segments; + + boolean isFilled = circle.filled; + boolean isPixelated = circle.pixelated; + + PoseStack poseStack = new PoseStack(); + + poseStack.translate(cx, cy, cz); + + poseStack.pushPose(); + + poseStack.mulPose(Vector3f.XP.rotationDegrees(rotX)); + poseStack.mulPose(Vector3f.YP.rotationDegrees(rotY)); + poseStack.mulPose(Vector3f.ZP.rotationDegrees(rotZ)); + + RenderSystem.disableCull(); + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + + Matrix4f matrix = poseStack.last().pose(); + + // Normal, smooth lines + if (!isPixelated) { + if (isFilled) { + + bufferbuilder.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR); + + bufferbuilder.vertex(matrix, 0, 0, 0f).color(red, green, blue, alpha).endVertex(); + + double angleStep = Math.PI * 2 / segments; + + for (int i = 0; i <= segments; i++) { + double angle = i * angleStep; + double x = r * Math.sin(angle); + double y = r * Math.cos(angle); + + bufferbuilder.vertex(matrix, (float) x, (float) y, 0).color(red, green, blue, alpha).endVertex(); + } + + } else { + float outerRadius = r; + float innerRadius = r - borderWidth; + + bufferbuilder.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR); + + double angleStep = Math.PI * 2 / segments; + + for (int i = 0; i <= segments; i++) { + double angle = i * angleStep; + + // Outer circle vertex + double outerX = innerRadius * Math.sin(angle); + double outerY = innerRadius * Math.cos(angle); + bufferbuilder.vertex(matrix, (float) outerX, (float) outerY, 0f).color(red, green, blue, alpha).endVertex(); + + // Inner circle vertex + double innerX = outerRadius * Math.sin(angle); + double innerY = outerRadius * Math.cos(angle); + bufferbuilder.vertex(matrix, (float) innerX, (float) innerY, 0f).color(red, green, blue, alpha).endVertex(); + } + } + + BufferUploader.drawWithShader(bufferbuilder.end()); + + return; + } + + // Pixelated lines + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + final float PIXEL_SIZE = borderWidth; // Defines the size of each "pixel" square + + // The thickness of the hollow line in terms of pixel units. + // A value of 1.0f means the line will be roughly one pixel thick. + final float LINE_THICKNESS_PIXELS = 1f; + + // Calculate the effective min/max coordinates in the relative space + float effectiveMinX = -r - PIXEL_SIZE; + float effectiveMaxX = r + PIXEL_SIZE; + float effectiveMinY = -r - PIXEL_SIZE; + float effectiveMaxY = r + PIXEL_SIZE; + +// Start the loop at the first multiple of PIXEL_SIZE that is less than or equal to effectiveMinX/Y + float startX = (float) Math.floor(effectiveMinX / PIXEL_SIZE) * PIXEL_SIZE; + float startY = (float) Math.floor(effectiveMinY / PIXEL_SIZE) * PIXEL_SIZE; + + + for (float x = startX; x <= effectiveMaxX; x += PIXEL_SIZE) { + for (float y = startY; y <= effectiveMaxY; y += PIXEL_SIZE) { + // Calculate the center of the current pixel cell. + // This is where you determine if the *center* of this block should be drawn. + float pixelCenterX = x + (PIXEL_SIZE / 2.0F); + float pixelCenterY = y + (PIXEL_SIZE / 2.0F); + + // Distance is calculated from (pixelCenterX, pixelCenterY) to (0,0) + double distanceToCenter = Math.sqrt( + Math.pow(pixelCenterX, 2) + Math.pow(pixelCenterY, 2) + ); + + boolean shouldDrawPixel; + + if (!isFilled) { + float outerRadius = r + (LINE_THICKNESS_PIXELS * (PIXEL_SIZE / 2.0F)); + float innerRadius = r - (LINE_THICKNESS_PIXELS * (PIXEL_SIZE / 2.0F)); + + if (innerRadius < 0) innerRadius = 0; + + shouldDrawPixel = (distanceToCenter <= outerRadius) && (distanceToCenter >= innerRadius); + } else { + shouldDrawPixel = distanceToCenter <= r + (PIXEL_SIZE / 2.0F); + } + + if (shouldDrawPixel) { + // Vertices for the QUAD (a PIXEL_SIZE x PIXEL_SIZE square) + // These coordinates are now relative to the current origin (0,0,0) + float p_x1 = x; + float p_y1 = y; + float p_z = 0f; // z-coordinate is relative to cz, so 0 in this space + + float p_x2 = x + PIXEL_SIZE; + float p_y2 = y + PIXEL_SIZE; + + // Vertices for the QUAD + // Ensure proper winding order (counter-clockwise for front face) + bufferbuilder.vertex(matrix, p_x1, p_y2, p_z).color(red, green, blue, alpha).endVertex(); // Bottom-left + bufferbuilder.vertex(matrix, p_x2, p_y2, p_z).color(red, green, blue, alpha).endVertex(); // Bottom-right + bufferbuilder.vertex(matrix, p_x2, p_y1, p_z).color(red, green, blue, alpha).endVertex(); // Top-right + bufferbuilder.vertex(matrix, p_x1, p_y1, p_z).color(red, green, blue, alpha).endVertex(); // Top-left + } + } + } + + RenderSystem.enableCull(); + + BufferUploader.drawWithShader(bufferbuilder.end()); + + + poseStack.popPose(); + + } +} + diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ITwoDObjectRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ITwoDObjectRenderer.java new file mode 100644 index 000000000..543f3580c --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ITwoDObjectRenderer.java @@ -0,0 +1,14 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.client.smartglasses.objects.IObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public interface ITwoDObjectRenderer extends IObjectRenderer { + + void renderBatch(List object, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight); + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ItemRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ItemRenderer.java new file mode 100644 index 000000000..6d2ff7ccb --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ItemRenderer.java @@ -0,0 +1,29 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.ItemObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.util.RegistryUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.List; + +public class ItemRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + Minecraft minecraft = Minecraft.getInstance(); + + for (RenderableObject obj : objects) { + Item renderItem = RegistryUtil.getRegistryEntry(((ItemObject) obj).item, ForgeRegistries.ITEMS); + if (renderItem == null) + continue; + minecraft.getItemRenderer().renderGuiItem(new ItemStack(renderItem), (int) obj.x, (int) obj.y); + } + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/LineRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/LineRenderer.java new file mode 100644 index 000000000..71579398a --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/LineRenderer.java @@ -0,0 +1,103 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +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.math.Matrix4f; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.LineObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class LineRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + RenderSystem.setShader(GameRenderer::getPositionColorShader); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + Matrix4f matrix = poseStack.last().pose(); + + for (RenderableObject obj : objects) { + + LineObject line = (LineObject) obj; + + float alpha = obj.opacity; + float red = RenderUtil.getRed(obj.color); + float green = RenderUtil.getGreen(obj.color); + float blue = RenderUtil.getBlue(obj.color); + + // Start and end points of the line + float x1 = obj.x; + float y1 = obj.y; + float z1 = obj.z; + + float x2 = obj.maxX; + float y2 = obj.maxY; + float z2 = obj.maxZ; + + // Normal, smooth lines + if (!line.pixelated) { + bufferbuilder.begin(VertexFormat.Mode.DEBUG_LINE_STRIP, DefaultVertexFormat.POSITION_COLOR); + bufferbuilder.vertex(matrix, x1, y1, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, x2, y2, 0).color(red, green, blue, alpha).endVertex(); + BufferUploader.drawWithShader(bufferbuilder.end()); + + continue; // Skip the rest of the loop for this object + } + + // Pixelated lines + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + // Calculate the delta for each axis + float dx = x2 - x1; + float dy = y2 - y1; + float dz = z2 - z1; + + final float PIXEL_SIZE = line.pixelSize; + + float maxDim = Math.max(Math.abs(dx), Math.max(Math.abs(dy), Math.abs(dz))); + int numPixels = (int) Math.ceil(maxDim / PIXEL_SIZE); + + if (numPixels == 0) { + numPixels = 1; // Always draw at least one pixel for very short lines + } + + // Iterate and draw a square for each "pixel" + for (int i = 0; i <= numPixels; i++) { + float t = (float) i / numPixels; // Interpolation factor (0.0 to 1.0) + + // Calculate the exact point on the line + float currentX = x1 + dx * t; + float currentY = y1 + dy * t; + float currentZ = z1 + dz * t; + + // Snap current point to the nearest pixel grid for consistent placement. + // This is key for placing pixels at corners or full side of each other. + currentX = Math.round(currentX / PIXEL_SIZE) * PIXEL_SIZE; + currentY = Math.round(currentY / PIXEL_SIZE) * PIXEL_SIZE; + currentZ = Math.round(currentZ / PIXEL_SIZE) * PIXEL_SIZE; + + float p_x1 = currentX; + float p_y1 = currentY; + float p_z1 = currentZ; + + float p_x2 = currentX + PIXEL_SIZE; + float p_y2 = currentY + PIXEL_SIZE; + float p_z2 = currentZ; + + bufferbuilder.vertex(matrix, p_x1, p_y2, p_z1).color(red, green, blue, alpha).endVertex(); // Bottom-left + bufferbuilder.vertex(matrix, p_x2, p_y2, p_z1).color(red, green, blue, alpha).endVertex(); // Bottom-right + bufferbuilder.vertex(matrix, p_x2, p_y1, p_z2).color(red, green, blue, alpha).endVertex(); // Top-right + bufferbuilder.vertex(matrix, p_x1, p_y1, p_z2).color(red, green, blue, alpha).endVertex(); // Top-left + } + BufferUploader.drawWithShader(bufferbuilder.end()); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/RectangleRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/RectangleRenderer.java new file mode 100644 index 000000000..55618cf74 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/RectangleRenderer.java @@ -0,0 +1,60 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +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.math.Matrix4f; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class RectangleRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack ignored, float partialTick, int screenWidth, int screenHeight) { + RenderSystem.setShader(GameRenderer::getPositionColorShader); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (RenderableObject obj : objects) { + float rotX = obj.rotX; + float rotY = obj.rotY; + float rotZ = obj.rotZ; + + PoseStack poseStack = new PoseStack(); + + poseStack.translate(obj.x, obj.y, obj.z); + + poseStack.pushPose(); + + Matrix4f matrix = poseStack.last().pose(); + + poseStack.mulPose(Vector3f.XP.rotationDegrees(rotX)); + poseStack.mulPose(Vector3f.YP.rotationDegrees(rotY)); + poseStack.mulPose(Vector3f.ZP.rotationDegrees(rotZ)); + + float alpha = obj.opacity; + float red = RenderUtil.getRed(obj.color); + float green = RenderUtil.getGreen(obj.color); + float blue = RenderUtil.getBlue(obj.color); + + bufferbuilder.vertex(matrix, 0, obj.maxY - obj.y, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, obj.maxX - obj.x, obj.maxY - obj.y, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, obj.maxX - obj.x, 0, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, 0, 0, 0).color(red, green, blue, alpha).endVertex(); + poseStack.popPose(); + + } + + BufferUploader.drawWithShader(bufferbuilder.end()); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/TextRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/TextRenderer.java new file mode 100644 index 000000000..ecde02ad7 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/TextRenderer.java @@ -0,0 +1,55 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.TextObject; +import net.minecraft.client.Minecraft; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class TextRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack ignored, float partialTick, int screenWidth, int screenHeight) { + Minecraft minecraft = Minecraft.getInstance(); + for (RenderableObject obj : objects) { + TextObject text = (TextObject) obj; + float rotX = obj.rotX; + float rotY = obj.rotY; + float rotZ = obj.rotZ; + + float x = text.x; + + if (text.center) { + x -= (minecraft.font.width(text.content) * text.fontSize) / 2f; + } + + PoseStack poseStack = new PoseStack(); + + poseStack.translate(x / text.fontSize, text.y / text.fontSize, obj.z); + + poseStack.pushPose(); + + poseStack.mulPose(Vector3f.XP.rotationDegrees(rotX)); + poseStack.mulPose(Vector3f.YP.rotationDegrees(rotY)); + poseStack.mulPose(Vector3f.ZP.rotationDegrees(rotZ)); + + poseStack.scale(text.fontSize, text.fontSize, 1); + + if (!text.shadow) { + minecraft.font.drawShadow(poseStack, text.content, 0, 0, text.color); + } else { + minecraft.font.draw(poseStack, text.content, 0, 0, text.color); + } + poseStack.popPose(); + } + } + + @Override + public int getWeight() { + return 110; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/widgets/SmartGlassesSettingsSwitch.java b/src/main/java/de/srendi/advancedperipherals/client/widgets/SmartGlassesSettingsSwitch.java new file mode 100644 index 000000000..a6ab0c0cc --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/widgets/SmartGlassesSettingsSwitch.java @@ -0,0 +1,85 @@ +package de.srendi.advancedperipherals.client.widgets; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import dan200.computercraft.client.gui.widgets.ComputerSidebar; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.screens.SmartGlassesScreen; +import de.srendi.advancedperipherals.common.smartglasses.SlotType; +import de.srendi.advancedperipherals.common.smartglasses.SmartGlassesSlot; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.Slot; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +public class SmartGlassesSettingsSwitch extends AbstractWidget { + + private static final ResourceLocation BACKGROUND = new ResourceLocation(AdvancedPeripherals.MOD_ID, "textures/gui/smart_glasses_gui.png"); + + private final SmartGlassesScreen screen; + private final SlotType type; + private boolean isEnabled; + + public SmartGlassesSettingsSwitch(int x, int y, SlotType type, SmartGlassesScreen screen) { + super(screen.getGuiLeft() + x + ComputerSidebar.WIDTH, screen.getGuiTop() + y, 21, 22, type.getName()); + this.screen = screen; + this.type = type; + this.isEnabled = type == SlotType.defaultType(); + } + + @Override + public void render(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) { + renderBg(pPoseStack, Minecraft.getInstance(), pMouseX, pMouseY); + } + + @Override + public void renderButton(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) { + // Disable rendering of default buttons + } + + @Override + protected void renderBg(@NotNull PoseStack pPoseStack, @NotNull Minecraft pMinecraft, int pMouseX, int pMouseY) { + RenderSystem.setShaderTexture(0, BACKGROUND); + if (isEnabled) { + blit(pPoseStack, this.x - 3, this.y, 45, 217, 24, 22); + } else { + blit(pPoseStack, this.x, this.y, 23, 217, 21, 22); + } + } + + @Override + public void onClick(double pMouseX, double pMouseY) { + if (this.isEnabled) + return; + for (Slot slot : screen.getMenu().slots) { + if (slot instanceof SmartGlassesSlot smartGlassesSlot) { + if (smartGlassesSlot.slotType == this.type) { + smartGlassesSlot.setEnabled(true); + continue; + } + smartGlassesSlot.setEnabled(false); + } + } + screen.renderables.forEach(renderable -> { + if (renderable instanceof SmartGlassesSettingsSwitch smartGlassesSettingsSwitch) { + smartGlassesSettingsSwitch.isEnabled = false; + } + }); + screen.setCurrentType(this.type); + this.isEnabled = true; + } + + public void renderTooltip(PoseStack poseStack, int x, int y) { + if (screen != null && isMouseOver(x, y)) + screen.renderComponentTooltip(poseStack, Collections.singletonList(type.getName()), x, y); + } + + @Override + public void updateNarration(@NotNull NarrationElementOutput pNarrationElementOutput) { + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java b/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java index c26e2652a..bdc4e4265 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java @@ -1,41 +1,72 @@ package de.srendi.advancedperipherals.common.addons; import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.common.addons.refinedstorage.RefinedStorage; +import de.srendi.advancedperipherals.common.addons.refinedstorage.RSApi; +import de.srendi.advancedperipherals.common.addons.valkyrienskies.ValkyrienSkies; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; +import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.SlotResult; +import top.theillusivec4.curios.api.SlotTypeMessage; + +import java.util.List; @Mod.EventBusSubscriber(modid = AdvancedPeripherals.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class APAddons { - public static final String CURIOS_MODID = "curios"; - public static final String REFINEDSTORAGE_MODID = "refinedstorage"; - public static final String AE_THINGS_MODID = "ae2things"; public static final String AE_ADDITIONS_MODID = "ae2additions"; + public static final String AE_THINGS_MODID = "ae2things"; + public static final String APPLIEDENERGISTICS_MODID = "ae2"; public static final String APP_MEKANISTICS_MODID = "appmek"; + public static final String BOTANIA_MODID = "botania"; + public static final String CREATE_MODID = "create"; + public static final String CURIOS_MODID = "curios"; + public static final String DIMSTORAGE_MODID = "dimstorage"; + public static final String MEKANISM_MODID = "mekanism"; + public static final String POWAH_MODID = "powah"; + public static final String REFINEDSTORAGE_MODID = "refinedstorage"; + public static final String VALKYRIEN_SKIES_MODID = "valkyrienskies"; - public static boolean curiosLoaded; - public static boolean refinedStorageLoaded; - public static boolean aeThingsLoaded; public static boolean aeAdditionsLoaded; + public static boolean aeThingsLoaded; public static boolean appMekLoaded; + public static boolean appliedEnergisticsLoaded; + public static boolean botaniaLoaded; + public static boolean createLoaded; + public static boolean curiosLoaded; + public static boolean dimstorageLoaded; + public static boolean mekanismLoaded; + public static boolean powahLoaded; + public static boolean refinedStorageLoaded; + public static boolean vs2Loaded; - private APAddons() { - } - - public static void commonSetup() { + // Use static so these checks run as early as possible, so we can use them for our registries + static { ModList modList = ModList.get(); - curiosLoaded = modList.isLoaded(CURIOS_MODID); - refinedStorageLoaded = modList.isLoaded(REFINEDSTORAGE_MODID); - aeThingsLoaded = modList.isLoaded(AE_THINGS_MODID); aeAdditionsLoaded = modList.isLoaded(AE_ADDITIONS_MODID); + aeThingsLoaded = modList.isLoaded(AE_THINGS_MODID); appMekLoaded = modList.isLoaded(APP_MEKANISTICS_MODID); + appliedEnergisticsLoaded = modList.isLoaded(APPLIEDENERGISTICS_MODID); + botaniaLoaded = modList.isLoaded(BOTANIA_MODID); + createLoaded = modList.isLoaded(CREATE_MODID); + curiosLoaded = modList.isLoaded(CURIOS_MODID); + dimstorageLoaded = modList.isLoaded(DIMSTORAGE_MODID); + mekanismLoaded = modList.isLoaded(MEKANISM_MODID); + powahLoaded = modList.isLoaded(POWAH_MODID); + refinedStorageLoaded = modList.isLoaded(REFINEDSTORAGE_MODID); + vs2Loaded = modList.isLoaded(VALKYRIEN_SKIES_MODID); - if (refinedStorageLoaded) - RefinedStorage.instance = new RefinedStorage(); - + if (refinedStorageLoaded) { + RSApi.instance = new RSApi(); + } } @SubscribeEvent @@ -43,6 +74,27 @@ public static void interModComms(InterModEnqueueEvent event) { if (!curiosLoaded) return; - // InterModComms.sendTo("curios", SlotTypeMessage.REGISTER_TYPE, () -> new SlotTypeMessage.Builder("glasses").size(1).build()); + InterModComms.sendTo(CURIOS_MODID, SlotTypeMessage.REGISTER_TYPE, + () -> new SlotTypeMessage.Builder("glasses") + .size(1) + .icon(new ResourceLocation(AdvancedPeripherals.MOD_ID, "slot/empty_glasses_slot")) + .build()); + } + + public static ItemStack getCurioGlasses(Player player) { + if (!curiosLoaded) + return ItemStack.EMPTY; + List curioSlots = CuriosApi.getCuriosHelper().findCurios(player, "glasses"); + if (curioSlots.isEmpty()) + return ItemStack.EMPTY; + + return curioSlots.get(0).stack(); + } + + public static boolean isBlockOnShip(Level level, BlockPos pos) { + if (!vs2Loaded) { + return false; + } + return ValkyrienSkies.isBlockOnShip(level, pos); } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AE2Registries.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AE2Registries.java new file mode 100644 index 000000000..b4759df1d --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AE2Registries.java @@ -0,0 +1,42 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.features.P2PTunnelAttunement; +import appeng.api.parts.IPart; +import appeng.api.parts.IPartItem; +import appeng.api.parts.PartModels; +import appeng.items.parts.PartItem; +import appeng.items.parts.PartModelsHelper; +import dan200.computercraft.shared.Registry.ModItems; +import de.srendi.advancedperipherals.common.setup.APRegistration; +import net.minecraft.data.tags.TagsProvider; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraftforge.registries.RegistryObject; + +import java.util.function.Function; + +public final class AE2Registries { + private AE2Registries() {} + + public static final RegistryObject> CABLE_P2P_TUNNEL = registerPart("cable_p2p_tunnel", WiredCableP2PTunnelPart.class, WiredCableP2PTunnelPart::new); + + private static RegistryObject> registerPart(String id, Class clazz, Function, T> factory) { + PartModels.registerModels(PartModelsHelper.createModels(clazz)); + return APRegistration.ITEMS.register(id, () -> new PartItem<>(new Item.Properties(), clazz, factory)); + } + + public static void finishRegister() { + P2PTunnelAttunement.registerAttunementTag(CABLE_P2P_TUNNEL.get()); + } + + public static TagKey getCableP2PTag() { + return P2PTunnelAttunement.getAttunementTag(CABLE_P2P_TUNNEL.get()); + } + + public static void registerTags(Function, TagsProvider.TagAppender> tagger) { + tagger.apply(getCableP2PTag()) + .add(ModItems.CABLE.get()) + .add(ModItems.WIRED_MODEM.get()) + .add(ModItems.WIRED_MODEM_FULL.get()); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AEApi.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AEApi.java new file mode 100644 index 000000000..51958de66 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AEApi.java @@ -0,0 +1,961 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.crafting.IPatternDetails; +import appeng.api.inventories.InternalInventory; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.CraftingJobStatus; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingService; +import appeng.api.networking.storage.IStorageService; +import appeng.api.stacks.AEFluidKey; +import appeng.api.stacks.AEItemKey; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.AEKeyType; +import appeng.api.stacks.GenericStack; +import appeng.api.stacks.KeyCounter; +import appeng.api.storage.AEKeyFilter; +import appeng.api.storage.IStorageProvider; +import appeng.api.storage.MEStorage; +import appeng.api.storage.cells.IBasicCellItem; +import appeng.blockentity.storage.DriveBlockEntity; +import appeng.crafting.execution.CraftingCpuLogic; +import appeng.crafting.pattern.EncodedPatternItem; +import appeng.helpers.iface.PatternContainer; +import appeng.items.storage.BasicStorageCell; +import appeng.me.cells.BasicCellHandler; +import appeng.me.cells.BasicCellInventory; +import appeng.me.cluster.implementations.CraftingCPUCluster; +import appeng.parts.storagebus.StorageBusPart; +import com.the9grounds.aeadditions.item.storage.StorageCell; +import com.the9grounds.aeadditions.item.storage.SuperStorageCell; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.util.LuaConverter; +import de.srendi.advancedperipherals.common.util.Pair; +import de.srendi.advancedperipherals.common.util.inventory.FluidFilter; +import de.srendi.advancedperipherals.common.util.inventory.GenericFilter; +import de.srendi.advancedperipherals.common.util.inventory.ItemFilter; +import io.github.projectet.ae2things.item.DISKDrive; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import me.ramidzkh.mekae2.ae2.MekanismKey; +import me.ramidzkh.mekae2.ae2.MekanismKeyType; +import me.ramidzkh.mekae2.item.ChemicalStorageCell; +import mekanism.api.chemical.merged.MergedChemicalTank; +import mekanism.common.tile.TileEntityChemicalTank; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class AEApi { + + public static Pair findAEStackFromStack(MEStorage monitor, @Nullable ICraftingService crafting, ItemStack item) { + return findAEStackFromFilter(monitor, crafting, ItemFilter.fromStack(item)); + } + + public static Pair findAEStackFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, ItemFilter item) { + for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { + if (temp.getKey() instanceof AEItemKey key && item.test(key.toStack())) + return Pair.of(temp.getLongValue(), key); + } + + if (crafting == null) + return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); + + for (var temp : crafting.getCraftables(param -> true)) { + if (temp instanceof AEItemKey key && item.test(key.toStack())) + return Pair.of(0L, key); + } + + return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); + } + + public static Pair findAEFluidFromStack(MEStorage monitor, @Nullable ICraftingService crafting, FluidStack item) { + return findAEFluidFromFilter(monitor, crafting, FluidFilter.fromStack(item)); + } + + public static Pair findAEFluidFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, FluidFilter item) { + for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { + if (temp.getKey() instanceof AEFluidKey key && item.test(key.toStack(1))) + return Pair.of(temp.getLongValue(), key); + } + + if (crafting == null) + return Pair.of(0L, AEFluidKey.of(FluidStack.EMPTY)); + + for (var temp : crafting.getCraftables(param -> true)) { + if (temp instanceof AEFluidKey key && item.test(key.toStack(1))) + return Pair.of(0L, key); + } + + return Pair.of(0L, AEFluidKey.of(FluidStack.EMPTY)); + } + + /** + * Finds a pattern from filters. + * + * @param grid The grid to search patterns from. + * @param level The level of the grid. + * @param inputFilter The input filter to apply, can be null to ignore input filter. + * @param outputFilter The output filter to apply, can be null to ignore output filter. + * @return A Pair object containing the matched pattern and an error message if no pattern is found. + * The pattern can be null if no pattern is found. + * The error message is "NO_PATTERN_FOUND" if no pattern is found. + */ + public static Pair findPatternFromFilters(IGrid grid, Level level, @Nullable GenericFilter inputFilter, @Nullable GenericFilter outputFilter) { + for (IPatternDetails pattern : getPatterns(grid, level)) { + if (pattern.getInputs().length == 0) + continue; + if (pattern.getOutputs().length == 0) + continue; + + boolean inputMatch = false; + boolean outputMatch = false; + + if (inputFilter != null) { + outerLoop: + for (IPatternDetails.IInput input : pattern.getInputs()) { + for (GenericStack possibleInput : input.getPossibleInputs()) { + if (inputFilter.testAE(possibleInput)) { + inputMatch = true; + break outerLoop; + } + } + } + } else { + inputMatch = true; + } + + if (outputFilter != null) { + for (GenericStack output : pattern.getOutputs()) { + if (outputFilter.testAE(output)) { + outputMatch = true; + break; + } + } + } else { + outputMatch = true; + } + + if (inputMatch && outputMatch) + return Pair.of(pattern, null); + } + + return Pair.of(null, "NO_PATTERN_FOUND"); + } + + + public static List listStacks(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + KeyCounter keyCounter = monitor.getAvailableStacks(); + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof AEItemKey itemKey) { + items.add(parseAeStack(Pair.of(aeKey.getLongValue(), itemKey), service)); + } + } + return items; + } + + public static List listCraftableStacks(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + KeyCounter keyCounter = monitor.getAvailableStacks(); + Set craftables = service.getCraftables(AEKeyFilter.none()); + for (AEKey aeKey : craftables) { + if (aeKey instanceof AEItemKey) { + items.add(parseAeStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); + } + } + return items; + } + + public static List listFluids(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { + if (aeKey.getKey() instanceof AEFluidKey itemKey) { + items.add(parseAeStack(Pair.of(aeKey.getLongValue(), itemKey), service)); + } + } + return items; + } + + public static List listGases(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { + if (APAddons.appMekLoaded && aeKey.getKey() instanceof MekanismKey itemKey) { + items.add(parseAeStack(Pair.of(aeKey.getLongValue(), itemKey), service)); + } + } + return items; + } + + public static List listCraftableFluids(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + KeyCounter keyCounter = monitor.getAvailableStacks(); + Set craftables = service.getCraftables(AEKeyFilter.none()); + for (AEKey aeKey : craftables) { + if (aeKey instanceof AEFluidKey) { + items.add(parseAeStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); + } + } + return items; + } + + public static List getPatterns(IGrid grid, Level level) { + List patterns = new ArrayList<>(); + for (var machineClass : grid.getMachineClasses()) { + var containerClass = tryCastMachineToContainer(machineClass); + if (containerClass == null) + continue; + + for (var container : grid.getActiveMachines(containerClass)) { + for (ItemStack patternItem : container.getTerminalPatternInventory()) { + if (patternItem.getItem() instanceof EncodedPatternItem item) { + IPatternDetails patternDetails = item.decode(patternItem, level, false); + if (patternDetails == null) + continue; + + patterns.add(patternDetails); + } + } + } + } + return patterns; + } + + public static List listPatterns(IGrid grid, Level level) { + return getPatterns(grid, level).stream().map(AEApi::parsePattern).collect(Collectors.toList()); + } + + public static List listDrives(IGrid grid) { + List drives = new ArrayList<>(); + + for (IGridNode node : grid.getMachineNodes(DriveBlockEntity.class)) { + DriveBlockEntity drive = (DriveBlockEntity) node.getService(IStorageProvider.class); + + // A normal drive has a cellCount of 10 + if (drive == null || drive.getCellCount() != 10) + continue; + + drives.add(parseDrive(drive)); + } + + return drives; + } + + private static Class extends PatternContainer> tryCastMachineToContainer(Class> machineClass) { + if (PatternContainer.class.isAssignableFrom(machineClass)) + return machineClass.asSubclass(PatternContainer.class); + + return null; + } + + public static Map parseAeStack(Pair stack, @Nullable ICraftingService service) { + if (stack == null || stack.getRight() == null) + return Collections.emptyMap(); + if (stack.getRight() instanceof AEItemKey itemKey) + return parseItemStack(Pair.of(stack.getLeft(), itemKey), service); + if (stack.getRight() instanceof AEFluidKey fluidKey) + return parseFluidStack(Pair.of(stack.getLeft(), fluidKey), service); + if (APAddons.appMekLoaded && (stack.getRight() instanceof MekanismKey gasKey)) + return parseChemStack(Pair.of(stack.getLeft(), gasKey)); + + AdvancedPeripherals.debug("Could not create table from unknown stack " + stack.getRight().getClass() + " - Report this to the maintainer of ap", org.apache.logging.log4j.Level.WARN); + return Collections.emptyMap(); + } + + public static Map parseGenericStack(GenericStack stack) { + if (stack.what() == null) + return Collections.emptyMap(); + if (stack.what() instanceof AEItemKey aeItemKey) + return parseItemStack(Pair.of(stack.amount(), aeItemKey), null); + if (stack.what() instanceof AEFluidKey aeFluidKey) + return parseFluidStack(Pair.of(stack.amount(), aeFluidKey), null); + + AdvancedPeripherals.debug("Could not create table from unknown stack " + stack.getClass() + " - Report this to the maintainer of ap", org.apache.logging.log4j.Level.WARN); + return Collections.emptyMap(); + } + + public static List parseKeyCounter(KeyCounter counter) { + List parsedKeys = new ArrayList<>(); + for (AEKey key : counter.keySet()) { + parsedKeys.add(parseGenericStack(new GenericStack(key, counter.get(key)))); + } + + return parsedKeys; + } + + public static Map parseDrive(DriveBlockEntity drive) { + Map map = new HashMap<>(); + + map.put("powered", drive.isPowered()); + + long totalBytes = 0; + long usedBytes = 0; + + if (drive.getCellCount() != 10) + return map; + + List driveCells = new ArrayList<>(); + for (ItemStack item : drive.getInternalInventory()) { + if (item.getItem() instanceof BasicStorageCell cell) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(item, null); + totalBytes += cellInventory.getTotalBytes(); + usedBytes += cellInventory.getUsedBytes(); + + driveCells.add(parseCell(cell, item)); + } + } + + map.put("usedBytes", usedBytes); + map.put("totalBytes", totalBytes); + map.put("cells", driveCells); + map.put("priority", drive.getPriority()); + map.put("menuIcon", LuaConverter.itemToObject(drive.getMainMenuIcon().getItem())); + map.put("position", LuaConverter.posToObject(drive.getBlockPos())); + map.put("name", drive.getCustomInventoryName().getString()); + + return map; + } + + public static Map parseCell(IBasicCellItem cell, ItemStack cellItem) { + Map map = new HashMap<>(); + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(cellItem, null); + + map.put("item", LuaConverter.itemToObject(cellItem.getItem())); + map.put("type", cell.getKeyType().toString()); + map.put("bytes", cell.getBytes(cellItem)); + map.put("bytesPerType", cell.getBytesPerType(cellItem)); + map.put("usedBytes", cellInventory.getUsedBytes()); + map.put("totalTypes", cell.getTotalTypes(cellItem)); + map.put("fuzzyMode", cell.getFuzzyMode(cellItem).toString()); + + return map; + } + + private static Map parseItemStack(Pair stack, @Nullable ICraftingService craftingService) { + Map map = LuaConverter.itemStackToObject(stack.getRight().toStack()); + map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); + map.put("count", stack.getLeft()); + return map; + } + + private static Map parseFluidStack(Pair stack, @Nullable ICraftingService craftingService) { + Map map = LuaConverter.fluidStackToObject(stack.getRight().toStack(1)); + map.put("count", stack.getLeft()); + map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); + return map; + } + + private static Map parseChemStack(Pair stack) { + Map map = new HashMap<>(); + long amount = stack.getLeft(); + map.put("name", stack.getRight().getStack().getTypeRegistryName().toString()); + map.put("amount", amount); + map.put("displayName", stack.getRight().getDisplayName().getString()); + map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getStack().getType().getTags())); + + return map; + } + + public static Map parsePattern(IPatternDetails pattern) { + Map map = new HashMap<>(); + + map.put("inputs", Arrays.stream(pattern.getInputs()).map(AEApi::parsePatternInput).collect(Collectors.toList())); + map.put("outputs", Arrays.stream(pattern.getOutputs()).map(AEApi::parseGenericStack).collect(Collectors.toList())); + map.put("primaryOutput", parseGenericStack(pattern.getPrimaryOutput())); + return map; + } + + public static Map parsePatternInput(IPatternDetails.IInput patternInput) { + Map map = new HashMap<>(); + map.put("primaryInput", parseGenericStack(patternInput.getPossibleInputs()[0])); + map.put("possibleInputs", + Arrays.stream(Arrays.copyOfRange(patternInput.getPossibleInputs(), 1, patternInput.getPossibleInputs().length)) + .map(AEApi::parseGenericStack)); + map.put("multiplier", patternInput.getMultiplier()); + map.put("remaining", patternInput.getRemainingKey(patternInput.getPossibleInputs()[0].what())); + return map; + } + + public static Map parseCraftingCPU(ICraftingCPU cpu, boolean recursive) { + Map map = new HashMap<>(); + long storage = cpu.getAvailableStorage(); + int coProcessors = cpu.getCoProcessors(); + boolean isBusy = cpu.isBusy(); + map.put("storage", storage); + map.put("coProcessors", coProcessors); + map.put("isBusy", isBusy); + if (!recursive) + map.put("craftingJob", cpu.getJobStatus() != null ? parseCraftingJob(cpu.getJobStatus(), null, null) : null); + map.put("name", cpu.getName() != null ? cpu.getName().getString() : "Unnamed"); + map.put("selectionMode", cpu.getSelectionMode().toString()); + + return map; + } + + public static Object parseCraftingJob(CraftingJobStatus status, AECraftJob craftJob, @Nullable ICraftingCPU cpu) { + Map properties = new HashMap<>(); + + properties.put("bridge_id", craftJob == null ? -1 : craftJob.getId()); + properties.put("quantity", status.crafting().amount()); + properties.put("resource", parseGenericStack(status.crafting())); + + if (cpu != null) { + CraftingCpuLogic craftingCpuLogic = ((CraftingCPUCluster) cpu).craftingLogic; + long pending = craftingCpuLogic.getPendingOutputs(status.crafting().what()); + long active = craftingCpuLogic.getWaitingFor(status.crafting().what()); + long crafted = status.crafting().amount() - (pending + active); + properties.put("completion", crafted / (double) status.crafting().amount()); + properties.put("crafted", crafted); + + properties.put("id", craftingCpuLogic.getLastLink().getCraftingID().toString()); + + properties.put("cpu", parseCraftingCPU(cpu, true)); + } + + return properties; + } + + public static MEStorage getMonitor(IGridNode node) { + return node.getGrid().getService(IStorageService.class).getInventory(); + } + + public static boolean isCrafting(ICraftingService grid, GenericFilter> filter, + @Nullable ICraftingCPU craftingCPU) { + + // If the passed cpu is null, check all cpus + if (craftingCPU == null) { + // Loop through all crafting cpus and check if the item is being crafted. + for (ICraftingCPU cpu : grid.getCpus()) { + if (cpu.isBusy()) { + CraftingJobStatus jobStatus = cpu.getJobStatus(); + + // avoid null pointer exception + if (jobStatus == null) + continue; + + if (filter.testAE(jobStatus.crafting())) + return true; + } + } + } else { + if (craftingCPU.isBusy()) { + CraftingJobStatus jobStatus = craftingCPU.getJobStatus(); + + // avoid null pointer exception + if (jobStatus == null) + return false; + + return filter.testAE(jobStatus.crafting()); + } + } + + return false; + } + + /// External Storage + /// Total + + public static long getTotalExternalItemStorage(IGridNode node) { + long total = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + Level level = bus.getLevel(); + BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); + BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); + + if (connectedInventoryEntity == null) + continue; + + LazyOptional itemHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.ITEM_HANDLER); + if (itemHandler.isPresent()) { + IItemHandler handler = itemHandler.orElse(null); + for (int i = 0; i < handler.getSlots(); i++) { + total += handler.getSlotLimit(i); + } + } + } + + return total; + } + + public static long getTotalExternalFluidStorage(IGridNode node) { + long total = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + Level level = bus.getLevel(); + BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); + BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); + + if (connectedInventoryEntity == null) + continue; + + LazyOptional fluidHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.FLUID_HANDLER); + if (fluidHandler.isPresent()) { + IFluidHandler handler = fluidHandler.orElse(null); + for (int i = 0; i < handler.getTanks(); i++) { + total += handler.getTankCapacity(i); + } + } + } + + return total; + } + + public static long getTotalExternalChemicalStorage(IGridNode node) { + long total = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + Level level = bus.getLevel(); + BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); + BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); + + if (connectedInventoryEntity == null) + continue; + + if (connectedInventoryEntity instanceof TileEntityChemicalTank tank) { + MergedChemicalTank.Current current = tank.getChemicalTank().getCurrent() == MergedChemicalTank.Current.EMPTY ? MergedChemicalTank.Current.GAS : tank.getChemicalTank().getCurrent(); + total += tank.getChemicalTank().getTankFromCurrent(current).getCapacity(); + } + } + + return total; + } + + /// Used + + public static long getUsedExternalItemStorage(IGridNode node) { + long used = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); + + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof AEItemKey) + used += aeKey.getLongValue(); + } + } + + return used; + } + + public static long getUsedExternalFluidStorage(IGridNode node) { + long used = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); + + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof AEFluidKey) + used += aeKey.getLongValue(); + } + } + + return used; + } + + public static long getUsedExternalChemicalStorage(IGridNode node) { + long used = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); + + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof MekanismKey) + used += aeKey.getLongValue(); + } + } + + return used; + } + + /// Internal Storage + /// Total + + public static long getTotalItemStorage(IGridNode node) { + long total = 0; + + // note: do not query DriveBlockEntity.class specifically here, because it will avoid subclasses, e.g. the ME Extended Drive from ExtendedAE + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { + total += cell.getBytes(null); + } + } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { + if (disk.getKeyType().toString().equals("ae2:i")) { + total += disk.getBytes(null); + } + } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof SuperStorageCell superStorageCell)) { + total += superStorageCell.getKiloBytes() * 1024L; + } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { + if (storageCell.getKeyType() != AEKeyType.items()) + continue; + total += storageCell.getKiloBytes() * 1024; + } + } + } + return total; + } + + public static long getTotalFluidStorage(IGridNode node) { + long total = 0; + + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { + total += cell.getBytes(null); + } + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { + total += superStorageCell.getKiloBytes() * 1024L; + } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { + if (storageCell.getKeyType() != AEKeyType.fluids()) + continue; + total += storageCell.getKiloBytes() * 1024; + } + } + } + + return total; + } + + public static long getTotalChemicalStorage(IGridNode node) { + long total = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(DriveBlockEntity.class)) { + DriveBlockEntity entity = (DriveBlockEntity) iGridNode.getService(IStorageProvider.class); + if (entity == null) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof ChemicalStorageCell cell) { + if (cell.getKeyType() instanceof MekanismKeyType) { + total += cell.getBytes(null); + } + } + } + } + + return total; + } + + /// Used + + public static long getUsedItemStorage(IGridNode node) { + long used = 0; + + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(stack, null); + + used += cellInventory.getUsedBytes(); + } + } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { + if (disk.getKeyType().toString().equals("ae2:i")) { + if (stack.getTag() == null) + continue; + long numBytesInCell = stack.getTag().getLong("ic"); + used += numBytesInCell; + } + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { + if (storageCell.getKeyType() != AEKeyType.items()) + continue; + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } + } + } + + return used; + } + + public static long getUsedFluidStorage(IGridNode node) { + long used = 0; + + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(stack, null); + + used += cellInventory.getUsedBytes(); + } + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { + if (storageCell.getKeyType() != AEKeyType.fluids()) + continue; + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } + } + } + + return used; + } + + public static long getUsedChemicalStorage(IGridNode node) { + long used = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(DriveBlockEntity.class)) { + DriveBlockEntity entity = (DriveBlockEntity) iGridNode.getService(IStorageProvider.class); + if (entity == null) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.getItem() instanceof ChemicalStorageCell) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(stack, null); + + used = cellInventory.getUsedBytes() / MekanismKeyType.TYPE.getAmountPerByte(); + } + } + } + + return used; + } + + /// Available Storage + + /** + * Calculates the available item storage on a given grid node. + * It subtracts the used item storage from the total item storage. + * + * @param node The grid node to calculate the available item storage for. + * @return The available item storage in bytes. + */ + public static long getAvailableItemStorage(IGridNode node) { + return getTotalItemStorage(node) - getUsedItemStorage(node); + } + + /** + * Calculates the available fluid storage in a given grid node. + * + * @param node The grid node to calculate the available fluid storage for. + * @return The available fluid storage in bytes. + */ + public static long getAvailableFluidStorage(IGridNode node) { + return getTotalFluidStorage(node) - getUsedFluidStorage(node); + } + + public static long getAvailableChemicalStorage(IGridNode node) { + return getTotalChemicalStorage(node) - getUsedChemicalStorage(node); + } + + /** + * Calculates the available external item storage of a given grid node. + * + * @param node The grid node for which to calculate the available external item storage. + * @return The available external item storage. + */ + public static long getAvailableExternalItemStorage(IGridNode node) { + return getTotalExternalItemStorage(node) - getUsedExternalItemStorage(node); + } + + /** + * Calculates the available external fluid storage on a given grid node by subtracting the used external fluid storage + * from the total external fluid storage. + * + * @param node The grid node on which to calculate the available external fluid storage. + * @return The available external fluid storage on the grid node. + */ + public static long getAvailableExternalFluidStorage(IGridNode node) { + return getTotalExternalFluidStorage(node) - getUsedExternalFluidStorage(node); + } + + public static long getAvailableExternalChemicalStorage(IGridNode node) { + return getTotalExternalChemicalStorage(node) - getUsedExternalChemicalStorage(node); + } + + public static ICraftingCPU getCraftingCPU(IGridNode node, String cpuName) { + if (cpuName.isEmpty()) return null; + ICraftingService grid = node.getGrid().getService(ICraftingService.class); + if (grid == null) return null; + + Iterator iterator = grid.getCpus().iterator(); + if (!iterator.hasNext()) return null; + + while (iterator.hasNext()) { + ICraftingCPU cpu = iterator.next(); + + if (cpu.getName() != null && cpu.getName().getString().equals(cpuName)) { + return cpu; + } + } + + return null; + } + + public static List listCells(IGridNode node) { + List items = new ArrayList<>(); + + Iterator iterator = node.getGrid().getNodes().iterator(); + + if (!iterator.hasNext()) return items; + while (iterator.hasNext()) { + IStorageProvider entity = iterator.next().getService(IStorageProvider.class); + if (!(entity instanceof DriveBlockEntity drive)) + continue; + + InternalInventory inventory = drive.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + items.add(parseCell(cell, stack)); + } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { + items.add(getObjectFromDisk(disk, stack)); + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { + items.add(getObjectFromSuperCell(superStorageCell, stack)); + } + } + } + + return items; + } + + private static Map getObjectFromDisk(DISKDrive drive, ItemStack stack) { + Map map = new HashMap<>(); + + map.put("item", stack.getItem().toString()); + + String cellType = ""; + + if (drive.getKeyType().toString().equals("ae2:i")) { + cellType = "item"; + } else if (drive.getKeyType().toString().equals("ae2:f")) { + cellType = "fluid"; + } + + map.put("cellType", cellType); + map.put("totalBytes", drive.getBytes(null)); + + return map; + } + + private static Map getObjectFromSuperCell(SuperStorageCell cell, ItemStack stack) { + Map map = new HashMap<>(); + + map.put("item", stack.getItem().toString()); + + String cellType = "all"; + + map.put("cellType", cellType); + map.put("totalBytes", cell.getBytes(stack)); + + return map; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AECraftJob.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AECraftJob.java new file mode 100644 index 000000000..f59291c09 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AECraftJob.java @@ -0,0 +1,312 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.CalculationStrategy; +import appeng.api.networking.crafting.CraftingJobStatus; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingPlan; +import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.networking.crafting.ICraftingService; +import appeng.api.networking.crafting.ICraftingSimulationRequester; +import appeng.api.networking.crafting.ICraftingSubmitResult; +import appeng.api.networking.security.IActionSource; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.KeyCounter; +import appeng.me.cluster.implementations.CraftingCPUCluster; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.IComputerAccess; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.blocks.blockentities.MeBridgeEntity; +import de.srendi.advancedperipherals.common.util.BasicCraftJob; +import de.srendi.advancedperipherals.common.util.StatusConstants; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +//TODO needs to persistent - should be stored in the me bridge +// We also need to do the same for the rs bridge. So we want to create a proper interface to keep the lua functions the same +public class AECraftJob extends BasicCraftJob { + + private final IGridNode node; + private final IActionSource source; + private final ICraftingSimulationRequester simulationRequester; + private final ICraftingRequester requester; + private ICraftingCPU targetCpu; + private final AEKey toCraft; + + private Future futureJob; + private ICraftingPlan currentJob; + @Nullable + private ICraftingLink jobLink; // Job after calculation was done + // Because the properties in `CraftingJobStatus` are set when the object is created, we need to create a supplier which + // always re-fetches the object from the cpu + private Supplier jobStatus; + // In the case the job is done and would return null, we have this cached one. + private CraftingJobStatus cachedStatus; + + public AECraftJob(Level world, final IComputerAccess computer, IGridNode node, AEKey item, long amount, MeBridgeEntity bridge, ICraftingCPU target) { + super(computer, "ae", world, amount); + this.node = node; + this.source = bridge; + this.toCraft = item; + this.simulationRequester = bridge; + this.requester = bridge; + this.targetCpu = target; + } + + @LuaFunction + public final Object getCraftingCPU() { + return AEApi.parseCraftingCPU(targetCpu, true); + } + + @Nullable + public ICraftingLink getJobLink() { + return jobLink; + } + + public ICraftingCPU getTargetCpu() { + return targetCpu; + } + + public AEKey getToCraft() { + return toCraft; + } + + @Override + protected boolean isJobDone() { + return jobLink != null && jobLink.isDone(); + } + + @Override + protected boolean isJobCanceled() { + return jobLink != null && jobLink.isCanceled(); + } + + @Override + public Object getParsedRequestedItem() { + if (getJobStatus() == null) { + return null; + } + return AEApi.parseGenericStack(getJobStatus().crafting()); + } + + @Override + public long getElapsedTime() { + if (getJobStatus() == null) { + return -1; + } + return getJobStatus().elapsedTimeNanos(); + } + + @Override + public long getTotalItems() { + if (getJobStatus() == null) { + return -1; + } + return getJobStatus().totalItems(); + } + + @Override + public long getItemProgress() { + if (getJobStatus() == null) { + return -1; + } + return getJobStatus().progress(); + } + + @Override + public Object getEmittedItems() { + if (currentJob == null) { + return null; + } + return AEApi.parseKeyCounter(currentJob.emittedItems()); + } + + @Override + public Object getUsedItems() { + if (currentJob == null) { + return null; + } + return AEApi.parseKeyCounter(currentJob.usedItems()); + } + + @Override + public Object getMissingItems() { + if (currentJob == null) { + return null; + } + return AEApi.parseKeyCounter(currentJob.missingItems()); + } + + @Override + public boolean hasMultiplePaths() { + if (currentJob == null) { + return false; + } + return currentJob.multiplePaths(); + } + + @Override + public Object getFinalOutput() { + if (currentJob == null) { + return null; + } + return AEApi.parseGenericStack(currentJob.finalOutput()); + } + + @Override + public boolean cancel() { + if (targetCpu instanceof CraftingCPUCluster cluster) { + if (cluster.isBusy()) { + cluster.cancel(); + return true; + } + } + return false; + } + + @LuaFunction + public long getUsedBytes() { + if (currentJob == null) { + return -1; + } + return currentJob.bytes(); + } + + public AECraftJob withJobStatus(Supplier jobStatus) { + this.jobStatus = jobStatus; + return this; + } + + public AECraftJob withCPU(ICraftingCPU craftingCpu) { + if (this.targetCpu == null) { + this.targetCpu = craftingCpu; + } + return this; + } + + public void startCalculation() { + if (startedCalculation) { + return; + } + startedCalculation = true; + + IGrid grid = node.getGrid(); + + ICraftingService craftingService = grid.getService(ICraftingService.class); + + if (!craftingService.isCraftable(toCraft)) { + fireEvent(true, StatusConstants.NOT_CRAFTABLE); + calculationNotSuccessful = true; + return; + } + + futureJob = craftingService.beginCraftingCalculation(world, this.simulationRequester, toCraft, amount, CalculationStrategy.REPORT_MISSING_ITEMS); + fireEvent(false, StatusConstants.CALCULATION_STARTED); + } + + public void maybeCraft() { + if (startedCrafting || futureJob == null || !futureJob.isDone()) { + return; + } + ICraftingPlan job; + + try { + job = futureJob.get(); + } catch (ExecutionException | InterruptedException ex) { + AdvancedPeripherals.debug("Tried to get job, but job calculation is not done. Should be done.", org.apache.logging.log4j.Level.ERROR); + ex.printStackTrace(); + fireEvent(true, StatusConstants.UNKNOWN_ERROR); + return; + } + + if (job == null) { + AdvancedPeripherals.debug("Job is null, should not be null.", org.apache.logging.log4j.Level.ERROR); + fireEvent(true, StatusConstants.UNKNOWN_ERROR); + return; + } + this.currentJob = job; + + KeyCounter missing = job.missingItems(); + if (!missing.isEmpty()) { + fireEvent(true, StatusConstants.MISSING_ITEMS); + calculationNotSuccessful = true; + return; + } + + IGrid grid = node.getGrid(); + + ICraftingService craftingService = grid.getService(ICraftingService.class); + ICraftingSubmitResult submitResult = craftingService.submitJob(job, requester, targetCpu, false, this.source); + if (!submitResult.successful()) { + calculationNotSuccessful = true; + fireEvent(true, submitResult.errorCode().toString()); + return; + } + + this.jobLink = submitResult.link(); + this.futureJob = null; + setStartedCrafting(); + prepareCPUAndStatus(craftingService); + } + + public void jobStateChanged() { + ICraftingLink jobLink = this.jobLink; + if (jobLink == null) { + fireEvent(true, StatusConstants.UNKNOWN_ERROR); + return; + } + + if (jobLink.isCanceled() && !isJobCanceled) { + fireEvent(false, StatusConstants.JOB_CANCELED); + setJobCanceled(); + return; + } + + if (jobLink.isDone() && !isJobDone) { + fireEvent(false, StatusConstants.JOB_DONE); + setJobDone(); + } + } + + private void prepareCPUAndStatus(ICraftingService service) { + if (jobLink == null || jobStatus != null || !startedCrafting) { + return; + } + for (ICraftingCPU cpu : service.getCpus()) { + if (cpu instanceof CraftingCPUCluster cpuCluster) { + if (cpuCluster.craftingLogic.getLastLink() != null && cpuCluster.craftingLogic.getLastLink().getCraftingID().equals(jobLink.getCraftingID())) { + this.jobStatus = () -> { + // Compare the id of the job in the cpu. This job object can exist longer than the job needs time to complete. So the cpu could have a new job + if (cpuCluster.craftingLogic.getLastLink() != null && cpuCluster.craftingLogic.getLastLink().getCraftingID().equals(jobLink.getCraftingID())) + return cpuCluster.getJobStatus(); + return null; + }; + cpuCluster.craftingLogic.addListener((key) -> { + // The last time the listeners are called from the cpu logic is when the job is finished + // These listeners are not intended by ae2 to be used like this, but it works, and we don't modify the key + if (cpuCluster.getJobStatus() != null) { + this.cachedStatus = cpuCluster.getJobStatus(); + } + }); + this.targetCpu = cpu; + return; + } + } + } + AdvancedPeripherals.debug("Could not find CPU or job link even after job started", org.apache.logging.log4j.Level.WARN); + } + + private CraftingJobStatus getJobStatus() { + if (jobStatus == null || jobStatus.get() == null && cachedStatus != null) { + return cachedStatus; + } + cachedStatus = jobStatus.get(); + return jobStatus.get(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeBridgeEntityListener.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEBridgeEntityListener.java similarity index 57% rename from src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeBridgeEntityListener.java rename to src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEBridgeEntityListener.java index 1aee16c85..439caf900 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeBridgeEntityListener.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEBridgeEntityListener.java @@ -1,21 +1,20 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; +package de.srendi.advancedperipherals.common.addons.ae2; import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNodeListener; import de.srendi.advancedperipherals.common.blocks.blockentities.MeBridgeEntity; -//TODO: Maybe do something special with these methods? -public class MeBridgeEntityListener implements IGridNodeListener { +public class MEBridgeEntityListener implements IGridNodeListener { - public static final MeBridgeEntityListener INSTANCE = new MeBridgeEntityListener(); + public static final MEBridgeEntityListener INSTANCE = new MEBridgeEntityListener(); @Override public void onSecurityBreak(MeBridgeEntity nodeOwner, IGridNode node) { - + // Maybe do something special with these methods? } @Override public void onSaveChanges(MeBridgeEntity nodeOwner, IGridNode node) { - + // Maybe do something special with these methods? } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeFluidHandler.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEFluidHandler.java similarity index 77% rename from src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeFluidHandler.java rename to src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEFluidHandler.java index 8072a777d..73936fb83 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeFluidHandler.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEFluidHandler.java @@ -1,9 +1,10 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; +package de.srendi.advancedperipherals.common.addons.ae2; import appeng.api.config.Actionable; import appeng.api.networking.security.IActionSource; import appeng.api.stacks.AEFluidKey; import appeng.api.storage.MEStorage; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MEBridgePeripheral; import de.srendi.advancedperipherals.common.util.Pair; import de.srendi.advancedperipherals.common.util.inventory.FluidFilter; import de.srendi.advancedperipherals.common.util.inventory.IStorageSystemFluidHandler; @@ -12,23 +13,24 @@ /** * Used to transfer item between an inventory and the ME system. - * @see de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MeBridgePeripheral + * + * @see MEBridgePeripheral */ -public class MeFluidHandler implements IStorageSystemFluidHandler { +public class MEFluidHandler implements IStorageSystemFluidHandler { @NotNull private final MEStorage storageMonitor; @NotNull private final IActionSource actionSource; - public MeFluidHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { + public MEFluidHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { this.storageMonitor = storageMonitor; this.actionSource = actionSource; } @Override public int fill(FluidStack resource, FluidAction action) { - if(resource.isEmpty()) + if (resource.isEmpty()) return 0; AEFluidKey itemKey = AEFluidKey.of(resource.getFluid()); long inserted = storageMonitor.insert(itemKey, resource.getAmount(), action == FluidAction.SIMULATE ? Actionable.SIMULATE : Actionable.MODULATE, actionSource); @@ -39,8 +41,8 @@ public int fill(FluidStack resource, FluidAction action) { @NotNull @Override public FluidStack drain(FluidFilter filter, FluidAction simulate) { - Pair itemKey = AppEngApi.findAEFluidFromFilter(storageMonitor, null, filter); - if(itemKey == null) + Pair itemKey = AEApi.findAEFluidFromFilter(storageMonitor, null, filter); + if (itemKey == null) return FluidStack.EMPTY; long extracted = storageMonitor.extract(itemKey.getRight(), filter.getCount(), simulate == FluidAction.SIMULATE ? Actionable.SIMULATE : Actionable.MODULATE, actionSource); return new FluidStack(itemKey.getRight().getFluid(), (int) Math.min(extracted, Integer.MAX_VALUE)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeItemHandler.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEItemHandler.java similarity index 82% rename from src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeItemHandler.java rename to src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEItemHandler.java index a3542cda3..4fdc79dac 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeItemHandler.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEItemHandler.java @@ -1,9 +1,10 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; +package de.srendi.advancedperipherals.common.addons.ae2; import appeng.api.config.Actionable; import appeng.api.networking.security.IActionSource; import appeng.api.stacks.AEItemKey; import appeng.api.storage.MEStorage; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MEBridgePeripheral; import de.srendi.advancedperipherals.common.util.Pair; import de.srendi.advancedperipherals.common.util.inventory.IStorageSystemItemHandler; import de.srendi.advancedperipherals.common.util.inventory.ItemFilter; @@ -13,16 +14,16 @@ /** * Used to transfer item between an inventory and the ME system. * - * @see de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MeBridgePeripheral + * @see MEBridgePeripheral */ -public class MeItemHandler implements IStorageSystemItemHandler { +public class MEItemHandler implements IStorageSystemItemHandler { @NotNull private final MEStorage storageMonitor; @NotNull private final IActionSource actionSource; - public MeItemHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { + public MEItemHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { this.storageMonitor = storageMonitor; this.actionSource = actionSource; } @@ -40,7 +41,7 @@ public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate @Override public ItemStack extractItem(ItemFilter filter, int count, boolean simulate) { - Pair itemKey = AppEngApi.findAEStackFromFilter(storageMonitor, null, filter); + Pair itemKey = AEApi.findAEStackFromFilter(storageMonitor, null, filter); if (itemKey.getRight() == null) return ItemStack.EMPTY; long extracted = storageMonitor.extract(itemKey.getRight(), count, simulate ? Actionable.SIMULATE : Actionable.MODULATE, actionSource); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/WiredCableP2PTunnelPart.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/WiredCableP2PTunnelPart.java new file mode 100644 index 000000000..596ce5e62 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/WiredCableP2PTunnelPart.java @@ -0,0 +1,174 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.networking.IGridNodeListener; +import appeng.api.parts.IPartItem; +import appeng.api.parts.IPartModel; +import appeng.items.parts.PartModels; +import appeng.parts.p2p.CapabilityP2PTunnelPart; +import appeng.parts.p2p.P2PModels; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.network.wired.IWiredElement; +import dan200.computercraft.api.network.wired.IWiredNetworkChange; +import dan200.computercraft.api.network.wired.IWiredNode; +import dan200.computercraft.shared.Capabilities; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.Vec3; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; + +public class WiredCableP2PTunnelPart extends CapabilityP2PTunnelPart { + private static final P2PModels MODELS = new P2PModels(AdvancedPeripherals.getRL("part/p2p/p2p_tunnel_cable")); + + private final IWiredElement element = new P2PWiredElement(); + private final IWiredElement outElement = new P2PWiredElement(); + private final IWiredNode node = this.element.getNode(); + private Set connected = new HashSet<>(); + private boolean activated = false; + + public WiredCableP2PTunnelPart(IPartItem> partItem) { + super(partItem, Capabilities.CAPABILITY_WIRED_ELEMENT); + this.inputHandler = outElement; + this.outputHandler = outElement; + this.emptyHandler = null; // should never used + } + + @PartModels + public static List getModels() { + return MODELS.getModels(); + } + + @Override + public IPartModel getStaticModels() { + return MODELS.getModel(this.isPowered(), this.isActive()); + } + + @Override + public void onTunnelConfigChange() { + super.onTunnelConfigChange(); + this.connectionsChanged(); + } + + @Override + public void onTunnelNetworkChange() { + super.onTunnelNetworkChange(); + this.connectionsChanged(); + } + + protected void connectionsChanged() { + if (this.isClientSide()) { + return; + } + if (!this.isActive()) { + return; + } + if (!this.activated) { + this.activated = true; + this.node.connectTo(this.outElement.getNode()); + } + + Stream nodeStream = this.getOutputStream().filter(out -> out != this); + WiredCableP2PTunnelPart in = this.getInput(); + if (in != null && in != this) { + nodeStream = Stream.concat(nodeStream, Stream.of(in)); + } + Set nodes = nodeStream.collect(Collectors.toCollection(HashSet::new)); + + for (WiredCableP2PTunnelPart part : this.connected.stream().filter(n -> !nodes.contains(n)).collect(Collectors.toList())) { + if (part.connected.contains(this)) { + this.node.disconnectFrom(part.node); + part.connected.remove(this); + } + this.connected.remove(part); + } + + for (WiredCableP2PTunnelPart part : nodes) { + if (!this.connected.contains(part)) { + this.node.connectTo(part.node); + this.connected.add(part); + part.connected.add(this); + } + } + } + + @Override + protected void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + if (reason == IGridNodeListener.State.GRID_BOOT) { + return; + } + if (this.isActive()) { + if (!this.getMainNode().hasGridBooted()) { + return; + } + this.connectionsChanged(); + this.refreshConnection(); + } else if (this.activated) { + this.activated = false; + this.node.remove(); + this.connected.clear(); + } + } + + protected BlockPos getFacingPos() { + return this.getHost().getLocation().getPos().relative(this.getSide()); + } + + protected void refreshConnection() { + BlockEntity cable = this.getLevel().getBlockEntity(this.getFacingPos()); + IWiredElement elem = cable == null ? null : cable.getCapability(Capabilities.CAPABILITY_WIRED_ELEMENT, this.getSide().getOpposite()).orElse(null); + if (elem == null) { + return; + } + elem.getNode().connectTo(this.outElement.getNode()); + } + + @Override + public void onNeighborChanged(BlockGetter level, BlockPos pos, BlockPos neighbor) { + if (!this.getFacingPos().equals(neighbor)) { + return; + } + if (this.activated) { + this.refreshConnection(); + } + } + + private class P2PWiredElement implements IWiredElement { + private final IWiredNode node = ComputerCraftAPI.createWiredNodeForElement(this); + + @Nonnull + @Override + public IWiredNode getNode() { + return node; + } + + @Nonnull + @Override + public String getSenderID() { + return "p2p"; + } + + @Nonnull + @Override + public Level getLevel() { + return WiredCableP2PTunnelPart.this.getLevel(); + } + + @Nonnull + @Override + public Vec3 getPosition() { + return Vec3.atCenterOf(WiredCableP2PTunnelPart.this.getBlockEntity().getBlockPos()); + } + + @Override + public void networkChanged(IWiredNetworkChange change) {} + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/AppEngApi.java b/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/AppEngApi.java deleted file mode 100644 index 3bc0c6d8e..000000000 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/AppEngApi.java +++ /dev/null @@ -1,641 +0,0 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; - -import appeng.api.inventories.InternalInventory; -import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.CraftingJobStatus; -import appeng.api.networking.crafting.ICraftingCPU; -import appeng.api.networking.crafting.ICraftingService; -import appeng.api.networking.storage.IStorageService; -import appeng.api.stacks.*; -import appeng.api.storage.AEKeyFilter; -import appeng.api.storage.IStorageProvider; -import appeng.api.storage.MEStorage; -import appeng.api.storage.cells.IBasicCellItem; -import appeng.blockentity.storage.DriveBlockEntity; -import appeng.parts.storagebus.StorageBusPart; -import com.the9grounds.aeadditions.item.storage.StorageCell; -import com.the9grounds.aeadditions.item.storage.SuperStorageCell; -import dan200.computercraft.shared.util.NBTUtil; -import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.common.addons.APAddons; -import de.srendi.advancedperipherals.common.util.LuaConverter; -import de.srendi.advancedperipherals.common.util.Pair; -import de.srendi.advancedperipherals.common.util.inventory.FluidFilter; -import de.srendi.advancedperipherals.common.util.inventory.ItemFilter; -import de.srendi.advancedperipherals.common.util.inventory.ItemUtil; -import io.github.projectet.ae2things.item.DISKDrive; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import me.ramidzkh.mekae2.ae2.MekanismKey; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.registries.ForgeRegistries; -import org.apache.logging.log4j.Level; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class AppEngApi { - - public static Pair findAEStackFromStack(MEStorage monitor, @Nullable ICraftingService crafting, ItemStack item) { - return findAEStackFromFilter(monitor, crafting, ItemFilter.fromStack(item)); - } - - public static Pair findAEStackFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, ItemFilter item) { - for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { - if (temp.getKey() instanceof AEItemKey key && item.test(key.toStack())) - return Pair.of(temp.getLongValue(), key); - } - - if (crafting == null) - return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); - - for (var temp : crafting.getCraftables(param -> true)) { - if (temp instanceof AEItemKey key && item.test(key.toStack())) - return Pair.of(0L, key); - } - - return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); - } - - public static Pair findAEFluidFromStack(MEStorage monitor, @Nullable ICraftingService crafting, FluidStack item) { - return findAEFluidFromFilter(monitor, crafting, FluidFilter.fromStack(item)); - } - - public static Pair findAEFluidFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, FluidFilter item) { - for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { - if (temp.getKey() instanceof AEFluidKey key && item.test(key.toStack(1))) - return Pair.of(temp.getLongValue(), key); - } - - if (crafting == null) - return null; - - for (var temp : crafting.getCraftables(param -> true)) { - if (temp instanceof AEFluidKey key && item.test(key.toStack(1))) - return Pair.of(0L, key); - } - - return null; - } - - public static List listStacks(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - KeyCounter keyCounter = monitor.getAvailableStacks(); - for (Object2LongMap.Entry aeKey : keyCounter) { - if (aeKey.getKey() instanceof AEItemKey itemKey) { - items.add(getObjectFromStack(Pair.of(aeKey.getLongValue(), itemKey), service)); - } - } - return items; - } - - public static List listCraftableStacks(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - KeyCounter keyCounter = monitor.getAvailableStacks(); - Set craftables = service.getCraftables(AEKeyFilter.none()); - for (AEKey aeKey : craftables) { - if (aeKey instanceof AEItemKey) { - items.add(getObjectFromStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); - } - } - return items; - } - - public static List listFluids(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { - if (aeKey.getKey() instanceof AEFluidKey itemKey) { - items.add(getObjectFromStack(Pair.of(aeKey.getLongValue(), itemKey), service)); - } - } - return items; - } - - public static List listGases(MEStorage monitor, ICraftingService service, int flag) { - List items = new ArrayList<>(); - for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { - if (APAddons.appMekLoaded && aeKey.getKey() instanceof MekanismKey itemKey) { - items.add(getObjectFromStack(Pair.of(aeKey.getLongValue(), itemKey), service)); - } - } - return items; - } - - public static List listCraftableFluids(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - KeyCounter keyCounter = monitor.getAvailableStacks(); - Set craftables = service.getCraftables(AEKeyFilter.none()); - for (AEKey aeKey : craftables) { - if (aeKey instanceof AEFluidKey) { - items.add(getObjectFromStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); - } - } - return items; - } - - public static Map getObjectFromStack(Pair stack, @Nullable ICraftingService service) { - if (stack.getRight() == null) - return Collections.emptyMap(); - if (stack.getRight() instanceof AEItemKey itemKey) - return getObjectFromItemStack(Pair.of(stack.getLeft(), itemKey), service); - if (stack.getRight() instanceof AEFluidKey fluidKey) - return getObjectFromFluidStack(Pair.of(stack.getLeft(), fluidKey), service); - if (APAddons.appMekLoaded && (stack.getRight() instanceof MekanismKey gasKey)) - return getObjectFromGasStack(Pair.of(stack.getLeft(), gasKey), service); - - AdvancedPeripherals.debug("Could not create table from unknown stack " + stack.getRight().getClass() + " - Report this to the maintainer of ap", Level.ERROR); - return Collections.emptyMap(); - } - - private static Map getObjectFromItemStack(Pair stack, @Nullable ICraftingService craftingService) { - Map map = new HashMap<>(); - String displayName = stack.getRight().getDisplayName().getString(); - CompoundTag nbt = stack.getRight().toTag(); - long amount = stack.getLeft(); - map.put("fingerprint", ItemUtil.getFingerprint(stack.getRight().toStack())); - map.put("name", ItemUtil.getRegistryKey(stack.getRight().getItem()).toString()); - map.put("amount", amount); - map.put("displayName", displayName); - map.put("nbt", NBTUtil.toLua(nbt)); - map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getItem().builtInRegistryHolder().tags())); - map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); - - return map; - } - - private static Map getObjectFromFluidStack(Pair stack, @Nullable ICraftingService craftingService) { - Map map = new HashMap<>(); - long amount = stack.getLeft(); - map.put("name", ForgeRegistries.FLUIDS.getKey(stack.getRight().getFluid()).toString()); - map.put("amount", amount); - map.put("displayName", stack.getRight().getDisplayName().getString()); - map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getFluid().builtInRegistryHolder().tags())); - map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); - - return map; - } - - private static Map getObjectFromGasStack(Pair stack, @Nullable ICraftingService craftingService) { - Map map = new HashMap<>(); - long amount = stack.getLeft(); - map.put("name", stack.getRight().getStack().getTypeRegistryName().toString()); - map.put("amount", amount); - map.put("displayName", stack.getRight().getDisplayName().getString()); - map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getStack().getType().getTags())); - - return map; - } - - public static Map getObjectFromCPU(ICraftingCPU cpu) { - Map map = new HashMap<>(); - long storage = cpu.getAvailableStorage(); - int coProcessors = cpu.getCoProcessors(); - boolean isBusy = cpu.isBusy(); - map.put("storage", storage); - map.put("coProcessors", coProcessors); - map.put("isBusy", isBusy); - map.put("craftingJob", cpu.getJobStatus() != null ? getObjectFromJob(cpu.getJobStatus()) : null); - map.put("name", cpu.getName() != null ? cpu.getName().getString() : "Unnamed"); - map.put("selectionMode", cpu.getSelectionMode().toString()); - - return map; - } - - public static Map getObjectFromJob(CraftingJobStatus job) { - Map map = new HashMap<>(); - map.put("storage", getObjectFromGenericStack(job.crafting())); - map.put("elapsedTimeNanos", job.elapsedTimeNanos()); - map.put("totalItem", job.totalItems()); - map.put("progress", job.progress()); - - return map; - } - - public static Map getObjectFromGenericStack(GenericStack stack) { - if (stack.what() == null) - return Collections.emptyMap(); - if (stack.what() instanceof AEItemKey aeItemKey) - return getObjectFromItemStack(Pair.of(stack.amount(), aeItemKey), null); - if (stack.what() instanceof AEFluidKey aeFluidKey) - return getObjectFromFluidStack(Pair.of(stack.amount(), aeFluidKey), null); - return Collections.emptyMap(); - } - - public static MEStorage getMonitor(IGridNode node) { - return node.getGrid().getService(IStorageService.class).getInventory(); - } - - public static boolean isItemCrafting(MEStorage monitor, ICraftingService grid, ItemFilter filter, - @Nullable ICraftingCPU craftingCPU) { - Pair stack = AppEngApi.findAEStackFromFilter(monitor, grid, filter); - - // If the item stack does not exist, it cannot be crafted. - if (stack == null) - return false; - - // If the passed cpu is null, check all cpus - if (craftingCPU == null) { - // Loop through all crafting cpus and check if the item is being crafted. - for (ICraftingCPU cpu : grid.getCpus()) { - if (cpu.isBusy()) { - CraftingJobStatus jobStatus = cpu.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - continue; - - if (jobStatus.crafting().what().equals(stack.getRight())) - return true; - } - } - } else { - if (craftingCPU.isBusy()) { - CraftingJobStatus jobStatus = craftingCPU.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - return false; - - return jobStatus.crafting().what().equals(stack.getRight()); - } - } - - return false; - } - - public static boolean isFluidCrafting(MEStorage monitor, ICraftingService grid, FluidFilter filter, - @Nullable ICraftingCPU craftingCPU) { - Pair stack = AppEngApi.findAEFluidFromFilter(monitor, grid, filter); - - // If the fluid stack does not exist, it cannot be crafted. - if (stack == null) - return false; - - // If the passed cpu is null, check all cpus - if (craftingCPU == null) { - // Loop through all crafting cpus and check if the fluid is being crafted. - for (ICraftingCPU cpu : grid.getCpus()) { - if (cpu.isBusy()) { - CraftingJobStatus jobStatus = cpu.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - continue; - - if (jobStatus.crafting().what().equals(stack.getRight())) - return true; - } - } - } else { - if (craftingCPU.isBusy()) { - CraftingJobStatus jobStatus = craftingCPU.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - return false; - - return jobStatus.crafting().what().equals(stack.getRight()); - } - } - - return false; - } - - public static long getTotalItemStorage(IGridNode node) { - long total = 0; - - // note: do not query DriveBlockEntity.class specifically here, because it will avoid subclasses, e.g. the ME Extended Drive from ExtendedAE - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { - total += cell.getBytes(null); - } - } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { - if (disk.getKeyType().toString().equals("ae2:i")) { - total += disk.getBytes(null); - } - } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof SuperStorageCell superStorageCell)) { - total += superStorageCell.getKiloBytes() * 1024; - } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { - if (storageCell.getKeyType() != AEKeyType.items()) - continue; - total += storageCell.getKiloBytes() * 1024; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - net.minecraft.world.level.Level level = bus.getLevel(); - BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); - BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); - if (connectedInventoryEntity == null) - continue; - - LazyOptional itemHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.ITEM_HANDLER); - if (itemHandler.isPresent()) { - IItemHandler handler = itemHandler.orElse(null); - for (int i = 0; i < handler.getSlots(); i++) { - total += handler.getSlotLimit(i); - } - } - } - - return total; - } - - public static long getTotalFluidStorage(IGridNode node) { - long total = 0; - - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { - total += cell.getBytes(null); - } - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { - total += superStorageCell.getKiloBytes() * 1024; - } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { - if (storageCell.getKeyType() != AEKeyType.fluids()) - continue; - total += storageCell.getKiloBytes() * 1024; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - net.minecraft.world.level.Level level = bus.getLevel(); - BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); - BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); - if (connectedInventoryEntity == null) - continue; - - LazyOptional fluidHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.FLUID_HANDLER); - if (fluidHandler.isPresent()) { - IFluidHandler handler = fluidHandler.orElse(null); - for (int i = 0; i < handler.getTanks(); i++) { - total += handler.getTankCapacity(i); - } - } - } - - return total; - } - - public static long getUsedItemStorage(IGridNode node) { - long used = 0; - - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - int bytesPerType = cell.getBytesPerType(null); - - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { - if (stack.getTag() == null) - continue; - int numOfType = stack.getTag().getLongArray("amts").length; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += ((int) Math.ceil(((double) numItemsInCell) / 8)) + ((long) bytesPerType * numOfType); - } - } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { - if (disk.getKeyType().toString().equals("ae2:i")) { - if (stack.getTag() == null) - continue; - long numBytesInCell = stack.getTag().getLong("ic"); - used += numBytesInCell; - } - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { - if (storageCell.getKeyType() != AEKeyType.items()) - continue; - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); - - for (Object2LongMap.Entry aeKey : keyCounter) { - if (aeKey.getKey() instanceof AEItemKey) { - used += aeKey.getLongValue(); - } - } - } - - return used; - } - - public static long getUsedFluidStorage(IGridNode node) { - long used = 0; - - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.getItem() instanceof IBasicCellItem cell) { - int bytesPerType = cell.getBytesPerType(null); - - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { - if (stack.getTag() == null) - continue; - int numOfType = stack.getTag().getLongArray("amts").length; - long numBucketsInCell = stack.getTag().getLong("ic") / 1000; - - used += ((int) Math.ceil(((double) numBucketsInCell) / 8)) + ((long) bytesPerType * numOfType); - } - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { - if (storageCell.getKeyType() != AEKeyType.fluids()) - continue; - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); - - for (Object2LongMap.Entry aeKey : keyCounter) { - if (aeKey.getKey() instanceof AEFluidKey fluidKey) { - used += aeKey.getLongValue(); - } - } - } - - return used; - } - - public static long getAvailableItemStorage(IGridNode node) { - return getTotalItemStorage(node) - getUsedItemStorage(node); - } - - public static long getAvailableFluidStorage(IGridNode node) { - return getTotalFluidStorage(node) - getUsedFluidStorage(node); - } - - public static List listCells(IGridNode node) { - List items = new ArrayList<>(); - - Iterator iterator = node.getGrid().getNodes().iterator(); - - if (!iterator.hasNext()) return items; - while (iterator.hasNext()) { - IStorageProvider entity = iterator.next().getService(IStorageProvider.class); - if (!(entity instanceof DriveBlockEntity drive)) - continue; - - InternalInventory inventory = drive.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - items.add(getObjectFromCell(cell, stack)); - } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { - items.add(getObjectFromDisk(disk, stack)); - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { - items.add(getObjectFromSuperCell(superStorageCell, stack)); - } - } - } - - return items; - } - - private static Map getObjectFromCell(IBasicCellItem cell, ItemStack stack) { - Map map = new HashMap<>(); - - map.put("item", ItemUtil.getRegistryKey(stack.getItem()).toString()); - - String cellType = ""; - - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { - cellType = "item"; - } else if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { - cellType = "fluid"; - } - - map.put("cellType", cellType); - map.put("bytesPerType", cell.getBytesPerType(null)); - map.put("totalBytes", cell.getBytes(null)); - - return map; - } - - private static Map getObjectFromDisk(DISKDrive drive, ItemStack stack) { - Map map = new HashMap<>(); - - map.put("item", stack.getItem().toString()); - - String cellType = ""; - - if (drive.getKeyType().toString().equals("ae2:i")) { - cellType = "item"; - } else if (drive.getKeyType().toString().equals("ae2:f")) { - cellType = "fluid"; - } - - map.put("cellType", cellType); - map.put("totalBytes", drive.getBytes(null)); - - return map; - } - - private static Map getObjectFromSuperCell(SuperStorageCell cell, ItemStack stack) { - Map map = new HashMap<>(); - - map.put("item", stack.getItem().toString()); - - String cellType = "all"; - - map.put("cellType", cellType); - map.put("totalBytes", cell.getBytes(stack)); - - return map; - } -} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/CraftJob.java b/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/CraftJob.java deleted file mode 100644 index 1b2d5d9a9..000000000 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/CraftJob.java +++ /dev/null @@ -1,135 +0,0 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; - -import appeng.api.networking.IGrid; -import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.*; -import appeng.api.networking.security.IActionSource; -import appeng.api.stacks.AEKey; -import dan200.computercraft.api.lua.ILuaCallback; -import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.peripheral.IComputerAccess; -import de.srendi.advancedperipherals.AdvancedPeripherals; -import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -public class CraftJob implements ILuaCallback { - - public static final String EVENT = "crafting"; - - private final IComputerAccess computer; - private final IGridNode node; - private final IActionSource source; - private final ICraftingSimulationRequester requester; - private final ICraftingCPU target; - private final AEKey item; - - private final long amount; - private final Level world; - private Future futureJob; - private boolean startedCrafting = false; - - private MethodResult result; - private LuaException exception; - - public CraftJob(Level world, final IComputerAccess computer, IGridNode node, AEKey item, long amount, IActionSource source, - ICraftingSimulationRequester requester, ICraftingCPU target) { - this.computer = computer; - this.node = node; - this.world = world; - this.source = source; - this.item = item; - this.amount = amount; - this.requester = requester; - this.target = target; - } - - protected void fireEvent(boolean success, @Nullable String exception) { - this.result = MethodResult.of(success, exception); - this.exception = new LuaException(exception); - this.computer.queueEvent(EVENT, success, exception); - - } - - protected void fireNotConnected() { - fireEvent(false, "not connected"); - } - - public void setStartedCrafting(boolean startedCrafting) { - this.startedCrafting = startedCrafting; - } - - public boolean isCraftingStarted() { - return startedCrafting; - } - - public void startCrafting() { - IGrid grid = node.getGrid(); - if (grid == null) { //true when the block is not connected - fireNotConnected(); - return; - } - - ICraftingService crafting = grid.getService(ICraftingService.class); - - if (item == null) { - AdvancedPeripherals.debug("Could not get AEItem from monitor", org.apache.logging.log4j.Level.FATAL); - return; - } - - if (!crafting.isCraftable(item)) { - fireEvent(false, item.getId().toString() + " is not craftable"); - return; - } - - futureJob = crafting.beginCraftingCalculation(world, this.requester, item, amount, CalculationStrategy.REPORT_MISSING_ITEMS); - fireEvent(true, "Started calculation of the recipe. After it's finished, the system will start crafting the item."); - } - - public void maybeCraft() { - if (startedCrafting || futureJob == null || !futureJob.isDone()) - return; - ICraftingPlan job; - try { - job = futureJob.get(); - } catch (ExecutionException | InterruptedException ex) { - AdvancedPeripherals.debug("Tried to get job, but job calculation is not done. Should be done.", org.apache.logging.log4j.Level.FATAL); - ex.printStackTrace(); - return; - } - - if (job == null) { - AdvancedPeripherals.debug("Job is null, should not be null.", org.apache.logging.log4j.Level.FATAL); - return; - } - - if (job.simulation()) { - return; - } - - IGrid grid = node.getGrid(); - if (grid == null) { - return; - } - - //TODO: Create events or methods like `isCraftingFinished` or `getCraftingJobState` - ICraftingService crafting = grid.getService(ICraftingService.class); - crafting.submitJob(job, null, target, false, this.source); - - setStartedCrafting(true); - - this.futureJob = null; - } - - @NotNull - @Override - public MethodResult resume(Object[] objects) { - if (result != null) return result; - if (exception != null) return MethodResult.of(exception); - return MethodResult.of(); - } -} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java index a4eb92215..fd45750e4 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java @@ -16,7 +16,7 @@ public ManaFlowerIntegration(BlockEntity entity) { @NotNull @Override public String getType() { - return "manaFlower"; + return "mana_flower"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java index cea44bbe9..2d2fb83c9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java @@ -15,7 +15,7 @@ public ManaPoolIntegration(BlockEntity entity) { @NotNull @Override public String getType() { - return "manaPool"; + return "mana_pool"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java index e0ea451f9..d615db44f 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java @@ -16,7 +16,7 @@ public SpreaderIntegration(BlockEntity entity) { @NotNull @Override public String getType() { - return "manaSpreader"; + return "mana_spreader"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java index 09e655726..0a35755df 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java @@ -2,7 +2,6 @@ import dan200.computercraft.api.lua.LuaFunction; import de.srendi.advancedperipherals.lib.peripherals.BlockEntityIntegrationPeripheral; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; @@ -20,9 +19,7 @@ public BeaconIntegration(BlockEntity entity) { @LuaFunction(mainThread = true) public final int getLevel() { - // because levels are now protected field .... why? - CompoundTag savedData = blockEntity.saveWithoutMetadata(); - return savedData.getInt("Levels"); + return blockEntity.levels; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java index f5c2fef95..eaf6cda03 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java @@ -3,6 +3,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.addons.APAddons; import de.srendi.advancedperipherals.common.util.Platform; import de.srendi.advancedperipherals.lib.integrations.IPeripheralIntegration; import de.srendi.advancedperipherals.lib.peripherals.BlockEntityIntegrationPeripheral; @@ -23,7 +24,14 @@ public class IntegrationPeripheralProvider implements IPeripheralProvider { - private static final String[] SUPPORTED_MODS = new String[]{"botania", "create", "mekanism", "powah"}; + private static final String[] SUPPORTED_MODS = new String[]{ + APAddons.BOTANIA_MODID, + APAddons.CREATE_MODID, + APAddons.MEKANISM_MODID, + APAddons.POWAH_MODID, + APAddons.DIMSTORAGE_MODID, + APAddons.VALKYRIEN_SKIES_MODID, + }; private static final PriorityQueue integrations = new PriorityQueue<>(Comparator.comparingInt(IPeripheralIntegration::getPriority)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java index b86b1aa39..5ed3604c4 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java @@ -7,7 +7,8 @@ import java.util.Map; public enum SimpleFreeOperation implements IPeripheralOperation { - CHAT_MESSAGE(100); + CHAT_MESSAGE(1000), + SADDLE_CAPTURE(5000); private final int defaultCooldown; private ForgeConfigSpec.IntValue cooldown; @@ -18,7 +19,7 @@ public enum SimpleFreeOperation implements IPeripheralOperation { @Override public void addToConfig(ForgeConfigSpec.Builder builder) { - cooldown = builder.defineInRange(settingsName() + "Cooldown", defaultCooldown, 1_000, Integer.MAX_VALUE); + cooldown = builder.defineInRange(settingsName() + "Cooldown", defaultCooldown, 100, Integer.MAX_VALUE); } @Override diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java index 90205db17..980c329b9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java @@ -5,16 +5,20 @@ import java.util.HashMap; import java.util.Map; -import java.util.function.Function; +import java.util.function.UnaryOperator; public enum SingleOperation implements IPeripheralOperation { DIG(1000, 1), USE_ON_BLOCK(5000, 1), + UPDATE_BLOCK(500, 1), SUCK(1000, 1), USE_ON_ANIMAL(2500, 10), CAPTURE_ANIMAL(50_000, 100), WARP(1000, DistancePolicy.IGNORED, CountPolicy.MULTIPLY, 1, DistancePolicy.SQRT, CountPolicy.MULTIPLY), - ACCURE_PLACE(1000, DistancePolicy.IGNORED, CountPolicy.MULTIPLY, 1, DistancePolicy.LINEAR, CountPolicy.MULTIPLY); + ACCURE_PLACE(1000, DistancePolicy.IGNORED, CountPolicy.MULTIPLY, 1, DistancePolicy.LINEAR, CountPolicy.MULTIPLY), + PREPARE_PORTAL(3_000, 600), + ACTIVE_PORTAL(60_000, 1), + MOUNT_SHIP(1000, 1); private final int defaultCooldown; private final DistancePolicy distanceCooldownPolicy; @@ -35,7 +39,7 @@ public enum SingleOperation implements IPeripheralOperation d), SQRT(d -> (int) Math.sqrt(d)); - private final Function factorFunction; + private final UnaryOperator factorFunction; - DistancePolicy(Function factorFunction) { + DistancePolicy(UnaryOperator factorFunction) { this.factorFunction = factorFunction; } @@ -90,11 +94,12 @@ public int getFactor(int distance) { } public enum CountPolicy { + IGNORED(c -> 1), MULTIPLY(c -> c); - private final Function factorFunction; + private final UnaryOperator factorFunction; - CountPolicy(Function factorFunction) { + CountPolicy(UnaryOperator factorFunction) { this.factorFunction = factorFunction; } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java index 147b06400..54217cede 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java @@ -9,7 +9,8 @@ public enum SphereOperation implements IPeripheralOperation { SCAN_BLOCKS(2_000, 8, 16, 0.17), - SCAN_ENTITIES(2_000, 8, 16, 0.17); + SCAN_ENTITIES(2_000, 8, 16, 0.17), + SCAN_SHIPS(2_500, 8 * 3, 16 * 10 /* common view distance */, 0.17); private final int defaultCooldown; private final int defaultMaxFreeRadius; @@ -29,7 +30,7 @@ public enum SphereOperation implements IPeripheralOperation, IOwnerAbility> abilities; - public BasePeripheralOwner() { + protected BasePeripheralOwner() { abilities = new HashMap<>(); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java index 2ea0bd6a3..0a593045a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java @@ -1,7 +1,7 @@ package de.srendi.advancedperipherals.common.addons.computercraft.owner; +import dan200.computercraft.api.peripheral.IPeripheral; import de.srendi.advancedperipherals.common.blocks.base.BaseBlock; -import de.srendi.advancedperipherals.common.blocks.blockentities.InventoryManagerEntity; import de.srendi.advancedperipherals.common.util.DataStorageUtil; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralTileEntity; @@ -11,16 +11,16 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.world.Nameable; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.JigsawBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; -import java.util.function.Function; +import org.apache.commons.lang3.NotImplementedException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class BlockEntityPeripheralOwner extends BasePeripheralOwner { @@ -61,7 +61,7 @@ public BlockPos getPos() { @NotNull @Override public Direction getFacing() { - return tileEntity.getBlockState().getValue(JigsawBlock.ORIENTATION).front(); + return getOrientation().front(); } @NotNull @@ -70,11 +70,15 @@ public FrontAndTop getOrientation() { return tileEntity.getBlockState().getValue(BaseBlock.ORIENTATION); } + @Nullable + @Override + public Entity getHoldingEntity() { + return null; + } + @Nullable @Override public Player getOwner() { - if (tileEntity instanceof InventoryManagerEntity inventoryManagerEntity) - return inventoryManagerEntity.getOwnerPlayer(); return null; } @@ -90,8 +94,8 @@ public void markDataStorageDirty() { } @Override - public T1 withPlayer(Function function) { - throw new RuntimeException("Not implemented yet"); + public T1 withPlayer(APFakePlayer.Action function) { + throw new NotImplementedException(); } @Override @@ -102,7 +106,7 @@ public ItemStack getToolInMainHand() { @Override public ItemStack storeItem(ItemStack stored) { // TODO: tricks with capability needed - throw new RuntimeException("Not implemented yet"); + throw new NotImplementedException(); } @Override @@ -124,4 +128,9 @@ public BlockEntityPeripheralOwner attachFuel() { attachAbility(PeripheralOwnerAbility.FUEL, new TileEntityFuelAbility<>(this)); return this; } + + @Override + public U getConnectedPeripheral(Class type) { + throw new NotImplementedException(); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java index 07245d648..80ecdefb0 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java @@ -14,7 +14,7 @@ public abstract class FuelAbility implements IOwnerA protected @NotNull T owner; - public FuelAbility(@NotNull T owner) { + protected FuelAbility(@NotNull T owner) { this.owner = owner; } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java index c99e9442b..fc737aa5a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java @@ -1,19 +1,26 @@ package de.srendi.advancedperipherals.common.addons.computercraft.owner; +import dan200.computercraft.api.peripheral.IPeripheral; +import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.addons.valkyrienskies.ValkyrienSkies; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralOperation; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.OwnableEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import net.minecraft.world.phys.Vec3; import java.util.Collection; -import java.util.function.Function; +import java.util.HashSet; +import java.util.Set; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface IPeripheralOwner { @@ -23,17 +30,47 @@ public interface IPeripheralOwner { @NotNull BlockPos getPos(); + @NotNull + default Vec3 getCenterPos() { + return Vec3.atCenterOf(getPos()); + } + @NotNull Direction getFacing(); @NotNull FrontAndTop getOrientation(); - @Nullable Player getOwner(); + @NotNull + default Vec3 getDirection() { + Vec3 dir = Vec3.atLowerCornerOf(getFacing().getNormal()); + if (!APAddons.vs2Loaded) { + return dir; + } + return ValkyrienSkies.transformToWorldDir(getLevel(), getPos(), dir); + } + + @Nullable Entity getHoldingEntity(); + + @Nullable + default Player getOwner() { + Entity owner = getHoldingEntity(); + Set checked = new HashSet<>(); + while (owner != null && checked.add(owner)) { + if (owner instanceof Player player) { + return (Player) player; + } + if (!(owner instanceof OwnableEntity ownable)) { + break; + } + owner = ownable.getOwner(); + } + return null; + } @NotNull CompoundTag getDataStorage(); void markDataStorageDirty(); - T withPlayer(Function function); + T withPlayer(APFakePlayer.Action function); ItemStack getToolInMainHand(); @@ -64,4 +101,10 @@ default void attachOperation(Collection> operations) { for (IPeripheralOperation> operation : operations) operationAbility.registerOperation(operation); } + + T getConnectedPeripheral(Class type); + + default boolean hasConnectedPeripheral(Class extends IPeripheral> type) { + return getConnectedPeripheral(type) != null; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/InventoryManagerOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/InventoryManagerOwner.java new file mode 100644 index 000000000..c9bc48605 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/InventoryManagerOwner.java @@ -0,0 +1,17 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.owner; + +import de.srendi.advancedperipherals.common.blocks.blockentities.InventoryManagerEntity; +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.Nullable; + +public class InventoryManagerOwner extends BlockEntityPeripheralOwner { + public InventoryManagerOwner(InventoryManagerEntity tile) { + super(tile); + } + + @Nullable + @Override + public Player getOwner() { + return tileEntity.getOwnerPlayer(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java index 4f5627f5e..fefa8a5be 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java @@ -5,6 +5,6 @@ public class PeripheralOwnerAbility { public static final PeripheralOwnerAbility> FUEL = new PeripheralOwnerAbility<>(); public static final PeripheralOwnerAbility OPERATION = new PeripheralOwnerAbility<>(); - public PeripheralOwnerAbility() { + private PeripheralOwnerAbility() { } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java index 5cd8e588c..21dc65ae6 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java @@ -1,30 +1,35 @@ package de.srendi.advancedperipherals.common.addons.computercraft.owner; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import de.srendi.advancedperipherals.common.configuration.APConfig; import de.srendi.advancedperipherals.common.util.DataStorageUtil; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; +import de.srendi.advancedperipherals.lib.peripherals.IBasePeripheral; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.apache.commons.lang3.NotImplementedException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.function.Function; - public class PocketPeripheralOwner extends BasePeripheralOwner { private final IPocketAccess pocket; + private final IPocketUpgrade upgrade; - public PocketPeripheralOwner(IPocketAccess pocket) { + public PocketPeripheralOwner(IPocketAccess pocket, IPocketUpgrade upgrade) { super(); this.pocket = pocket; - if(APConfig.PERIPHERALS_CONFIG.disablePocketFuelConsumption.get()) + this.upgrade = upgrade; + if (APConfig.PERIPHERALS_CONFIG.disablePocketFuelConsumption.get()) { attachAbility(PeripheralOwnerAbility.FUEL, new InfinitePocketFuelAbility(this)); + } } @Nullable @@ -37,48 +42,58 @@ public String getCustomName() { @Override public Level getLevel() { Entity owner = pocket.getEntity(); - if (owner == null) return null; - return owner.getCommandSenderWorld(); + return owner == null ? null : owner.getCommandSenderWorld(); } @NotNull @Override public BlockPos getPos() { Entity owner = pocket.getEntity(); - if (owner == null) return new BlockPos(0, 0, 0); - return owner.blockPosition(); + return owner == null ? BlockPos.ZERO : new BlockPos(owner.getEyePosition()); } @NotNull @Override - public Direction getFacing() { + public Vec3 getCenterPos() { Entity owner = pocket.getEntity(); - if (owner == null) return Direction.NORTH; - return owner.getDirection(); + return owner == null ? Vec3.ZERO : owner.getEyePosition(); } + @NotNull + @Override + public Direction getFacing() { + Vec3 dir = getDirection(); + return Direction.getNearest(dir.x, dir.y, dir.z); + } - /** - * Not used for pockets - */ @NotNull @Override public FrontAndTop getOrientation() { - return FrontAndTop.NORTH_UP; + Entity owner = pocket.getEntity(); + if (owner == null) { + return FrontAndTop.NORTH_UP; + } + Vec3 up = owner.getUpVector(1.0f); + return FrontAndTop.fromFrontAndTop(getFacing(), Direction.getNearest(up.x, up.y, up.z)); } - @Nullable + @NotNull @Override - public Player getOwner() { + public Vec3 getDirection() { Entity owner = pocket.getEntity(); - if (owner instanceof Player player) return player; - return null; + return owner == null ? /* North */ new Vec3(0, 0, -1) : owner.getLookAngle(); + } + + @Nullable + @Override + public Entity getHoldingEntity() { + return pocket.getEntity(); } @NotNull @Override public CompoundTag getDataStorage() { - return DataStorageUtil.getDataStorage(pocket); + return DataStorageUtil.getDataStorage(pocket, upgrade); } @Override @@ -87,8 +102,8 @@ public void markDataStorageDirty() { } @Override - public T withPlayer(Function function) { - throw new RuntimeException("Not implemented yet"); + public T withPlayer(APFakePlayer.Action function) { + throw new NotImplementedException(); } @Override @@ -98,13 +113,12 @@ public ItemStack getToolInMainHand() { @Override public ItemStack storeItem(ItemStack stored) { - // Tricks with inventory needed - throw new RuntimeException("Not implemented yet"); + throw new NotImplementedException(); } @Override public void destroyUpgrade() { - throw new RuntimeException("Not implemented yet"); + throw new NotImplementedException(); } @Override @@ -116,4 +130,18 @@ public boolean isMovementPossible(@NotNull Level level, @NotNull BlockPos pos) { public boolean move(@NotNull Level level, @NotNull BlockPos pos) { return false; } + + @Override + public T getConnectedPeripheral(Class type) { + IPeripheral foundPeripheral = pocket.getUpgrades().values().stream() + .filter(peripheral -> { + if (peripheral == null || type.isInstance(peripheral)) { + return false; + } + return peripheral instanceof IBasePeripheral basePeripheral ? basePeripheral.isEnabled() : true; + }) + .findFirst() + .orElse(null); + return (T) foundPeripheral; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java index c2709e02d..e8365fcc7 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java @@ -2,6 +2,7 @@ import com.mojang.authlib.GameProfile; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.TurtlePermissions; @@ -9,17 +10,20 @@ import de.srendi.advancedperipherals.common.util.DataStorageUtil; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; import de.srendi.advancedperipherals.common.util.fakeplayer.FakePlayerProviderTurtle; +import de.srendi.advancedperipherals.lib.peripherals.IBasePeripheral; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraftforge.items.wrapper.InvWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.function.Function; +import java.util.stream.Stream; public class TurtlePeripheralOwner extends BasePeripheralOwner { public final ITurtleAccess turtle; @@ -61,6 +65,12 @@ public FrontAndTop getOrientation() { return FrontAndTop.fromFrontAndTop(getFacing(), Direction.UP); } + @Nullable + @Override + public Entity getHoldingEntity() { + return null; + } + @Nullable @Override public Player getOwner() { @@ -81,7 +91,7 @@ public void markDataStorageDirty() { } @Override - public T withPlayer(Function function) { + public T withPlayer(APFakePlayer.Action function) { return FakePlayerProviderTurtle.withPlayer(turtle, function); } @@ -92,7 +102,7 @@ public ItemStack getToolInMainHand() { @Override public ItemStack storeItem(ItemStack stored) { - return InventoryUtil.storeItems(stored, turtle.getItemHandler(), turtle.getSelectedSlot()); + return InventoryUtil.storeItems(stored, new InvWrapper(turtle.getInventory()), turtle.getSelectedSlot()); } @Override @@ -131,4 +141,19 @@ public TurtlePeripheralOwner attachFuel(int maxFuelConsumptionLevel) { attachAbility(PeripheralOwnerAbility.FUEL, new TurtleFuelAbility(this, maxFuelConsumptionLevel)); return this; } + + @Override + public T getConnectedPeripheral(Class type) { + IPeripheral foundPeripheral = Stream.of(TurtleSide.values()) + .map(side -> turtle.getPeripheral(side)) + .filter(peripheral -> { + if (peripheral == null || type.isInstance(peripheral)) { + return false; + } + return peripheral instanceof IBasePeripheral basePeripheral ? basePeripheral.isEnabled() : true; + }) + .findFirst() + .orElse(null); + return (T) foundPeripheral; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BaseDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BaseDetectorPeripheral.java new file mode 100644 index 000000000..843c5554f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BaseDetectorPeripheral.java @@ -0,0 +1,42 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import dan200.computercraft.api.lua.LuaFunction; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; +import de.srendi.advancedperipherals.common.blocks.base.BaseDetectorEntity; +import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; + +public abstract class BaseDetectorPeripheral extends BasePeripheral> { + protected BaseDetectorPeripheral(String type, E tileEntity) { + super(type, new BlockEntityPeripheralOwner<>(tileEntity)); + } + + @LuaFunction + public final long getMaxTransferRate() { + return owner.tileEntity.getMaxTransferRate(); + } + + @LuaFunction + public final long getTransferRateLimit() { + return owner.tileEntity.getTransferRateLimit(); + } + + @LuaFunction + public final void setTransferRateLimit(long transferRate) { + owner.tileEntity.setTransferRateLimit(transferRate); + } + + @LuaFunction + public final long getTransferRate() { + return owner.tileEntity.getTransferRate(); + } + + @LuaFunction + public final String getLastTransferedId() { + return owner.tileEntity.getLastTransferedId(); + } + + @LuaFunction + public final String getReadyTransferId() { + return owner.tileEntity.getReadyTransferId(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java index 086fa4fe9..ce78b5077 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java @@ -18,7 +18,7 @@ public class BlockReaderPeripheral extends BasePeripheral> { - public static final String PERIPHERAL_TYPE = "blockReader"; + public static final String PERIPHERAL_TYPE = "block_reader"; public BlockReaderPeripheral(BlockReaderEntity tileEntity) { super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java index 91f82b2e2..920f64f13 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java @@ -7,6 +7,7 @@ import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import de.srendi.advancedperipherals.AdvancedPeripherals; @@ -17,16 +18,16 @@ import de.srendi.advancedperipherals.common.blocks.base.PeripheralBlockEntity; import de.srendi.advancedperipherals.common.configuration.APConfig; import de.srendi.advancedperipherals.common.events.Events; +import de.srendi.advancedperipherals.common.network.APNetworking; +import de.srendi.advancedperipherals.common.network.toclient.ToastToClientPacket; import de.srendi.advancedperipherals.common.util.CoordUtil; import de.srendi.advancedperipherals.common.util.StringUtil; import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralFunction; -import de.srendi.advancedperipherals.network.APNetworking; -import de.srendi.advancedperipherals.network.toclient.ToastToClientPacket; import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentContents; -import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; @@ -35,7 +36,6 @@ import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; import net.minecraftforge.server.ServerLifecycleHooks; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,12 +44,12 @@ import java.util.UUID; import java.util.function.Predicate; -import static de.srendi.advancedperipherals.common.commands.APCommands.ROOT_SAFE_EXEC_LITERAL; import static de.srendi.advancedperipherals.common.addons.computercraft.operations.SimpleFreeOperation.CHAT_MESSAGE; +import static de.srendi.advancedperipherals.common.commands.APCommands.ROOT_SAFE_EXEC_LITERAL; public class ChatBoxPeripheral extends BasePeripheral { - public static final String PERIPHERAL_TYPE = "chatBox"; + public static final String PERIPHERAL_TYPE = "chat_box"; private long lastConsumedMessage; @@ -67,8 +67,8 @@ public ChatBoxPeripheral(ITurtleAccess turtle, TurtleSide side) { this(new TurtlePeripheralOwner(turtle, side)); } - public ChatBoxPeripheral(IPocketAccess pocket) { - this(new PocketPeripheralOwner(pocket)); + public ChatBoxPeripheral(IPocketAccess pocket, IPocketUpgrade upgrade) { + this(new PocketPeripheralOwner(pocket, upgrade)); } @Override @@ -251,7 +251,7 @@ public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) th if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.getLevel().dimension() != dimension) { continue; } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } } @@ -294,7 +294,7 @@ public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaE if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.getLevel().dimension() != dimension) { continue; } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } } @@ -341,7 +341,7 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } return MethodResult.of(true); @@ -399,7 +399,7 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { ToastToClientPacket packet = new ToastToClientPacket(titleComponent, preparedMessage); APNetworking.sendTo(packet, player); } @@ -438,7 +438,7 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage, false); } return MethodResult.of(true); @@ -477,7 +477,7 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { ToastToClientPacket packet = new ToastToClientPacket(Component.literal(title), preparedMessage); APNetworking.sendTo(packet, player); } @@ -485,6 +485,7 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw }); } + @Override public void update() { lastConsumedMessage = Events.traverseChatMessages(lastConsumedMessage, message -> { for (IComputerAccess computer : getConnectedComputers()) { diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java index 94829b12f..428574bcb 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java @@ -1,5 +1,6 @@ package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; @@ -44,6 +45,11 @@ public boolean isEnabled() { return APConfig.PERIPHERALS_CONFIG.enableChunkyTurtle.get(); } + @LuaFunction + public int getRadius() { + return ChunkManager.getMaxLoadRadius(); + } + public void updateChunkState() { // TODO: should find someway to update after turtle moved or while moving, but not every tick ServerLevel level = (ServerLevel) getLevel(); @@ -72,7 +78,7 @@ protected void setLoadedChunk(@Nullable ChunkPos newChunk, ChunkManager manager, } @Override - public void attach(IComputerAccess computer) { + public void attach(@NotNull IComputerAccess computer) { super.attach(computer); ServerLevel level = (ServerLevel) owner.getLevel(); ChunkManager manager = ChunkManager.get(Objects.requireNonNull(level)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java index 5a689c538..8b5a9a1e9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java @@ -18,6 +18,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import de.srendi.advancedperipherals.AdvancedPeripherals; import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; @@ -32,12 +33,17 @@ import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.ModList; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class ColonyPeripheral extends BasePeripheral { - public static final String PERIPHERAL_TYPE = "colonyIntegrator"; + public static final String PERIPHERAL_TYPE = "colony_integrator"; protected boolean hasPermission = true; @@ -45,8 +51,8 @@ public ColonyPeripheral(PeripheralBlockEntity> tileEntity) { super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); } - public ColonyPeripheral(IPocketAccess access) { - super(PERIPHERAL_TYPE, new PocketPeripheralOwner(access)); + public ColonyPeripheral(IPocketAccess access, IPocketUpgrade upgrade) { + super(PERIPHERAL_TYPE, new PocketPeripheralOwner(access, upgrade)); } @Override @@ -272,7 +278,7 @@ public final Object getRequests() throws LuaException { map.put("state", request.getState().toString()); map.put("count", deliverableRequest.getCount()); map.put("minCount", deliverableRequest.getMinimumCount()); - map.put("items", request.getDisplayStacks().stream().map(LuaConverter::stackToObject).collect(Collectors.toList())); + map.put("items", request.getDisplayStacks().stream().map(LuaConverter::itemStackToObject).collect(Collectors.toList())); map.put("target", request.getRequester().getRequesterDisplayName(requestManager, request).getString()); result.add(map); }); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DisabledPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DisabledPeripheral.java new file mode 100644 index 000000000..0fb89318f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DisabledPeripheral.java @@ -0,0 +1,75 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.IDynamicLuaObject; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; +import dan200.computercraft.api.peripheral.IPeripheral; + +import java.lang.reflect.Method; +import java.util.Objects; +import java.util.stream.Stream; + +public class DisabledPeripheral implements IDynamicPeripheral { + private static final MethodResult TRUE_RESULT = MethodResult.of(true); + + private final IPeripheral basePeripheral; + private final String[] methods; + + public DisabledPeripheral(IPeripheral basePeripheral) { + this.basePeripheral = basePeripheral; + Stream.Builder builder = Stream.builder(); + builder.add("peripheralDisabled"); + for (Method method : basePeripheral.getClass().getMethods()) { + LuaFunction annotation = method.getAnnotation(LuaFunction.class); + if (annotation == null) { + continue; + } + String[] names = annotation.value(); + if (names.length == 0) { + builder.add(method.getName()); + } else { + for (String name : names) { + builder.add(name); + } + } + } + Stream methodStream = builder.build(); + if (basePeripheral instanceof IDynamicPeripheral dynPeripheral) { + methodStream = Stream.concat(methodStream, Stream.of(dynPeripheral.getMethodNames())); + } + this.methods = methodStream.toArray(String[]::new); + } + + @Override + public String getType() { + return this.basePeripheral.getType(); + } + + @Override + public Object getTarget() { + return this.basePeripheral.getTarget(); + } + + @Override + public boolean equals(IPeripheral other) { + return other instanceof DisabledPeripheral disabled && this.basePeripheral.equals(disabled.basePeripheral); + } + + @Override + public String[] getMethodNames() { + return this.methods; + } + + @Override + public MethodResult callMethod(IComputerAccess computer, ILuaContext context, int method, IArguments arguments) throws LuaException { + if (method == 0) { + return TRUE_RESULT; + } + throw new LuaException("This peripheral is disabled, please contact server administrator if you want to use it"); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java new file mode 100644 index 000000000..aeba25afc --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java @@ -0,0 +1,331 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.PocketPeripheralOwner; +import de.srendi.advancedperipherals.common.blocks.blockentities.DistanceDetectorEntity; +import de.srendi.advancedperipherals.common.configuration.APConfig; +import de.srendi.advancedperipherals.common.util.HitResultUtil; +import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +public class DistanceDetectorPeripheral extends BasePeripheral { + + public static final String PERIPHERAL_TYPE = "distance_detector"; + + private final AtomicBoolean isDirty = new AtomicBoolean(false); + private final DistanceDetectorEntity tileEntity; + private final AtomicInteger maxRange; + private volatile float currentDistance; + private final AtomicBoolean showLaser; + private volatile boolean calculatePeriodically; + private volatile boolean ignoreTransparent; + private final AtomicReference detectionType; + + public DistanceDetectorPeripheral(DistanceDetectorEntity tileEntity) { + super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); + this.tileEntity = tileEntity; + this.maxRange = new AtomicInteger(Float.floatToRawIntBits(this.tileEntity.getMaxRange())); + this.currentDistance = this.tileEntity.getCurrentDistance(); + this.showLaser = new AtomicBoolean(this.tileEntity.getShowLaser()); + this.calculatePeriodically = this.tileEntity.getCalculatePeriodically(); + this.ignoreTransparent = this.tileEntity.getIgnoreTransparent(); + this.detectionType = new AtomicReference<>(this.tileEntity.getDetectionType()); + } + + protected DistanceDetectorPeripheral(IPeripheralOwner owner) { + super(PERIPHERAL_TYPE, owner); + this.tileEntity = null; + CompoundTag data = this.owner.getDataStorage(); + this.maxRange = new AtomicInteger(Float.floatToRawIntBits(data.contains("maxRange") ? data.getFloat("maxRange") : this.getConfiguredMaxRange())); + this.currentDistance = data.contains("currentDistance") ? data.getFloat("currentDistance") : -1; + this.showLaser = new AtomicBoolean(data.contains("showLaser") ? data.getBoolean("showLaser") : true); + this.calculatePeriodically = data.contains("calculatePeriodically") ? data.getBoolean("calculatePeriodically") : false; + this.ignoreTransparent = data.contains("ignoreTransparent") ? data.getBoolean("ignoreTransparent") : true; + this.detectionType = new AtomicReference<>(data.contains("detectionType") ? DetectionType.values()[data.getByte("detectionType")] : DetectionType.BOTH); + } + + public DistanceDetectorPeripheral(IPocketAccess pocket, IPocketUpgrade upgrade) { + this(new PocketPeripheralOwner(pocket, upgrade)); + } + + @Override + public boolean isEnabled() { + return APConfig.PERIPHERALS_CONFIG.enableDistanceDetector.get(); + } + + public float getConfiguredMaxRange() { + return APConfig.PERIPHERALS_CONFIG.distanceDetectorRange.get().floatValue(); + } + + public int getUpdateRate() { + return APConfig.PERIPHERALS_CONFIG.distanceDetectorUpdateRate.get(); + } + + public float getMaxRange() { + return Float.intBitsToFloat(this.maxRange.get()); + } + + public void setMaxRange(float maxRange) { + maxRange = Math.min(Math.max(maxRange, 0), this.getConfiguredMaxRange()); + int maxRangeBits = Float.floatToRawIntBits(maxRange); + if (this.maxRange.getAndSet(maxRangeBits) == maxRange) { + return; + } + if (this.tileEntity != null) { + this.tileEntity.setMaxRange(maxRange); + this.tileEntity.sendUpdate(); + } + this.isDirty.set(true); + } + + public float getCurrentDistance() { + return this.currentDistance; + } + + public void setCurrentDistance(float currentDistance) { + this.currentDistance = currentDistance; + if (this.tileEntity != null) { + this.tileEntity.setCurrentDistance(currentDistance); + this.tileEntity.sendUpdate(); + } + this.isDirty.set(true); + } + + public boolean getCalculatePeriodically() { + return this.calculatePeriodically; + } + + public void setCalculatePeriodically(boolean calculatePeriodically) { + this.calculatePeriodically = calculatePeriodically; + if (this.tileEntity != null) { + this.tileEntity.setCalculatePeriodically(calculatePeriodically); + } + this.isDirty.set(true); + } + + public boolean getShowLaser() { + return this.showLaser.get(); + } + + public void setShowLaser(boolean showLaser) { + if (this.showLaser.getAndSet(showLaser) == showLaser) { + return; + } + if (this.tileEntity != null) { + this.tileEntity.setShowLaser(showLaser); + this.tileEntity.sendUpdate(); + } + this.isDirty.set(true); + } + + public boolean getIgnoreTransparent() { + return this.ignoreTransparent; + } + + public void setIgnoreTransparent(boolean ignoreTransparent) { + this.ignoreTransparent = ignoreTransparent; + if (this.tileEntity != null) { + this.tileEntity.setIgnoreTransparent(ignoreTransparent); + } + this.isDirty.set(true); + } + + public DetectionType getDetectionType() { + return this.detectionType.get(); + } + + public void setDetectionType(DetectionType detectionType) { + if (this.detectionType.getAndSet(detectionType) == detectionType) { + return; + } + if (this.tileEntity != null) { + this.tileEntity.setDetectionType(detectionType); + } + this.isDirty.set(true); + } + + @LuaFunction + public final void setLaserVisibility(boolean laser) { + this.setShowLaser(laser); + } + + @LuaFunction + public final boolean getLaserVisibility() { + return this.getShowLaser(); + } + + @LuaFunction(value = "setIgnoreTransparency") + public final void setIgnoreTransparencyLua(boolean enable) { + this.setIgnoreTransparent(enable); + } + + @LuaFunction + public final boolean ignoresTransparency() { + return this.getIgnoreTransparent(); + } + + @LuaFunction + public final void setDetectionMode(IArguments args) throws LuaException { + Object mode = args.get(0); + if (mode == null) { + throw new LuaException("arg #1 must provide a mode name or an index between [0, 2]"); + } + DetectionType detectionType; + if (mode instanceof Number modeInd) { + int index = Math.min(Math.max(modeInd.intValue(), 0), 2); + detectionType = DetectionType.values()[index]; + } else if (mode instanceof String modeStr) { + detectionType = switch (modeStr.toUpperCase()) { + case "BLOCK" -> DetectionType.BLOCK; + case "ENTITY" -> DetectionType.ENTITY; + case "BOTH" -> DetectionType.BOTH; + default -> throw new LuaException("Unknown detection mode '" + mode + "'"); + }; + } else { + throw new LuaException("arg #1 must be a string or a number"); + } + this.setDetectionType(detectionType); + } + + @LuaFunction + public final boolean detectsEntities() { + return this.getDetectionType().detectEntity(); + } + + @LuaFunction + public final boolean detectsBlocks() { + return this.getDetectionType().detectBlock(); + } + + @LuaFunction + public final String getDetectionMode() { + return this.getDetectionType().toString(); + } + + @LuaFunction + public final double getDistance() { + return this.getCurrentDistance(); + } + + @LuaFunction(mainThread = true) + public final double calculateDistance() { + return this.calculateAndUpdateDistance(); + } + + @LuaFunction + public final boolean shouldCalculatePeriodically() { + return this.getCalculatePeriodically(); + } + + @LuaFunction(value = "setCalculatePeriodically") + public final void setCalculatePeriodicallyLua(boolean shouldCalculatePeriodically) { + this.setCalculatePeriodically(shouldCalculatePeriodically); + } + + @LuaFunction(value = "setMaxRange") + public final void setMaxRangeLua(double maxDistance) { + this.setMaxRange((float) maxDistance); + } + + @LuaFunction(value = "getMaxRange") + public final double getMaxRangeLua() { + return this.getMaxRange(); + } + + protected double calculateDistanceImpl() { + final double maxRange = this.getMaxRange(); + Vec3 direction = this.owner.getDirection(); + Vec3 center = this.getPhysicsPos(); + Vec3 from = center; + Vec3 to = from.add(direction.scale(maxRange)); + + HitResult result = this.getHitResult(from, to); + if (result.getType() == HitResult.Type.MISS) { + return -1; + } + double distance = result.getLocation().distanceTo(center); + if (this.tileEntity != null) { + distance -= 0.5; + } + return distance; + } + + /** + * calculateAndUpdateDistance should only invokes from server main thread + */ + public double calculateAndUpdateDistance() { + double distance = this.calculateDistanceImpl(); + this.setCurrentDistance((float) distance); + return distance; + } + + @Override + public void update() { + if (this.getCalculatePeriodically() && this.getLevel().getGameTime() % this.getUpdateRate() == 0) { + // We calculate the distance every 2 ticks, so we do not have to run the getDistance function of the peripheral + // on the main thread which prevents the 1 tick yield time of the function. + // The calculateDistance function is not thread safe, so we have to run it on the main thread. + // It should be okay to run that function every 2 ticks, calculating it does not take too much time. + this.calculateAndUpdateDistance(); + } + + if (this.isDirty.getAndSet(false)) { + if (this.tileEntity == null) { + CompoundTag data = this.owner.getDataStorage(); + data.putFloat("maxRange", this.getMaxRange()); + data.putFloat("currentDistance", this.getCurrentDistance()); + data.putBoolean("showLaser", this.getShowLaser()); + data.putBoolean("calculatePeriodically", this.getCalculatePeriodically()); + data.putBoolean("ignoreTransparent", this.getIgnoreTransparent()); + data.putByte("detectionType", (byte) this.getDetectionType().ordinal()); + } + this.owner.markDataStorageDirty(); + } + } + + protected HitResult getHitResult(Vec3 from, Vec3 to) { + Level level = this.getLevel(); + ClipContext.ShapeGetter shapeGetter = this.ignoreTransparent ? HitResultUtil.IgnoreNoOccludedContext.INSTANCE : ClipContext.Block.COLLIDER; + return switch (this.getDetectionType()) { + case ENTITY -> HitResultUtil.getEntityHitResult(from, to, level, this.owner.getHoldingEntity()); + case BLOCK -> HitResultUtil.getBlockHitResult(from, to, level, shapeGetter, this.getPos()); + case BOTH -> HitResultUtil.getHitResult(from, to, level, shapeGetter, this.owner); + }; + } + + public enum DetectionType { + BLOCK(true, false), + ENTITY(false, true), + BOTH(true, true); + + private final boolean block, entity; + + DetectionType(boolean block, boolean entity) { + this.block = block; + this.entity = entity; + } + + public boolean detectBlock() { + return this.block; + } + + public boolean detectEntity() { + return this.entity; + } + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java index 8b0e016f2..5aff47acd 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java @@ -1,37 +1,18 @@ package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; -import dan200.computercraft.api.lua.LuaFunction; -import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; import de.srendi.advancedperipherals.common.blocks.blockentities.EnergyDetectorEntity; import de.srendi.advancedperipherals.common.configuration.APConfig; -import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; -public class EnergyDetectorPeripheral extends BasePeripheral> { +public class EnergyDetectorPeripheral extends BaseDetectorPeripheral { - public static final String PERIPHERAL_TYPE = "energyDetector"; + public static final String TYPE = "energy_detector"; public EnergyDetectorPeripheral(EnergyDetectorEntity tileEntity) { - super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); + super(TYPE, tileEntity); } @Override public boolean isEnabled() { return APConfig.PERIPHERALS_CONFIG.enableEnergyDetector.get(); } - - @LuaFunction(mainThread = true) - public final int getTransferRateLimit() { - return owner.tileEntity.storageProxy.getMaxTransferRate(); - } - - @LuaFunction(mainThread = true) - public final void setTransferRateLimit(long transferRate) { - transferRate = Math.max(0, Math.min(APConfig.PERIPHERALS_CONFIG.energyDetectorMaxFlow.get(), transferRate)); - owner.tileEntity.storageProxy.setMaxTransferRate((int) transferRate); - } - - @LuaFunction(mainThread = true) - public final int getTransferRate() { - return owner.tileEntity.transferRate; - } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java index f37aa156e..62db06f6a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java @@ -4,10 +4,11 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; + import de.srendi.advancedperipherals.common.addons.computercraft.operations.SphereOperationContext; import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; @@ -18,13 +19,12 @@ import de.srendi.advancedperipherals.common.util.LuaConverter; import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralPlugin; -import net.minecraft.core.BlockPos; + import net.minecraft.resources.ResourceKey; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LightLayer; @@ -32,28 +32,35 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.SleepingTimeCheckEvent; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.server.ServerLifecycleHooks; -import org.jetbrains.annotations.NotNull; - -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.function.Function; +import org.jetbrains.annotations.NotNull; import static de.srendi.advancedperipherals.common.addons.computercraft.operations.SphereOperation.SCAN_ENTITIES; public class EnvironmentDetectorPeripheral extends BasePeripheral { - public static final String PERIPHERAL_TYPE = "environmentDetector"; - private static final List> PERIPHERAL_PLUGINS = new LinkedList<>(); + public static final String PERIPHERAL_TYPE = "environment_detector"; + private static final List> PERIPHERAL_PLUGINS = new ArrayList<>(); protected EnvironmentDetectorPeripheral(IPeripheralOwner owner) { super(PERIPHERAL_TYPE, owner); owner.attachOperation(SCAN_ENTITIES); - for (Function plugin : PERIPHERAL_PLUGINS) + for (Function plugin : PERIPHERAL_PLUGINS) { addPlugin(plugin.apply(owner)); + } } public EnvironmentDetectorPeripheral(PeripheralBlockEntity> tileEntity) { @@ -64,8 +71,8 @@ public EnvironmentDetectorPeripheral(ITurtleAccess turtle, TurtleSide side) { this(new TurtlePeripheralOwner(turtle, side).attachFuel(1)); } - public EnvironmentDetectorPeripheral(IPocketAccess pocket) { - this(new PocketPeripheralOwner(pocket)); + public EnvironmentDetectorPeripheral(IPocketAccess pocket, IPocketUpgrade upgrade) { + this(new PocketPeripheralOwner(pocket, upgrade)); } private static int estimateCost(int radius) { @@ -89,24 +96,24 @@ public boolean isEnabled() { @LuaFunction(mainThread = true) public final String getBiome() { - Optional
+ * We just create a terminal which is used to forward all the key presses and mouse clicks but we don't render it. + */ +public class KeyboardScreen extends Screen implements MenuAccess { + + protected final KeyboardContainer keyboardContainer; + protected final InputHandler input; + private final Terminal terminalData; + private WidgetTerminal terminal; + private MouseState mouseState = MouseState.RELEASED; + private boolean captureMouse; + private boolean regrabingMouse; + private final byte[] lastPosLock = new byte[0]; + private double lastX = 0; + private double lastY = 0; + private double lastScroll = 0; + + public KeyboardScreen(KeyboardContainer keyboardContainer, Inventory inv, Component titleIn) { + super(titleIn); + this.keyboardContainer = keyboardContainer; + this.input = new ClientInputHandler(keyboardContainer); + this.terminalData = new Terminal(0, 0, false); + } + + @Override + public KeyboardContainer getMenu() { + return this.keyboardContainer; + } + + @Override + public void render(@NotNull PoseStack poseStack, int x, int y, float partialTicks) { + super.render(poseStack, x, y, partialTicks); + + Minecraft minecraft = Minecraft.getInstance(); + float scale = 2f; + int screenWidth = minecraft.getWindow().getGuiScaledWidth(); + // Make the text a bit smaller on small screens + if (screenWidth <= 1080) + scale = 1f; + + poseStack.scale(scale, scale, 1); + Component text = Component.translatable("text.advancedperipherals.keyboard.close"); + float textX = (screenWidth / 2f - minecraft.font.width(text) * scale / 2f) / scale; + minecraft.font.drawShadow(poseStack, text, textX, 1, 0xFFFFFF); + } + + @Override + protected void init() { + if (this.isCapturingMouse()) { + this.grabMouse(); + } else { + this.grabMouseWithControl(); + } + this.passEvents = true; + KeyMapping.releaseAll(); + + super.init(); + this.minecraft.keyboardHandler.setSendRepeatsToGui(true); + + this.terminal = addWidget(new WidgetTerminal(terminalData, new ClientInputHandler(this.keyboardContainer), 0, 0)); + this.terminal.visible = false; + this.terminal.active = false; + setFocused(this.terminal); + } + + @Override + public final void removed() { + if (this.regrabingMouse) { + return; + } + super.removed(); + if (this.minecraft.player != null) { + this.keyboardContainer.removed(this.minecraft.player); + } + this.minecraft.keyboardHandler.setSendRepeatsToGui(false); + } + + @Override + public void onClose() { + // Don't allow closing using standard keys like E. Closing using ESCAPE is still possible due to the keyPressed method + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public void mouseMoved(double x, double y) { + if (this.mouseState != MouseState.CAPTURE) { + return; + } + ClientWorker.put("mouse_move", () -> { + synchronized (this.lastPosLock) { + double dx = x - this.lastX; + double dy = y - this.lastY; + APNetworking.sendToServer(new KeyboardMouseMovePacket(dx, dy)); + this.lastX = x; + this.lastY = y; + } + }); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + if (this.mouseState != MouseState.CAPTURE) { + return false; + } + APNetworking.sendToServer(new KeyboardMouseClickPacket(button, false)); + return true; + } + + @Override + public boolean mouseReleased(double x, double y, int button) { + if (this.mouseState != MouseState.CAPTURE) { + return false; + } + APNetworking.sendToServer(new KeyboardMouseClickPacket(button, true)); + return true; + } + + @Override + public boolean mouseScrolled(double x, double y, double direction) { + this.lastScroll += direction; + int scrolled = (int) this.lastScroll; + if (scrolled == 0) { + return true; + } + if (this.mouseState == MouseState.CAPTURE) { + ClientWorker.put("mouse_scroll", () -> { + if (this.mouseState != MouseState.CAPTURE) { + return; + } + this.lastScroll -= scrolled; + APNetworking.sendToServer(new KeyboardMouseScrollPacket(scrolled)); + }); + } else { + this.lastScroll -= scrolled; + minecraft.player.getInventory().swapPaint(scrolled); + } + return true; + } + + @Override + public final boolean keyPressed(int key, int scancode, int modifiers) { + if (key == GLFW.GLFW_KEY_ESCAPE) { + if (this.minecraft.player != null) { + this.minecraft.player.closeContainer(); + } else { + super.onClose(); + } + return true; + } + // Forward the tab key to the terminal, rather than moving between controls. + if (key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) { + return getFocused().keyPressed(key, scancode, modifiers); + } + + return super.keyPressed(key, scancode, modifiers); + } + + public boolean isCapturingMouse() { + return this.captureMouse; + } + + public void setCaptureMouse(boolean enable) { + this.captureMouse = enable; + if (enable) { + this.grabMouse(); + } else { + this.grabMouseWithControl(); + } + } + + private void grabMouseWithControl() { + if (this.mouseState == MouseState.NORMAL) { + return; + } + this.releaseMouse(); + this.regrabingMouse = true; + this.minecraft.mouseHandler.grabMouse(); + this.regrabingMouse = false; + this.minecraft.screen = this; + this.mouseState = MouseState.NORMAL; + } + + private void grabMouse() { + if (this.minecraft.mouseHandler.isMouseGrabbed()) { + this.minecraft.mouseHandler.releaseMouse(); + } + Window window = this.minecraft.getWindow(); + synchronized (this.lastPosLock) { + this.lastX = window.getScreenWidth() / 2; + this.lastY = window.getScreenHeight() / 2; + InputConstants.grabOrReleaseMouse(window.getWindow(), InputConstants.CURSOR_DISABLED, this.lastX, this.lastY); + } + this.mouseState = MouseState.CAPTURE; + } + + private void releaseMouse() { + if (this.mouseState == MouseState.RELEASED) { + return; + } + if (this.minecraft.mouseHandler.isMouseGrabbed()) { + this.minecraft.mouseHandler.releaseMouse(); + return; + } + Window window = this.minecraft.getWindow(); + synchronized (this.lastPosLock) { + this.lastX = window.getScreenWidth() / 2; + this.lastY = window.getScreenHeight() / 2; + InputConstants.grabOrReleaseMouse(window.getWindow(), InputConstants.CURSOR_NORMAL, this.lastX, this.lastY); + } + this.mouseState = MouseState.RELEASED; + } + + private enum MouseState { + RELEASED, NORMAL, CAPTURE + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/screens/SaddleTurtleOverlay.java b/src/main/java/de/srendi/advancedperipherals/client/screens/SaddleTurtleOverlay.java new file mode 100644 index 000000000..60bb4cccf --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/SaddleTurtleOverlay.java @@ -0,0 +1,156 @@ +package de.srendi.advancedperipherals.client.screens; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.entity.TurtleSeatEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.util.FormattedCharSequence; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.client.gui.overlay.IGuiOverlay; + +public class SaddleTurtleOverlay extends GuiComponent implements IGuiOverlay { + public static final String ID = "saddle_turtle_overlay"; + + private static final long ACTIVE_TIMEOUT = 5000; + + private ForgeGui gui; + private int screenWidth = 0; + private int screenHeight = 0; + + private int fuelLevel = 0; + private int fuelLimit = 0; + private int barColor = 0; + private long lastActived = 0; + + public SaddleTurtleOverlay() {} + + protected Font getFont() { + return this.gui.getMinecraft().font; + } + + protected int textWidth(String text) { + return getFont().width(text); + } + + protected int textWidth(FormattedText text) { + return getFont().width(text); + } + + protected int textWidth(FormattedCharSequence text) { + return getFont().width(text); + } + + public boolean isPlayerControllingTurtle() { + LocalPlayer player = Minecraft.getInstance().player; + return player != null && player.getVehicle() instanceof TurtleSeatEntity; + } + + public boolean isPlayerMountedOnTurtle() { + LocalPlayer player = Minecraft.getInstance().player; + return player != null && player.getRootVehicle() instanceof TurtleSeatEntity; + } + + public boolean shouldRenderFuelBar() { + if (this.lastActived == 0) { + return false; + } + if (!this.isPlayerMountedOnTurtle()) { + this.hide(); + return false; + } + return this.lastActived + ACTIVE_TIMEOUT > System.currentTimeMillis(); + } + + public void hide() { + this.fuelLevel = 0; + this.fuelLimit = 0; + this.barColor = 0; + this.lastActived = 0; + } + + public void keepAlive() { + this.lastActived = System.currentTimeMillis(); + } + + public void setFuelLevel(int level) { + if (level < 0) { + level = 0; + } + if (this.fuelLevel != level) { + this.fuelLevel = level; + this.keepAlive(); + } + } + + public void setFuelLimit(int limit) { + if (this.fuelLimit != limit) { + this.fuelLimit = limit; + this.keepAlive(); + } + } + + public void setBarColor(int color) { + if (this.barColor != color) { + this.barColor = color; + this.keepAlive(); + } + } + + private void renderFuelBar(PoseStack stack) { + // TODO: use a better looking bar here, and/or find someway to change the bar's color + RenderSystem.setShaderTexture(0, GuiComponent.GUI_ICONS_LOCATION); + int fontColor = 0x80ff20; + + int width = 182; + int left = this.screenWidth / 2 - 91; + int top = this.screenHeight - 32 + 3; + this.blit(stack, left, top, 0, 64, width, 5); + if (fuelLevel > 0 && fuelLimit > 0) { + int progWidth = fuelLevel * width / fuelLimit; + this.blit(stack, left, top, 0, 69, progWidth, 5); + } + + String text = fuelLimit > 0 ? String.format("%d / %d", fuelLevel, fuelLimit) : "Infinity"; + int x = (this.screenWidth - getFont().width(text)) / 2; + int y = this.screenHeight - 31; + getFont().draw(stack, text, (float)(x + 1), (float) y, 0); + getFont().draw(stack, text, (float)(x - 1), (float) y, 0); + getFont().draw(stack, text, (float) x, (float)(y + 1), 0); + getFont().draw(stack, text, (float) x, (float)(y - 1), 0); + getFont().draw(stack, text, (float) x, (float) y, fontColor); + } + + private void renderDismountHint(PoseStack stack) { + Minecraft minecraft = Minecraft.getInstance(); + Component name = Component.translatable("block.computercraft.turtle_normal.upgraded", Component.translatable("turtle.advancedperipherals.saddle_turtle")); + // TODO: get and render turtle's label if exists + Component text = Component.translatable("text.advancedperipherals.saddle_turtle.dismount_hint", + name, minecraft.options.keyShift.getTranslatedKeyMessage(), minecraft.options.keyInventory.getTranslatedKeyMessage()); + float top = 10; + float x = (float)(this.screenWidth / 2 - textWidth(text) / 2); + getFont().drawShadow(stack, text, x, top, 0xffffff); + } + + @Override + public void render(ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + if (!this.isPlayerMountedOnTurtle()) { + return; + } + + this.gui = gui; + this.screenWidth = screenWidth; + this.screenHeight = screenHeight; + + if (this.shouldRenderFuelBar()) { + this.renderFuelBar(poseStack); + } + if (this.isPlayerControllingTurtle()) { + this.renderDismountHint(poseStack); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/screens/SmartGlassesScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/SmartGlassesScreen.java new file mode 100644 index 000000000..c81884b59 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/SmartGlassesScreen.java @@ -0,0 +1,78 @@ +package de.srendi.advancedperipherals.client.screens; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import dan200.computercraft.client.gui.ComputerScreenBase; +import dan200.computercraft.client.gui.widgets.ComputerSidebar; +import dan200.computercraft.client.gui.widgets.WidgetTerminal; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.widgets.SmartGlassesSettingsSwitch; +import de.srendi.advancedperipherals.common.container.SmartGlassesContainer; +import de.srendi.advancedperipherals.common.smartglasses.SlotType; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.NotNull; + +public class SmartGlassesScreen extends ComputerScreenBase { + + private static final ResourceLocation BACKGROUND = new ResourceLocation(AdvancedPeripherals.MOD_ID, "textures/gui/smart_glasses_gui.png"); + public static final ResourceLocation SIDEBAR = new ResourceLocation(AdvancedPeripherals.MOD_ID, "textures/gui/corners_glasses.png"); + + private static final int TEX_WIDTH = 254; + private static final int TEX_HEIGHT = 217; + private SlotType currentType = SlotType.defaultType(); + + public SmartGlassesScreen(SmartGlassesContainer container, Inventory player, Component title) { + super(container, player, title, ContainerTurtle.BORDER); + + imageWidth = TEX_WIDTH + ComputerSidebar.WIDTH; + imageHeight = TEX_HEIGHT; + } + + @Override + protected void init() { + super.init(); + addRenderableWidget(new SmartGlassesSettingsSwitch(254, 147, SlotType.PERIPHERALS, this)); + addRenderableWidget(new SmartGlassesSettingsSwitch(254, 170, SlotType.MODULES, this)); + } + + @Override + protected WidgetTerminal createTerminal() { + return new WidgetTerminal(terminalData, input, leftPos + ContainerTurtle.BORDER + ComputerSidebar.WIDTH, topPos + ContainerTurtle.BORDER); + } + + @Override + protected void renderBg(@NotNull PoseStack transform, float partialTicks, int mouseX, int mouseY) { + RenderSystem.setShaderTexture(0, BACKGROUND); + blit(transform, leftPos + ComputerSidebar.WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT); + + if (currentType == SlotType.PERIPHERALS) + blit(transform, leftPos + ComputerSidebar.WIDTH + 222, topPos + 183, 186, 183, 18, 18); + + RenderSystem.setShaderTexture(0, SIDEBAR); + ComputerSidebar.renderBackground(transform, leftPos, topPos + sidebarYOffset); + } + + @Override + protected void renderTooltip(@NotNull PoseStack poseStack, int x, int y) { + super.renderTooltip(poseStack, x, y); + renderables.forEach(renderable -> { + if (renderable instanceof SmartGlassesSettingsSwitch smartGlassesSettingsSwitch) { + smartGlassesSettingsSwitch.renderTooltip(poseStack, x, y); + } + }); + } + + @Override + protected void renderLabels(@NotNull PoseStack poseStack, int x, int y) { + FormattedCharSequence formattedcharsequence = currentType.getName().getVisualOrderText(); + this.font.draw(poseStack, formattedcharsequence, (212 + ComputerSidebar.WIDTH - (float) this.font.width(formattedcharsequence) / 2), 133, 4210752); + } + + public void setCurrentType(SlotType currentType) { + this.currentType = currentType; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseItemScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseItemScreen.java similarity index 73% rename from src/main/java/de/srendi/advancedperipherals/common/container/base/BaseItemScreen.java rename to src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseItemScreen.java index 527878f10..a7e7e9476 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseItemScreen.java +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseItemScreen.java @@ -1,16 +1,18 @@ -package de.srendi.advancedperipherals.common.container.base; +package de.srendi.advancedperipherals.client.screens.base; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.container.base.BaseItemContainer; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.NotNull; public abstract class BaseItemScreen extends AbstractContainerScreen { - public BaseItemScreen(T screenContainer, Inventory inv, Component titleIn) { + protected BaseItemScreen(T screenContainer, Inventory inv, Component titleIn) { super(screenContainer, inv, titleIn); imageWidth = getSizeX(); @@ -18,14 +20,14 @@ public BaseItemScreen(T screenContainer, Inventory inv, Component titleIn) { } @Override - public void render(PoseStack matrixStack, int x, int y, float partialTicks) { + public void render(@NotNull PoseStack matrixStack, int x, int y, float partialTicks) { renderBackground(matrixStack); super.render(matrixStack, x, y, partialTicks); renderTooltip(matrixStack, x, y); } @Override - protected void renderBg(PoseStack matrixStack, float partialTicks, int x, int y) { + protected void renderBg(@NotNull PoseStack matrixStack, float partialTicks, int x, int y) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.setShaderTexture(0, getTexture()); diff --git a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseScreen.java b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseScreen.java similarity index 86% rename from src/main/java/de/srendi/advancedperipherals/common/container/base/BaseScreen.java rename to src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseScreen.java index f9311435e..9390fa902 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/container/base/BaseScreen.java +++ b/src/main/java/de/srendi/advancedperipherals/client/screens/base/BaseScreen.java @@ -1,7 +1,8 @@ -package de.srendi.advancedperipherals.common.container.base; +package de.srendi.advancedperipherals.client.screens.base; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.container.base.BaseContainer; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.network.chat.Component; @@ -11,7 +12,7 @@ public abstract class BaseScreen extends AbstractContainerScreen { - public BaseScreen(T screenContainer, Inventory inv, Component titleIn) { + protected BaseScreen(T screenContainer, Inventory inv, Component titleIn) { super(screenContainer, inv, titleIn); imageWidth = getSizeX(); imageHeight = getSizeY(); diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleLevelRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleLevelRenderer.java new file mode 100644 index 000000000..1a8aa23c2 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleLevelRenderer.java @@ -0,0 +1,115 @@ +package de.srendi.advancedperipherals.client.smartglasses; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.client.smartglasses.objects.threedim.IThreeDObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.util.EnumColor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE, modid = AdvancedPeripherals.MOD_ID) +public class OverlayModuleLevelRenderer { + + @SubscribeEvent + public static void renderLevelState(RenderLevelStageEvent event) { + PoseStack posestack = event.getPoseStack(); + Vec3 view = Minecraft.getInstance().getEntityRenderDispatcher().camera.getPosition(); + + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) { + Map, List> batches = new HashMap<>(); + + for (RenderableObject object : OverlayObjectHolder.getObjects()) { + if (!object.isEnabled() || !(object.getRenderObject() instanceof IThreeDObjectRenderer)) + continue; + + ThreeDimensionalObject threeDimObject = (ThreeDimensionalObject) object; + + Class extends ThreeDimensionalObject> objectClass = threeDimObject.getClass(); + + if (batches.containsKey(objectClass)) { + batches.get(objectClass).add(threeDimObject); + continue; + } + + List newBatchArray = new ArrayList<>(); + newBatchArray.add(threeDimObject); + batches.put(objectClass, newBatchArray); + } + + for (List batch : batches.values()) { + ((IThreeDObjectRenderer) batch.get(0).getRenderObject()).renderBatch(batch, event, posestack, view, bufferbuilder); + } + + //TODO Everything below here is just for debugging and testing. Will be removed before we push to production + BlockPos blockPos = new BlockPos(2, 100, 0); + + float[] colors = EnumColor.DARK_PURPLE.getRgb(); + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + bufferbuilder.begin(RenderType.translucent().mode(), DefaultVertexFormat.POSITION_COLOR_NORMAL); + posestack.pushPose(); + + posestack.translate(-view.x + blockPos.getX(), -view.y + blockPos.getY(), -view.z + blockPos.getZ()); + + RenderUtil.drawPlane(posestack, bufferbuilder, colors[0], colors[1], colors[2], 0.8f, Direction.UP, 0f, 0.5f, 0f, 0.5f, 0f, 1f); + + BufferUploader.drawWithShader(bufferbuilder.end()); + posestack.popPose(); + + VertexConsumer boxVertexConsumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.entityCutout(InventoryMenu.BLOCK_ATLAS)); + //RenderSystem.setShader(GameRenderer::getPositionColorLightmapShader); + + //bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP); + posestack.pushPose(); + colors = EnumColor.WHITE.getRgb(); + + blockPos = new BlockPos(0, 100, 0); + posestack.translate(-view.x + blockPos.getX(), -view.y + blockPos.getY(), -view.z + blockPos.getZ()); + + RenderUtil.drawSphere(posestack, boxVertexConsumer, 2f, 0f, 0f, 0f, 270f, 0f, 0f, colors[0], colors[1], colors[2], 0.4f, 16, 128); + + //BufferUploader.drawWithShader(bufferbuilder.end()); + posestack.popPose(); + + boxVertexConsumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.entityCutout(InventoryMenu.BLOCK_ATLAS)); + + //bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_NORMAL); + posestack.pushPose(); + + colors = EnumColor.WHITE.getRgb(); + blockPos = new BlockPos(6, 100, 0); + posestack.translate(-view.x + blockPos.getX(), -view.y + blockPos.getY(), -view.z + blockPos.getZ()); + + RenderUtil.drawTorus(posestack, boxVertexConsumer, 1f, 0.4f, 0f, 0f, 0f, 0f, 0f, 0f, colors[0], colors[1], colors[2], 1f, 48, 48); + + //BufferUploader.drawWithShader(bufferbuilder.end()); + posestack.popPose(); + + } + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleOverlay.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleOverlay.java new file mode 100644 index 000000000..6ef3fab90 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayModuleOverlay.java @@ -0,0 +1,56 @@ +package de.srendi.advancedperipherals.client.smartglasses; + +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.client.smartglasses.objects.twodim.ITwoDObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.RectangleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.TextObject; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.client.gui.overlay.IGuiOverlay; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +public class OverlayModuleOverlay implements IGuiOverlay { + public static final String ID = "overlay_module_overlay"; + + @Override + public void render(ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + poseStack.pushPose(); + + Map, List>> prioritizedBatches = new TreeMap<>(); + + for (RenderableObject object : OverlayObjectHolder.getObjects()) { + if (!object.isEnabled() || !(object.getRenderObject() instanceof ITwoDObjectRenderer)) { + continue; + } + + // We need to sort the objects by their weight, some things can't be rendered before something else. + // For example, when texts are rendered before our circles, rectangles, etc., the other objects can't be transparent anymore + int weight = object.getRenderObject().getWeight(); + Class extends RenderableObject> objectClass = object.getClass(); + + // Get or create the batch map for the current weight + Map, List> batchesForWeight = prioritizedBatches.computeIfAbsent(weight, k -> new HashMap<>()); + + List batch = batchesForWeight.computeIfAbsent(objectClass, k -> new ArrayList<>()); + + batch.add(object); + } + + for (Map, List> batchesForWeight : prioritizedBatches.values()) { + for (List batch : batchesForWeight.values()) { + + if (!batch.isEmpty()) { + ((ITwoDObjectRenderer) batch.get(0).getRenderObject()).renderBatch(batch, gui, poseStack, partialTick, screenWidth, screenHeight); + } + } + } + poseStack.popPose(); + + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayObjectHolder.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayObjectHolder.java new file mode 100644 index 000000000..e319679fd --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/OverlayObjectHolder.java @@ -0,0 +1,60 @@ +package de.srendi.advancedperipherals.client.smartglasses; + +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.ObjectDecodeRegistry; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BlockObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BoxObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.SphereObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.TorusObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.CircleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.ItemObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.LineObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.RectangleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.TextObject; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Static holder for client side renderable objects - will change + */ +public class OverlayObjectHolder { + + public static Map objects = new HashMap<>(); + + public static void addOrUpdateObject(RenderableObject object) { + objects.put(object.getId(), object); + } + + public static void addOrUpdateObjects(Collection objects) { + for (RenderableObject renderableObject : objects) { + addOrUpdateObject(renderableObject); + } + } + + public static void removeObject(int id) { + objects.remove(id); + } + + public static Collection getObjects() { + return objects.values(); + } + + public static void clear() { + objects.clear(); + } + + public static void registerDecodeObjects() { + ObjectDecodeRegistry.register(RectangleObject.TYPE_ID, RectangleObject::decode); + ObjectDecodeRegistry.register(CircleObject.TYPE_ID, CircleObject::decode); + ObjectDecodeRegistry.register(TextObject.TYPE_ID, TextObject::decode); + ObjectDecodeRegistry.register(ItemObject.TYPE_ID, ItemObject::decode); + ObjectDecodeRegistry.register(LineObject.TYPE_ID, LineObject::decode); + + ObjectDecodeRegistry.register(BoxObject.TYPE_ID, BoxObject::decode); + ObjectDecodeRegistry.register(BlockObject.TYPE_ID, BlockObject::decode); + ObjectDecodeRegistry.register(SphereObject.TYPE_ID, SphereObject::decode); + ObjectDecodeRegistry.register(TorusObject.TYPE_ID, TorusObject::decode); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/IObjectRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/IObjectRenderer.java new file mode 100644 index 000000000..aeefb36a9 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/IObjectRenderer.java @@ -0,0 +1,13 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects; + +public interface IObjectRenderer { + /** + * Get the weight of the renderer. Lower weight means higher priority and it will render first. + * Some things need to be rendered before others to prevent color and opacity issues. + * @return the weight of the renderer. + */ + default int getWeight() { + return 100; + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BlockRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BlockRenderer.java new file mode 100644 index 000000000..152f9c3fe --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BlockRenderer.java @@ -0,0 +1,65 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Quaternion; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BlockObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import de.srendi.advancedperipherals.common.util.RegistryUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.List; + +public class BlockRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + + bufferBuilder.begin(RenderType.solid().mode(), DefaultVertexFormat.BLOCK); + + BlockObject block = (BlockObject) obj; + + poseStack.translate(-view.x + block.getX(), -view.y + block.getY(), -view.z + block.getZ()); + poseStack.mulPose(new Quaternion(block.rotX, block.rotY, block.rotZ, true)); + poseStack.translate(-0.5f, -0.5f, -0.5f); + float alpha = block.opacity; + float red = RenderUtil.getRed(block.color); + float green = RenderUtil.getGreen(block.color); + float blue = RenderUtil.getBlue(block.color); + + RenderSystem.setShader(GameRenderer::getBlockShader); + RenderSystem.setShaderColor(red, green, blue, alpha); + + Block blockToRender = RegistryUtil.getRegistryEntry(block.block, ForgeRegistries.BLOCKS); + BlockPos blockPos = new BlockPos(obj.getX(), obj.getY(), obj.getZ()); + + if (blockToRender != null) + Minecraft.getInstance().getBlockRenderer().renderBatched(blockToRender.defaultBlockState(), blockPos, event.getCamera().getEntity().level, poseStack, bufferBuilder, false, event.getCamera().getEntity().level.random); + + poseStack.popPose(); + BufferUploader.drawWithShader(bufferBuilder.end()); + onPostRender(obj); + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + } + + + poseStack.popPose(); + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BoxRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BoxRenderer.java new file mode 100644 index 000000000..e773a6ec4 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/BoxRenderer.java @@ -0,0 +1,47 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.BoxObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public class BoxRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_NORMAL); + + BoxObject box = (BoxObject) obj; + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + float alpha = box.opacity; + float red = RenderUtil.getRed(box.color); + float green = RenderUtil.getGreen(box.color); + float blue = RenderUtil.getBlue(box.color); + + poseStack.translate(-view.x + box.getX(), -view.y + box.getY(), -view.z + box.getZ()); + RenderUtil.drawBox(poseStack, bufferBuilder, red, green, blue, alpha, box.x, box.y, box.z, obj.rotX, obj.rotY, obj.rotZ, obj.maxX, obj.maxY, obj.maxZ); + BufferUploader.drawWithShader(bufferBuilder.end()); + onPostRender(obj); + + poseStack.popPose(); + } + + poseStack.popPose(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/IThreeDObjectRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/IThreeDObjectRenderer.java new file mode 100644 index 000000000..119277f6f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/IThreeDObjectRenderer.java @@ -0,0 +1,30 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.client.smartglasses.objects.IObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public interface IThreeDObjectRenderer extends IObjectRenderer { + + void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder); + + default void onPostRender(ThreeDimensionalObject object) { + if (object.disableCulling) + RenderSystem.enableCull(); + if (object.disableDepthTest) + RenderSystem.enableDepthTest(); + } + + default void onPreRender(ThreeDimensionalObject object) { + if (object.disableCulling) + RenderSystem.disableCull(); + if (object.disableDepthTest) + RenderSystem.disableDepthTest(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/SphereRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/SphereRenderer.java new file mode 100644 index 000000000..71388a20e --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/SphereRenderer.java @@ -0,0 +1,49 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.SphereObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public class SphereRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + VertexConsumer boxVertexConsumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.entitySmoothCutout(TextureAtlas.LOCATION_BLOCKS)); + + SphereObject sphere = (SphereObject) obj; + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + float alpha = sphere.opacity; + float red = RenderUtil.getRed(sphere.color); + float green = RenderUtil.getRed(sphere.color); + float blue = RenderUtil.getRed(sphere.color); + + poseStack.translate(-view.x, -view.y, -view.z); + RenderUtil.drawSphere(poseStack, boxVertexConsumer, sphere.radius, sphere.x, sphere.y, sphere.z, sphere.rotX, sphere.rotY, sphere.rotZ, red, green, blue, alpha, sphere.sectors, sphere.stacks); + onPostRender(obj); + + poseStack.popPose(); + } + + + poseStack.popPose(); + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/TorusRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/TorusRenderer.java new file mode 100644 index 000000000..7921b8a71 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/threedim/TorusRenderer.java @@ -0,0 +1,47 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.threedim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.ThreeDimensionalObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.three_dim.TorusObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import java.util.List; + +public class TorusRenderer implements IThreeDObjectRenderer { + + @Override + public void renderBatch(List batch, RenderLevelStageEvent event, PoseStack poseStack, Vec3 view, BufferBuilder bufferBuilder) { + poseStack.pushPose(); + + for (ThreeDimensionalObject obj : batch) { + poseStack.pushPose(); + onPreRender(obj); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_NORMAL); + + TorusObject torus = (TorusObject) obj; + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + float alpha = torus.opacity; + float red = RenderUtil.getRed(torus.color); + float green = RenderUtil.getGreen(torus.color); + float blue = RenderUtil.getBlue(torus.color); + + poseStack.translate(-view.x + torus.x, -view.y + torus.y, -view.z + torus.z); + RenderUtil.drawTorus(poseStack, bufferBuilder, torus.majorRadius, torus.minorRadius, 0, 0, 0, torus.rotX, torus.rotY, torus.rotZ, red, green, blue, alpha, torus.rings, torus.sides); + BufferUploader.drawWithShader(bufferBuilder.end()); + onPostRender(obj); + + poseStack.popPose(); + } + + poseStack.popPose(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/CircleRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/CircleRenderer.java new file mode 100644 index 000000000..5929b3e8e --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/CircleRenderer.java @@ -0,0 +1,189 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +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.math.Matrix4f; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.CircleObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class CircleRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + for (RenderableObject obj : objects) { + + CircleObject circle = (CircleObject) obj; + + float alpha = circle.opacity; + float red = RenderUtil.getRed(circle.color); + float green = RenderUtil.getGreen(circle.color); + float blue = RenderUtil.getBlue(circle.color); + + drawCircle(poseStack, circle, red, green, blue, alpha); + } + } + + public void drawCircle(PoseStack t, CircleObject circle, float red, float green, float blue, float alpha) { + float r = circle.radius; + float cx = circle.x; + float cy = circle.y; + float cz = circle.z; + float rotX = circle.rotX; + float rotY = circle.rotY; + float rotZ = circle.rotZ; + float borderWidth = circle.borderWidth; + int segments = circle.segments; + + boolean isFilled = circle.filled; + boolean isPixelated = circle.pixelated; + + PoseStack poseStack = new PoseStack(); + + poseStack.translate(cx, cy, cz); + + poseStack.pushPose(); + + poseStack.mulPose(Vector3f.XP.rotationDegrees(rotX)); + poseStack.mulPose(Vector3f.YP.rotationDegrees(rotY)); + poseStack.mulPose(Vector3f.ZP.rotationDegrees(rotZ)); + + RenderSystem.disableCull(); + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + + Matrix4f matrix = poseStack.last().pose(); + + // Normal, smooth lines + if (!isPixelated) { + if (isFilled) { + + bufferbuilder.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR); + + bufferbuilder.vertex(matrix, 0, 0, 0f).color(red, green, blue, alpha).endVertex(); + + double angleStep = Math.PI * 2 / segments; + + for (int i = 0; i <= segments; i++) { + double angle = i * angleStep; + double x = r * Math.sin(angle); + double y = r * Math.cos(angle); + + bufferbuilder.vertex(matrix, (float) x, (float) y, 0).color(red, green, blue, alpha).endVertex(); + } + + } else { + float outerRadius = r; + float innerRadius = r - borderWidth; + + bufferbuilder.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR); + + double angleStep = Math.PI * 2 / segments; + + for (int i = 0; i <= segments; i++) { + double angle = i * angleStep; + + // Outer circle vertex + double outerX = innerRadius * Math.sin(angle); + double outerY = innerRadius * Math.cos(angle); + bufferbuilder.vertex(matrix, (float) outerX, (float) outerY, 0f).color(red, green, blue, alpha).endVertex(); + + // Inner circle vertex + double innerX = outerRadius * Math.sin(angle); + double innerY = outerRadius * Math.cos(angle); + bufferbuilder.vertex(matrix, (float) innerX, (float) innerY, 0f).color(red, green, blue, alpha).endVertex(); + } + } + + BufferUploader.drawWithShader(bufferbuilder.end()); + + return; + } + + // Pixelated lines + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + final float PIXEL_SIZE = borderWidth; // Defines the size of each "pixel" square + + // The thickness of the hollow line in terms of pixel units. + // A value of 1.0f means the line will be roughly one pixel thick. + final float LINE_THICKNESS_PIXELS = 1f; + + // Calculate the effective min/max coordinates in the relative space + float effectiveMinX = -r - PIXEL_SIZE; + float effectiveMaxX = r + PIXEL_SIZE; + float effectiveMinY = -r - PIXEL_SIZE; + float effectiveMaxY = r + PIXEL_SIZE; + +// Start the loop at the first multiple of PIXEL_SIZE that is less than or equal to effectiveMinX/Y + float startX = (float) Math.floor(effectiveMinX / PIXEL_SIZE) * PIXEL_SIZE; + float startY = (float) Math.floor(effectiveMinY / PIXEL_SIZE) * PIXEL_SIZE; + + + for (float x = startX; x <= effectiveMaxX; x += PIXEL_SIZE) { + for (float y = startY; y <= effectiveMaxY; y += PIXEL_SIZE) { + // Calculate the center of the current pixel cell. + // This is where you determine if the *center* of this block should be drawn. + float pixelCenterX = x + (PIXEL_SIZE / 2.0F); + float pixelCenterY = y + (PIXEL_SIZE / 2.0F); + + // Distance is calculated from (pixelCenterX, pixelCenterY) to (0,0) + double distanceToCenter = Math.sqrt( + Math.pow(pixelCenterX, 2) + Math.pow(pixelCenterY, 2) + ); + + boolean shouldDrawPixel; + + if (!isFilled) { + float outerRadius = r + (LINE_THICKNESS_PIXELS * (PIXEL_SIZE / 2.0F)); + float innerRadius = r - (LINE_THICKNESS_PIXELS * (PIXEL_SIZE / 2.0F)); + + if (innerRadius < 0) innerRadius = 0; + + shouldDrawPixel = (distanceToCenter <= outerRadius) && (distanceToCenter >= innerRadius); + } else { + shouldDrawPixel = distanceToCenter <= r + (PIXEL_SIZE / 2.0F); + } + + if (shouldDrawPixel) { + // Vertices for the QUAD (a PIXEL_SIZE x PIXEL_SIZE square) + // These coordinates are now relative to the current origin (0,0,0) + float p_x1 = x; + float p_y1 = y; + float p_z = 0f; // z-coordinate is relative to cz, so 0 in this space + + float p_x2 = x + PIXEL_SIZE; + float p_y2 = y + PIXEL_SIZE; + + // Vertices for the QUAD + // Ensure proper winding order (counter-clockwise for front face) + bufferbuilder.vertex(matrix, p_x1, p_y2, p_z).color(red, green, blue, alpha).endVertex(); // Bottom-left + bufferbuilder.vertex(matrix, p_x2, p_y2, p_z).color(red, green, blue, alpha).endVertex(); // Bottom-right + bufferbuilder.vertex(matrix, p_x2, p_y1, p_z).color(red, green, blue, alpha).endVertex(); // Top-right + bufferbuilder.vertex(matrix, p_x1, p_y1, p_z).color(red, green, blue, alpha).endVertex(); // Top-left + } + } + } + + RenderSystem.enableCull(); + + BufferUploader.drawWithShader(bufferbuilder.end()); + + + poseStack.popPose(); + + } +} + diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ITwoDObjectRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ITwoDObjectRenderer.java new file mode 100644 index 000000000..543f3580c --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ITwoDObjectRenderer.java @@ -0,0 +1,14 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.client.smartglasses.objects.IObjectRenderer; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public interface ITwoDObjectRenderer extends IObjectRenderer { + + void renderBatch(List object, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight); + +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ItemRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ItemRenderer.java new file mode 100644 index 000000000..6d2ff7ccb --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/ItemRenderer.java @@ -0,0 +1,29 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.vertex.PoseStack; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.ItemObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.util.RegistryUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.List; + +public class ItemRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + Minecraft minecraft = Minecraft.getInstance(); + + for (RenderableObject obj : objects) { + Item renderItem = RegistryUtil.getRegistryEntry(((ItemObject) obj).item, ForgeRegistries.ITEMS); + if (renderItem == null) + continue; + minecraft.getItemRenderer().renderGuiItem(new ItemStack(renderItem), (int) obj.x, (int) obj.y); + } + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/LineRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/LineRenderer.java new file mode 100644 index 000000000..71579398a --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/LineRenderer.java @@ -0,0 +1,103 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +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.math.Matrix4f; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.LineObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class LineRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack poseStack, float partialTick, int screenWidth, int screenHeight) { + RenderSystem.setShader(GameRenderer::getPositionColorShader); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + Matrix4f matrix = poseStack.last().pose(); + + for (RenderableObject obj : objects) { + + LineObject line = (LineObject) obj; + + float alpha = obj.opacity; + float red = RenderUtil.getRed(obj.color); + float green = RenderUtil.getGreen(obj.color); + float blue = RenderUtil.getBlue(obj.color); + + // Start and end points of the line + float x1 = obj.x; + float y1 = obj.y; + float z1 = obj.z; + + float x2 = obj.maxX; + float y2 = obj.maxY; + float z2 = obj.maxZ; + + // Normal, smooth lines + if (!line.pixelated) { + bufferbuilder.begin(VertexFormat.Mode.DEBUG_LINE_STRIP, DefaultVertexFormat.POSITION_COLOR); + bufferbuilder.vertex(matrix, x1, y1, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, x2, y2, 0).color(red, green, blue, alpha).endVertex(); + BufferUploader.drawWithShader(bufferbuilder.end()); + + continue; // Skip the rest of the loop for this object + } + + // Pixelated lines + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + // Calculate the delta for each axis + float dx = x2 - x1; + float dy = y2 - y1; + float dz = z2 - z1; + + final float PIXEL_SIZE = line.pixelSize; + + float maxDim = Math.max(Math.abs(dx), Math.max(Math.abs(dy), Math.abs(dz))); + int numPixels = (int) Math.ceil(maxDim / PIXEL_SIZE); + + if (numPixels == 0) { + numPixels = 1; // Always draw at least one pixel for very short lines + } + + // Iterate and draw a square for each "pixel" + for (int i = 0; i <= numPixels; i++) { + float t = (float) i / numPixels; // Interpolation factor (0.0 to 1.0) + + // Calculate the exact point on the line + float currentX = x1 + dx * t; + float currentY = y1 + dy * t; + float currentZ = z1 + dz * t; + + // Snap current point to the nearest pixel grid for consistent placement. + // This is key for placing pixels at corners or full side of each other. + currentX = Math.round(currentX / PIXEL_SIZE) * PIXEL_SIZE; + currentY = Math.round(currentY / PIXEL_SIZE) * PIXEL_SIZE; + currentZ = Math.round(currentZ / PIXEL_SIZE) * PIXEL_SIZE; + + float p_x1 = currentX; + float p_y1 = currentY; + float p_z1 = currentZ; + + float p_x2 = currentX + PIXEL_SIZE; + float p_y2 = currentY + PIXEL_SIZE; + float p_z2 = currentZ; + + bufferbuilder.vertex(matrix, p_x1, p_y2, p_z1).color(red, green, blue, alpha).endVertex(); // Bottom-left + bufferbuilder.vertex(matrix, p_x2, p_y2, p_z1).color(red, green, blue, alpha).endVertex(); // Bottom-right + bufferbuilder.vertex(matrix, p_x2, p_y1, p_z2).color(red, green, blue, alpha).endVertex(); // Top-right + bufferbuilder.vertex(matrix, p_x1, p_y1, p_z2).color(red, green, blue, alpha).endVertex(); // Top-left + } + BufferUploader.drawWithShader(bufferbuilder.end()); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/RectangleRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/RectangleRenderer.java new file mode 100644 index 000000000..55618cf74 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/RectangleRenderer.java @@ -0,0 +1,60 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +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.math.Matrix4f; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.client.RenderUtil; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class RectangleRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack ignored, float partialTick, int screenWidth, int screenHeight) { + RenderSystem.setShader(GameRenderer::getPositionColorShader); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (RenderableObject obj : objects) { + float rotX = obj.rotX; + float rotY = obj.rotY; + float rotZ = obj.rotZ; + + PoseStack poseStack = new PoseStack(); + + poseStack.translate(obj.x, obj.y, obj.z); + + poseStack.pushPose(); + + Matrix4f matrix = poseStack.last().pose(); + + poseStack.mulPose(Vector3f.XP.rotationDegrees(rotX)); + poseStack.mulPose(Vector3f.YP.rotationDegrees(rotY)); + poseStack.mulPose(Vector3f.ZP.rotationDegrees(rotZ)); + + float alpha = obj.opacity; + float red = RenderUtil.getRed(obj.color); + float green = RenderUtil.getGreen(obj.color); + float blue = RenderUtil.getBlue(obj.color); + + bufferbuilder.vertex(matrix, 0, obj.maxY - obj.y, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, obj.maxX - obj.x, obj.maxY - obj.y, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, obj.maxX - obj.x, 0, 0).color(red, green, blue, alpha).endVertex(); + bufferbuilder.vertex(matrix, 0, 0, 0).color(red, green, blue, alpha).endVertex(); + poseStack.popPose(); + + } + + BufferUploader.drawWithShader(bufferbuilder.end()); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/TextRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/TextRenderer.java new file mode 100644 index 000000000..ecde02ad7 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/smartglasses/objects/twodim/TextRenderer.java @@ -0,0 +1,55 @@ +package de.srendi.advancedperipherals.client.smartglasses.objects.twodim; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.RenderableObject; +import de.srendi.advancedperipherals.common.smartglasses.modules.overlay.objects.two_dim.TextObject; +import net.minecraft.client.Minecraft; +import net.minecraftforge.client.gui.overlay.ForgeGui; + +import java.util.List; + +public class TextRenderer implements ITwoDObjectRenderer { + + @Override + public void renderBatch(List objects, ForgeGui gui, PoseStack ignored, float partialTick, int screenWidth, int screenHeight) { + Minecraft minecraft = Minecraft.getInstance(); + for (RenderableObject obj : objects) { + TextObject text = (TextObject) obj; + float rotX = obj.rotX; + float rotY = obj.rotY; + float rotZ = obj.rotZ; + + float x = text.x; + + if (text.center) { + x -= (minecraft.font.width(text.content) * text.fontSize) / 2f; + } + + PoseStack poseStack = new PoseStack(); + + poseStack.translate(x / text.fontSize, text.y / text.fontSize, obj.z); + + poseStack.pushPose(); + + poseStack.mulPose(Vector3f.XP.rotationDegrees(rotX)); + poseStack.mulPose(Vector3f.YP.rotationDegrees(rotY)); + poseStack.mulPose(Vector3f.ZP.rotationDegrees(rotZ)); + + poseStack.scale(text.fontSize, text.fontSize, 1); + + if (!text.shadow) { + minecraft.font.drawShadow(poseStack, text.content, 0, 0, text.color); + } else { + minecraft.font.draw(poseStack, text.content, 0, 0, text.color); + } + poseStack.popPose(); + } + } + + @Override + public int getWeight() { + return 110; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/widgets/SmartGlassesSettingsSwitch.java b/src/main/java/de/srendi/advancedperipherals/client/widgets/SmartGlassesSettingsSwitch.java new file mode 100644 index 000000000..a6ab0c0cc --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/widgets/SmartGlassesSettingsSwitch.java @@ -0,0 +1,85 @@ +package de.srendi.advancedperipherals.client.widgets; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import dan200.computercraft.client.gui.widgets.ComputerSidebar; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.screens.SmartGlassesScreen; +import de.srendi.advancedperipherals.common.smartglasses.SlotType; +import de.srendi.advancedperipherals.common.smartglasses.SmartGlassesSlot; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.Slot; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +public class SmartGlassesSettingsSwitch extends AbstractWidget { + + private static final ResourceLocation BACKGROUND = new ResourceLocation(AdvancedPeripherals.MOD_ID, "textures/gui/smart_glasses_gui.png"); + + private final SmartGlassesScreen screen; + private final SlotType type; + private boolean isEnabled; + + public SmartGlassesSettingsSwitch(int x, int y, SlotType type, SmartGlassesScreen screen) { + super(screen.getGuiLeft() + x + ComputerSidebar.WIDTH, screen.getGuiTop() + y, 21, 22, type.getName()); + this.screen = screen; + this.type = type; + this.isEnabled = type == SlotType.defaultType(); + } + + @Override + public void render(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) { + renderBg(pPoseStack, Minecraft.getInstance(), pMouseX, pMouseY); + } + + @Override + public void renderButton(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) { + // Disable rendering of default buttons + } + + @Override + protected void renderBg(@NotNull PoseStack pPoseStack, @NotNull Minecraft pMinecraft, int pMouseX, int pMouseY) { + RenderSystem.setShaderTexture(0, BACKGROUND); + if (isEnabled) { + blit(pPoseStack, this.x - 3, this.y, 45, 217, 24, 22); + } else { + blit(pPoseStack, this.x, this.y, 23, 217, 21, 22); + } + } + + @Override + public void onClick(double pMouseX, double pMouseY) { + if (this.isEnabled) + return; + for (Slot slot : screen.getMenu().slots) { + if (slot instanceof SmartGlassesSlot smartGlassesSlot) { + if (smartGlassesSlot.slotType == this.type) { + smartGlassesSlot.setEnabled(true); + continue; + } + smartGlassesSlot.setEnabled(false); + } + } + screen.renderables.forEach(renderable -> { + if (renderable instanceof SmartGlassesSettingsSwitch smartGlassesSettingsSwitch) { + smartGlassesSettingsSwitch.isEnabled = false; + } + }); + screen.setCurrentType(this.type); + this.isEnabled = true; + } + + public void renderTooltip(PoseStack poseStack, int x, int y) { + if (screen != null && isMouseOver(x, y)) + screen.renderComponentTooltip(poseStack, Collections.singletonList(type.getName()), x, y); + } + + @Override + public void updateNarration(@NotNull NarrationElementOutput pNarrationElementOutput) { + + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java b/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java index c26e2652a..bdc4e4265 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java @@ -1,41 +1,72 @@ package de.srendi.advancedperipherals.common.addons; import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.common.addons.refinedstorage.RefinedStorage; +import de.srendi.advancedperipherals.common.addons.refinedstorage.RSApi; +import de.srendi.advancedperipherals.common.addons.valkyrienskies.ValkyrienSkies; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; +import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.SlotResult; +import top.theillusivec4.curios.api.SlotTypeMessage; + +import java.util.List; @Mod.EventBusSubscriber(modid = AdvancedPeripherals.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class APAddons { - public static final String CURIOS_MODID = "curios"; - public static final String REFINEDSTORAGE_MODID = "refinedstorage"; - public static final String AE_THINGS_MODID = "ae2things"; public static final String AE_ADDITIONS_MODID = "ae2additions"; + public static final String AE_THINGS_MODID = "ae2things"; + public static final String APPLIEDENERGISTICS_MODID = "ae2"; public static final String APP_MEKANISTICS_MODID = "appmek"; + public static final String BOTANIA_MODID = "botania"; + public static final String CREATE_MODID = "create"; + public static final String CURIOS_MODID = "curios"; + public static final String DIMSTORAGE_MODID = "dimstorage"; + public static final String MEKANISM_MODID = "mekanism"; + public static final String POWAH_MODID = "powah"; + public static final String REFINEDSTORAGE_MODID = "refinedstorage"; + public static final String VALKYRIEN_SKIES_MODID = "valkyrienskies"; - public static boolean curiosLoaded; - public static boolean refinedStorageLoaded; - public static boolean aeThingsLoaded; public static boolean aeAdditionsLoaded; + public static boolean aeThingsLoaded; public static boolean appMekLoaded; + public static boolean appliedEnergisticsLoaded; + public static boolean botaniaLoaded; + public static boolean createLoaded; + public static boolean curiosLoaded; + public static boolean dimstorageLoaded; + public static boolean mekanismLoaded; + public static boolean powahLoaded; + public static boolean refinedStorageLoaded; + public static boolean vs2Loaded; - private APAddons() { - } - - public static void commonSetup() { + // Use static so these checks run as early as possible, so we can use them for our registries + static { ModList modList = ModList.get(); - curiosLoaded = modList.isLoaded(CURIOS_MODID); - refinedStorageLoaded = modList.isLoaded(REFINEDSTORAGE_MODID); - aeThingsLoaded = modList.isLoaded(AE_THINGS_MODID); aeAdditionsLoaded = modList.isLoaded(AE_ADDITIONS_MODID); + aeThingsLoaded = modList.isLoaded(AE_THINGS_MODID); appMekLoaded = modList.isLoaded(APP_MEKANISTICS_MODID); + appliedEnergisticsLoaded = modList.isLoaded(APPLIEDENERGISTICS_MODID); + botaniaLoaded = modList.isLoaded(BOTANIA_MODID); + createLoaded = modList.isLoaded(CREATE_MODID); + curiosLoaded = modList.isLoaded(CURIOS_MODID); + dimstorageLoaded = modList.isLoaded(DIMSTORAGE_MODID); + mekanismLoaded = modList.isLoaded(MEKANISM_MODID); + powahLoaded = modList.isLoaded(POWAH_MODID); + refinedStorageLoaded = modList.isLoaded(REFINEDSTORAGE_MODID); + vs2Loaded = modList.isLoaded(VALKYRIEN_SKIES_MODID); - if (refinedStorageLoaded) - RefinedStorage.instance = new RefinedStorage(); - + if (refinedStorageLoaded) { + RSApi.instance = new RSApi(); + } } @SubscribeEvent @@ -43,6 +74,27 @@ public static void interModComms(InterModEnqueueEvent event) { if (!curiosLoaded) return; - // InterModComms.sendTo("curios", SlotTypeMessage.REGISTER_TYPE, () -> new SlotTypeMessage.Builder("glasses").size(1).build()); + InterModComms.sendTo(CURIOS_MODID, SlotTypeMessage.REGISTER_TYPE, + () -> new SlotTypeMessage.Builder("glasses") + .size(1) + .icon(new ResourceLocation(AdvancedPeripherals.MOD_ID, "slot/empty_glasses_slot")) + .build()); + } + + public static ItemStack getCurioGlasses(Player player) { + if (!curiosLoaded) + return ItemStack.EMPTY; + List curioSlots = CuriosApi.getCuriosHelper().findCurios(player, "glasses"); + if (curioSlots.isEmpty()) + return ItemStack.EMPTY; + + return curioSlots.get(0).stack(); + } + + public static boolean isBlockOnShip(Level level, BlockPos pos) { + if (!vs2Loaded) { + return false; + } + return ValkyrienSkies.isBlockOnShip(level, pos); } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AE2Registries.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AE2Registries.java new file mode 100644 index 000000000..b4759df1d --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AE2Registries.java @@ -0,0 +1,42 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.features.P2PTunnelAttunement; +import appeng.api.parts.IPart; +import appeng.api.parts.IPartItem; +import appeng.api.parts.PartModels; +import appeng.items.parts.PartItem; +import appeng.items.parts.PartModelsHelper; +import dan200.computercraft.shared.Registry.ModItems; +import de.srendi.advancedperipherals.common.setup.APRegistration; +import net.minecraft.data.tags.TagsProvider; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraftforge.registries.RegistryObject; + +import java.util.function.Function; + +public final class AE2Registries { + private AE2Registries() {} + + public static final RegistryObject> CABLE_P2P_TUNNEL = registerPart("cable_p2p_tunnel", WiredCableP2PTunnelPart.class, WiredCableP2PTunnelPart::new); + + private static RegistryObject> registerPart(String id, Class clazz, Function, T> factory) { + PartModels.registerModels(PartModelsHelper.createModels(clazz)); + return APRegistration.ITEMS.register(id, () -> new PartItem<>(new Item.Properties(), clazz, factory)); + } + + public static void finishRegister() { + P2PTunnelAttunement.registerAttunementTag(CABLE_P2P_TUNNEL.get()); + } + + public static TagKey getCableP2PTag() { + return P2PTunnelAttunement.getAttunementTag(CABLE_P2P_TUNNEL.get()); + } + + public static void registerTags(Function, TagsProvider.TagAppender> tagger) { + tagger.apply(getCableP2PTag()) + .add(ModItems.CABLE.get()) + .add(ModItems.WIRED_MODEM.get()) + .add(ModItems.WIRED_MODEM_FULL.get()); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AEApi.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AEApi.java new file mode 100644 index 000000000..51958de66 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AEApi.java @@ -0,0 +1,961 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.crafting.IPatternDetails; +import appeng.api.inventories.InternalInventory; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.CraftingJobStatus; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingService; +import appeng.api.networking.storage.IStorageService; +import appeng.api.stacks.AEFluidKey; +import appeng.api.stacks.AEItemKey; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.AEKeyType; +import appeng.api.stacks.GenericStack; +import appeng.api.stacks.KeyCounter; +import appeng.api.storage.AEKeyFilter; +import appeng.api.storage.IStorageProvider; +import appeng.api.storage.MEStorage; +import appeng.api.storage.cells.IBasicCellItem; +import appeng.blockentity.storage.DriveBlockEntity; +import appeng.crafting.execution.CraftingCpuLogic; +import appeng.crafting.pattern.EncodedPatternItem; +import appeng.helpers.iface.PatternContainer; +import appeng.items.storage.BasicStorageCell; +import appeng.me.cells.BasicCellHandler; +import appeng.me.cells.BasicCellInventory; +import appeng.me.cluster.implementations.CraftingCPUCluster; +import appeng.parts.storagebus.StorageBusPart; +import com.the9grounds.aeadditions.item.storage.StorageCell; +import com.the9grounds.aeadditions.item.storage.SuperStorageCell; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.util.LuaConverter; +import de.srendi.advancedperipherals.common.util.Pair; +import de.srendi.advancedperipherals.common.util.inventory.FluidFilter; +import de.srendi.advancedperipherals.common.util.inventory.GenericFilter; +import de.srendi.advancedperipherals.common.util.inventory.ItemFilter; +import io.github.projectet.ae2things.item.DISKDrive; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import me.ramidzkh.mekae2.ae2.MekanismKey; +import me.ramidzkh.mekae2.ae2.MekanismKeyType; +import me.ramidzkh.mekae2.item.ChemicalStorageCell; +import mekanism.api.chemical.merged.MergedChemicalTank; +import mekanism.common.tile.TileEntityChemicalTank; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class AEApi { + + public static Pair findAEStackFromStack(MEStorage monitor, @Nullable ICraftingService crafting, ItemStack item) { + return findAEStackFromFilter(monitor, crafting, ItemFilter.fromStack(item)); + } + + public static Pair findAEStackFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, ItemFilter item) { + for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { + if (temp.getKey() instanceof AEItemKey key && item.test(key.toStack())) + return Pair.of(temp.getLongValue(), key); + } + + if (crafting == null) + return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); + + for (var temp : crafting.getCraftables(param -> true)) { + if (temp instanceof AEItemKey key && item.test(key.toStack())) + return Pair.of(0L, key); + } + + return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); + } + + public static Pair findAEFluidFromStack(MEStorage monitor, @Nullable ICraftingService crafting, FluidStack item) { + return findAEFluidFromFilter(monitor, crafting, FluidFilter.fromStack(item)); + } + + public static Pair findAEFluidFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, FluidFilter item) { + for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { + if (temp.getKey() instanceof AEFluidKey key && item.test(key.toStack(1))) + return Pair.of(temp.getLongValue(), key); + } + + if (crafting == null) + return Pair.of(0L, AEFluidKey.of(FluidStack.EMPTY)); + + for (var temp : crafting.getCraftables(param -> true)) { + if (temp instanceof AEFluidKey key && item.test(key.toStack(1))) + return Pair.of(0L, key); + } + + return Pair.of(0L, AEFluidKey.of(FluidStack.EMPTY)); + } + + /** + * Finds a pattern from filters. + * + * @param grid The grid to search patterns from. + * @param level The level of the grid. + * @param inputFilter The input filter to apply, can be null to ignore input filter. + * @param outputFilter The output filter to apply, can be null to ignore output filter. + * @return A Pair object containing the matched pattern and an error message if no pattern is found. + * The pattern can be null if no pattern is found. + * The error message is "NO_PATTERN_FOUND" if no pattern is found. + */ + public static Pair findPatternFromFilters(IGrid grid, Level level, @Nullable GenericFilter inputFilter, @Nullable GenericFilter outputFilter) { + for (IPatternDetails pattern : getPatterns(grid, level)) { + if (pattern.getInputs().length == 0) + continue; + if (pattern.getOutputs().length == 0) + continue; + + boolean inputMatch = false; + boolean outputMatch = false; + + if (inputFilter != null) { + outerLoop: + for (IPatternDetails.IInput input : pattern.getInputs()) { + for (GenericStack possibleInput : input.getPossibleInputs()) { + if (inputFilter.testAE(possibleInput)) { + inputMatch = true; + break outerLoop; + } + } + } + } else { + inputMatch = true; + } + + if (outputFilter != null) { + for (GenericStack output : pattern.getOutputs()) { + if (outputFilter.testAE(output)) { + outputMatch = true; + break; + } + } + } else { + outputMatch = true; + } + + if (inputMatch && outputMatch) + return Pair.of(pattern, null); + } + + return Pair.of(null, "NO_PATTERN_FOUND"); + } + + + public static List listStacks(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + KeyCounter keyCounter = monitor.getAvailableStacks(); + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof AEItemKey itemKey) { + items.add(parseAeStack(Pair.of(aeKey.getLongValue(), itemKey), service)); + } + } + return items; + } + + public static List listCraftableStacks(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + KeyCounter keyCounter = monitor.getAvailableStacks(); + Set craftables = service.getCraftables(AEKeyFilter.none()); + for (AEKey aeKey : craftables) { + if (aeKey instanceof AEItemKey) { + items.add(parseAeStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); + } + } + return items; + } + + public static List listFluids(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { + if (aeKey.getKey() instanceof AEFluidKey itemKey) { + items.add(parseAeStack(Pair.of(aeKey.getLongValue(), itemKey), service)); + } + } + return items; + } + + public static List listGases(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { + if (APAddons.appMekLoaded && aeKey.getKey() instanceof MekanismKey itemKey) { + items.add(parseAeStack(Pair.of(aeKey.getLongValue(), itemKey), service)); + } + } + return items; + } + + public static List listCraftableFluids(MEStorage monitor, ICraftingService service) { + List items = new ArrayList<>(); + KeyCounter keyCounter = monitor.getAvailableStacks(); + Set craftables = service.getCraftables(AEKeyFilter.none()); + for (AEKey aeKey : craftables) { + if (aeKey instanceof AEFluidKey) { + items.add(parseAeStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); + } + } + return items; + } + + public static List getPatterns(IGrid grid, Level level) { + List patterns = new ArrayList<>(); + for (var machineClass : grid.getMachineClasses()) { + var containerClass = tryCastMachineToContainer(machineClass); + if (containerClass == null) + continue; + + for (var container : grid.getActiveMachines(containerClass)) { + for (ItemStack patternItem : container.getTerminalPatternInventory()) { + if (patternItem.getItem() instanceof EncodedPatternItem item) { + IPatternDetails patternDetails = item.decode(patternItem, level, false); + if (patternDetails == null) + continue; + + patterns.add(patternDetails); + } + } + } + } + return patterns; + } + + public static List listPatterns(IGrid grid, Level level) { + return getPatterns(grid, level).stream().map(AEApi::parsePattern).collect(Collectors.toList()); + } + + public static List listDrives(IGrid grid) { + List drives = new ArrayList<>(); + + for (IGridNode node : grid.getMachineNodes(DriveBlockEntity.class)) { + DriveBlockEntity drive = (DriveBlockEntity) node.getService(IStorageProvider.class); + + // A normal drive has a cellCount of 10 + if (drive == null || drive.getCellCount() != 10) + continue; + + drives.add(parseDrive(drive)); + } + + return drives; + } + + private static Class extends PatternContainer> tryCastMachineToContainer(Class> machineClass) { + if (PatternContainer.class.isAssignableFrom(machineClass)) + return machineClass.asSubclass(PatternContainer.class); + + return null; + } + + public static Map parseAeStack(Pair stack, @Nullable ICraftingService service) { + if (stack == null || stack.getRight() == null) + return Collections.emptyMap(); + if (stack.getRight() instanceof AEItemKey itemKey) + return parseItemStack(Pair.of(stack.getLeft(), itemKey), service); + if (stack.getRight() instanceof AEFluidKey fluidKey) + return parseFluidStack(Pair.of(stack.getLeft(), fluidKey), service); + if (APAddons.appMekLoaded && (stack.getRight() instanceof MekanismKey gasKey)) + return parseChemStack(Pair.of(stack.getLeft(), gasKey)); + + AdvancedPeripherals.debug("Could not create table from unknown stack " + stack.getRight().getClass() + " - Report this to the maintainer of ap", org.apache.logging.log4j.Level.WARN); + return Collections.emptyMap(); + } + + public static Map parseGenericStack(GenericStack stack) { + if (stack.what() == null) + return Collections.emptyMap(); + if (stack.what() instanceof AEItemKey aeItemKey) + return parseItemStack(Pair.of(stack.amount(), aeItemKey), null); + if (stack.what() instanceof AEFluidKey aeFluidKey) + return parseFluidStack(Pair.of(stack.amount(), aeFluidKey), null); + + AdvancedPeripherals.debug("Could not create table from unknown stack " + stack.getClass() + " - Report this to the maintainer of ap", org.apache.logging.log4j.Level.WARN); + return Collections.emptyMap(); + } + + public static List parseKeyCounter(KeyCounter counter) { + List parsedKeys = new ArrayList<>(); + for (AEKey key : counter.keySet()) { + parsedKeys.add(parseGenericStack(new GenericStack(key, counter.get(key)))); + } + + return parsedKeys; + } + + public static Map parseDrive(DriveBlockEntity drive) { + Map map = new HashMap<>(); + + map.put("powered", drive.isPowered()); + + long totalBytes = 0; + long usedBytes = 0; + + if (drive.getCellCount() != 10) + return map; + + List driveCells = new ArrayList<>(); + for (ItemStack item : drive.getInternalInventory()) { + if (item.getItem() instanceof BasicStorageCell cell) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(item, null); + totalBytes += cellInventory.getTotalBytes(); + usedBytes += cellInventory.getUsedBytes(); + + driveCells.add(parseCell(cell, item)); + } + } + + map.put("usedBytes", usedBytes); + map.put("totalBytes", totalBytes); + map.put("cells", driveCells); + map.put("priority", drive.getPriority()); + map.put("menuIcon", LuaConverter.itemToObject(drive.getMainMenuIcon().getItem())); + map.put("position", LuaConverter.posToObject(drive.getBlockPos())); + map.put("name", drive.getCustomInventoryName().getString()); + + return map; + } + + public static Map parseCell(IBasicCellItem cell, ItemStack cellItem) { + Map map = new HashMap<>(); + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(cellItem, null); + + map.put("item", LuaConverter.itemToObject(cellItem.getItem())); + map.put("type", cell.getKeyType().toString()); + map.put("bytes", cell.getBytes(cellItem)); + map.put("bytesPerType", cell.getBytesPerType(cellItem)); + map.put("usedBytes", cellInventory.getUsedBytes()); + map.put("totalTypes", cell.getTotalTypes(cellItem)); + map.put("fuzzyMode", cell.getFuzzyMode(cellItem).toString()); + + return map; + } + + private static Map parseItemStack(Pair stack, @Nullable ICraftingService craftingService) { + Map map = LuaConverter.itemStackToObject(stack.getRight().toStack()); + map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); + map.put("count", stack.getLeft()); + return map; + } + + private static Map parseFluidStack(Pair stack, @Nullable ICraftingService craftingService) { + Map map = LuaConverter.fluidStackToObject(stack.getRight().toStack(1)); + map.put("count", stack.getLeft()); + map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); + return map; + } + + private static Map parseChemStack(Pair stack) { + Map map = new HashMap<>(); + long amount = stack.getLeft(); + map.put("name", stack.getRight().getStack().getTypeRegistryName().toString()); + map.put("amount", amount); + map.put("displayName", stack.getRight().getDisplayName().getString()); + map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getStack().getType().getTags())); + + return map; + } + + public static Map parsePattern(IPatternDetails pattern) { + Map map = new HashMap<>(); + + map.put("inputs", Arrays.stream(pattern.getInputs()).map(AEApi::parsePatternInput).collect(Collectors.toList())); + map.put("outputs", Arrays.stream(pattern.getOutputs()).map(AEApi::parseGenericStack).collect(Collectors.toList())); + map.put("primaryOutput", parseGenericStack(pattern.getPrimaryOutput())); + return map; + } + + public static Map parsePatternInput(IPatternDetails.IInput patternInput) { + Map map = new HashMap<>(); + map.put("primaryInput", parseGenericStack(patternInput.getPossibleInputs()[0])); + map.put("possibleInputs", + Arrays.stream(Arrays.copyOfRange(patternInput.getPossibleInputs(), 1, patternInput.getPossibleInputs().length)) + .map(AEApi::parseGenericStack)); + map.put("multiplier", patternInput.getMultiplier()); + map.put("remaining", patternInput.getRemainingKey(patternInput.getPossibleInputs()[0].what())); + return map; + } + + public static Map parseCraftingCPU(ICraftingCPU cpu, boolean recursive) { + Map map = new HashMap<>(); + long storage = cpu.getAvailableStorage(); + int coProcessors = cpu.getCoProcessors(); + boolean isBusy = cpu.isBusy(); + map.put("storage", storage); + map.put("coProcessors", coProcessors); + map.put("isBusy", isBusy); + if (!recursive) + map.put("craftingJob", cpu.getJobStatus() != null ? parseCraftingJob(cpu.getJobStatus(), null, null) : null); + map.put("name", cpu.getName() != null ? cpu.getName().getString() : "Unnamed"); + map.put("selectionMode", cpu.getSelectionMode().toString()); + + return map; + } + + public static Object parseCraftingJob(CraftingJobStatus status, AECraftJob craftJob, @Nullable ICraftingCPU cpu) { + Map properties = new HashMap<>(); + + properties.put("bridge_id", craftJob == null ? -1 : craftJob.getId()); + properties.put("quantity", status.crafting().amount()); + properties.put("resource", parseGenericStack(status.crafting())); + + if (cpu != null) { + CraftingCpuLogic craftingCpuLogic = ((CraftingCPUCluster) cpu).craftingLogic; + long pending = craftingCpuLogic.getPendingOutputs(status.crafting().what()); + long active = craftingCpuLogic.getWaitingFor(status.crafting().what()); + long crafted = status.crafting().amount() - (pending + active); + properties.put("completion", crafted / (double) status.crafting().amount()); + properties.put("crafted", crafted); + + properties.put("id", craftingCpuLogic.getLastLink().getCraftingID().toString()); + + properties.put("cpu", parseCraftingCPU(cpu, true)); + } + + return properties; + } + + public static MEStorage getMonitor(IGridNode node) { + return node.getGrid().getService(IStorageService.class).getInventory(); + } + + public static boolean isCrafting(ICraftingService grid, GenericFilter> filter, + @Nullable ICraftingCPU craftingCPU) { + + // If the passed cpu is null, check all cpus + if (craftingCPU == null) { + // Loop through all crafting cpus and check if the item is being crafted. + for (ICraftingCPU cpu : grid.getCpus()) { + if (cpu.isBusy()) { + CraftingJobStatus jobStatus = cpu.getJobStatus(); + + // avoid null pointer exception + if (jobStatus == null) + continue; + + if (filter.testAE(jobStatus.crafting())) + return true; + } + } + } else { + if (craftingCPU.isBusy()) { + CraftingJobStatus jobStatus = craftingCPU.getJobStatus(); + + // avoid null pointer exception + if (jobStatus == null) + return false; + + return filter.testAE(jobStatus.crafting()); + } + } + + return false; + } + + /// External Storage + /// Total + + public static long getTotalExternalItemStorage(IGridNode node) { + long total = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + Level level = bus.getLevel(); + BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); + BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); + + if (connectedInventoryEntity == null) + continue; + + LazyOptional itemHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.ITEM_HANDLER); + if (itemHandler.isPresent()) { + IItemHandler handler = itemHandler.orElse(null); + for (int i = 0; i < handler.getSlots(); i++) { + total += handler.getSlotLimit(i); + } + } + } + + return total; + } + + public static long getTotalExternalFluidStorage(IGridNode node) { + long total = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + Level level = bus.getLevel(); + BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); + BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); + + if (connectedInventoryEntity == null) + continue; + + LazyOptional fluidHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.FLUID_HANDLER); + if (fluidHandler.isPresent()) { + IFluidHandler handler = fluidHandler.orElse(null); + for (int i = 0; i < handler.getTanks(); i++) { + total += handler.getTankCapacity(i); + } + } + } + + return total; + } + + public static long getTotalExternalChemicalStorage(IGridNode node) { + long total = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + Level level = bus.getLevel(); + BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); + BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); + + if (connectedInventoryEntity == null) + continue; + + if (connectedInventoryEntity instanceof TileEntityChemicalTank tank) { + MergedChemicalTank.Current current = tank.getChemicalTank().getCurrent() == MergedChemicalTank.Current.EMPTY ? MergedChemicalTank.Current.GAS : tank.getChemicalTank().getCurrent(); + total += tank.getChemicalTank().getTankFromCurrent(current).getCapacity(); + } + } + + return total; + } + + /// Used + + public static long getUsedExternalItemStorage(IGridNode node) { + long used = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); + + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof AEItemKey) + used += aeKey.getLongValue(); + } + } + + return used; + } + + public static long getUsedExternalFluidStorage(IGridNode node) { + long used = 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); + + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof AEFluidKey) + used += aeKey.getLongValue(); + } + } + + return used; + } + + public static long getUsedExternalChemicalStorage(IGridNode node) { + long used = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(StorageBusPart.class)) { + StorageBusPart bus = (StorageBusPart) iGridNode.getService(IStorageProvider.class); + KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); + + for (Object2LongMap.Entry aeKey : keyCounter) { + if (aeKey.getKey() instanceof MekanismKey) + used += aeKey.getLongValue(); + } + } + + return used; + } + + /// Internal Storage + /// Total + + public static long getTotalItemStorage(IGridNode node) { + long total = 0; + + // note: do not query DriveBlockEntity.class specifically here, because it will avoid subclasses, e.g. the ME Extended Drive from ExtendedAE + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { + total += cell.getBytes(null); + } + } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { + if (disk.getKeyType().toString().equals("ae2:i")) { + total += disk.getBytes(null); + } + } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof SuperStorageCell superStorageCell)) { + total += superStorageCell.getKiloBytes() * 1024L; + } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { + if (storageCell.getKeyType() != AEKeyType.items()) + continue; + total += storageCell.getKiloBytes() * 1024; + } + } + } + return total; + } + + public static long getTotalFluidStorage(IGridNode node) { + long total = 0; + + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { + total += cell.getBytes(null); + } + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { + total += superStorageCell.getKiloBytes() * 1024L; + } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { + if (storageCell.getKeyType() != AEKeyType.fluids()) + continue; + total += storageCell.getKiloBytes() * 1024; + } + } + } + + return total; + } + + public static long getTotalChemicalStorage(IGridNode node) { + long total = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(DriveBlockEntity.class)) { + DriveBlockEntity entity = (DriveBlockEntity) iGridNode.getService(IStorageProvider.class); + if (entity == null) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof ChemicalStorageCell cell) { + if (cell.getKeyType() instanceof MekanismKeyType) { + total += cell.getBytes(null); + } + } + } + } + + return total; + } + + /// Used + + public static long getUsedItemStorage(IGridNode node) { + long used = 0; + + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(stack, null); + + used += cellInventory.getUsedBytes(); + } + } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { + if (disk.getKeyType().toString().equals("ae2:i")) { + if (stack.getTag() == null) + continue; + long numBytesInCell = stack.getTag().getLong("ic"); + used += numBytesInCell; + } + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { + if (storageCell.getKeyType() != AEKeyType.items()) + continue; + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } + } + } + + return used; + } + + public static long getUsedFluidStorage(IGridNode node) { + long used = 0; + + Iterator iterator = node.getGrid().getNodes().iterator(); + + while (iterator.hasNext()) { + if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.getItem() instanceof IBasicCellItem cell) { + if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(stack, null); + + used += cellInventory.getUsedBytes(); + } + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { + if (storageCell.getKeyType() != AEKeyType.fluids()) + continue; + if (stack.getTag() == null) + continue; + long numItemsInCell = stack.getTag().getLong("ic"); + + used += numItemsInCell; + } + } + } + + return used; + } + + public static long getUsedChemicalStorage(IGridNode node) { + long used = 0; + + if (!APAddons.appMekLoaded) + return 0; + + for (IGridNode iGridNode : node.getGrid().getMachineNodes(DriveBlockEntity.class)) { + DriveBlockEntity entity = (DriveBlockEntity) iGridNode.getService(IStorageProvider.class); + if (entity == null) + continue; + + InternalInventory inventory = entity.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.getItem() instanceof ChemicalStorageCell) { + BasicCellInventory cellInventory = BasicCellHandler.INSTANCE.getCellInventory(stack, null); + + used = cellInventory.getUsedBytes() / MekanismKeyType.TYPE.getAmountPerByte(); + } + } + } + + return used; + } + + /// Available Storage + + /** + * Calculates the available item storage on a given grid node. + * It subtracts the used item storage from the total item storage. + * + * @param node The grid node to calculate the available item storage for. + * @return The available item storage in bytes. + */ + public static long getAvailableItemStorage(IGridNode node) { + return getTotalItemStorage(node) - getUsedItemStorage(node); + } + + /** + * Calculates the available fluid storage in a given grid node. + * + * @param node The grid node to calculate the available fluid storage for. + * @return The available fluid storage in bytes. + */ + public static long getAvailableFluidStorage(IGridNode node) { + return getTotalFluidStorage(node) - getUsedFluidStorage(node); + } + + public static long getAvailableChemicalStorage(IGridNode node) { + return getTotalChemicalStorage(node) - getUsedChemicalStorage(node); + } + + /** + * Calculates the available external item storage of a given grid node. + * + * @param node The grid node for which to calculate the available external item storage. + * @return The available external item storage. + */ + public static long getAvailableExternalItemStorage(IGridNode node) { + return getTotalExternalItemStorage(node) - getUsedExternalItemStorage(node); + } + + /** + * Calculates the available external fluid storage on a given grid node by subtracting the used external fluid storage + * from the total external fluid storage. + * + * @param node The grid node on which to calculate the available external fluid storage. + * @return The available external fluid storage on the grid node. + */ + public static long getAvailableExternalFluidStorage(IGridNode node) { + return getTotalExternalFluidStorage(node) - getUsedExternalFluidStorage(node); + } + + public static long getAvailableExternalChemicalStorage(IGridNode node) { + return getTotalExternalChemicalStorage(node) - getUsedExternalChemicalStorage(node); + } + + public static ICraftingCPU getCraftingCPU(IGridNode node, String cpuName) { + if (cpuName.isEmpty()) return null; + ICraftingService grid = node.getGrid().getService(ICraftingService.class); + if (grid == null) return null; + + Iterator iterator = grid.getCpus().iterator(); + if (!iterator.hasNext()) return null; + + while (iterator.hasNext()) { + ICraftingCPU cpu = iterator.next(); + + if (cpu.getName() != null && cpu.getName().getString().equals(cpuName)) { + return cpu; + } + } + + return null; + } + + public static List listCells(IGridNode node) { + List items = new ArrayList<>(); + + Iterator iterator = node.getGrid().getNodes().iterator(); + + if (!iterator.hasNext()) return items; + while (iterator.hasNext()) { + IStorageProvider entity = iterator.next().getService(IStorageProvider.class); + if (!(entity instanceof DriveBlockEntity drive)) + continue; + + InternalInventory inventory = drive.getInternalInventory(); + + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack.isEmpty()) + continue; + + if (stack.getItem() instanceof IBasicCellItem cell) { + items.add(parseCell(cell, stack)); + } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { + items.add(getObjectFromDisk(disk, stack)); + } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { + items.add(getObjectFromSuperCell(superStorageCell, stack)); + } + } + } + + return items; + } + + private static Map getObjectFromDisk(DISKDrive drive, ItemStack stack) { + Map map = new HashMap<>(); + + map.put("item", stack.getItem().toString()); + + String cellType = ""; + + if (drive.getKeyType().toString().equals("ae2:i")) { + cellType = "item"; + } else if (drive.getKeyType().toString().equals("ae2:f")) { + cellType = "fluid"; + } + + map.put("cellType", cellType); + map.put("totalBytes", drive.getBytes(null)); + + return map; + } + + private static Map getObjectFromSuperCell(SuperStorageCell cell, ItemStack stack) { + Map map = new HashMap<>(); + + map.put("item", stack.getItem().toString()); + + String cellType = "all"; + + map.put("cellType", cellType); + map.put("totalBytes", cell.getBytes(stack)); + + return map; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AECraftJob.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AECraftJob.java new file mode 100644 index 000000000..f59291c09 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/AECraftJob.java @@ -0,0 +1,312 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.CalculationStrategy; +import appeng.api.networking.crafting.CraftingJobStatus; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingPlan; +import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.networking.crafting.ICraftingService; +import appeng.api.networking.crafting.ICraftingSimulationRequester; +import appeng.api.networking.crafting.ICraftingSubmitResult; +import appeng.api.networking.security.IActionSource; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.KeyCounter; +import appeng.me.cluster.implementations.CraftingCPUCluster; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.IComputerAccess; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.blocks.blockentities.MeBridgeEntity; +import de.srendi.advancedperipherals.common.util.BasicCraftJob; +import de.srendi.advancedperipherals.common.util.StatusConstants; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +//TODO needs to persistent - should be stored in the me bridge +// We also need to do the same for the rs bridge. So we want to create a proper interface to keep the lua functions the same +public class AECraftJob extends BasicCraftJob { + + private final IGridNode node; + private final IActionSource source; + private final ICraftingSimulationRequester simulationRequester; + private final ICraftingRequester requester; + private ICraftingCPU targetCpu; + private final AEKey toCraft; + + private Future futureJob; + private ICraftingPlan currentJob; + @Nullable + private ICraftingLink jobLink; // Job after calculation was done + // Because the properties in `CraftingJobStatus` are set when the object is created, we need to create a supplier which + // always re-fetches the object from the cpu + private Supplier jobStatus; + // In the case the job is done and would return null, we have this cached one. + private CraftingJobStatus cachedStatus; + + public AECraftJob(Level world, final IComputerAccess computer, IGridNode node, AEKey item, long amount, MeBridgeEntity bridge, ICraftingCPU target) { + super(computer, "ae", world, amount); + this.node = node; + this.source = bridge; + this.toCraft = item; + this.simulationRequester = bridge; + this.requester = bridge; + this.targetCpu = target; + } + + @LuaFunction + public final Object getCraftingCPU() { + return AEApi.parseCraftingCPU(targetCpu, true); + } + + @Nullable + public ICraftingLink getJobLink() { + return jobLink; + } + + public ICraftingCPU getTargetCpu() { + return targetCpu; + } + + public AEKey getToCraft() { + return toCraft; + } + + @Override + protected boolean isJobDone() { + return jobLink != null && jobLink.isDone(); + } + + @Override + protected boolean isJobCanceled() { + return jobLink != null && jobLink.isCanceled(); + } + + @Override + public Object getParsedRequestedItem() { + if (getJobStatus() == null) { + return null; + } + return AEApi.parseGenericStack(getJobStatus().crafting()); + } + + @Override + public long getElapsedTime() { + if (getJobStatus() == null) { + return -1; + } + return getJobStatus().elapsedTimeNanos(); + } + + @Override + public long getTotalItems() { + if (getJobStatus() == null) { + return -1; + } + return getJobStatus().totalItems(); + } + + @Override + public long getItemProgress() { + if (getJobStatus() == null) { + return -1; + } + return getJobStatus().progress(); + } + + @Override + public Object getEmittedItems() { + if (currentJob == null) { + return null; + } + return AEApi.parseKeyCounter(currentJob.emittedItems()); + } + + @Override + public Object getUsedItems() { + if (currentJob == null) { + return null; + } + return AEApi.parseKeyCounter(currentJob.usedItems()); + } + + @Override + public Object getMissingItems() { + if (currentJob == null) { + return null; + } + return AEApi.parseKeyCounter(currentJob.missingItems()); + } + + @Override + public boolean hasMultiplePaths() { + if (currentJob == null) { + return false; + } + return currentJob.multiplePaths(); + } + + @Override + public Object getFinalOutput() { + if (currentJob == null) { + return null; + } + return AEApi.parseGenericStack(currentJob.finalOutput()); + } + + @Override + public boolean cancel() { + if (targetCpu instanceof CraftingCPUCluster cluster) { + if (cluster.isBusy()) { + cluster.cancel(); + return true; + } + } + return false; + } + + @LuaFunction + public long getUsedBytes() { + if (currentJob == null) { + return -1; + } + return currentJob.bytes(); + } + + public AECraftJob withJobStatus(Supplier jobStatus) { + this.jobStatus = jobStatus; + return this; + } + + public AECraftJob withCPU(ICraftingCPU craftingCpu) { + if (this.targetCpu == null) { + this.targetCpu = craftingCpu; + } + return this; + } + + public void startCalculation() { + if (startedCalculation) { + return; + } + startedCalculation = true; + + IGrid grid = node.getGrid(); + + ICraftingService craftingService = grid.getService(ICraftingService.class); + + if (!craftingService.isCraftable(toCraft)) { + fireEvent(true, StatusConstants.NOT_CRAFTABLE); + calculationNotSuccessful = true; + return; + } + + futureJob = craftingService.beginCraftingCalculation(world, this.simulationRequester, toCraft, amount, CalculationStrategy.REPORT_MISSING_ITEMS); + fireEvent(false, StatusConstants.CALCULATION_STARTED); + } + + public void maybeCraft() { + if (startedCrafting || futureJob == null || !futureJob.isDone()) { + return; + } + ICraftingPlan job; + + try { + job = futureJob.get(); + } catch (ExecutionException | InterruptedException ex) { + AdvancedPeripherals.debug("Tried to get job, but job calculation is not done. Should be done.", org.apache.logging.log4j.Level.ERROR); + ex.printStackTrace(); + fireEvent(true, StatusConstants.UNKNOWN_ERROR); + return; + } + + if (job == null) { + AdvancedPeripherals.debug("Job is null, should not be null.", org.apache.logging.log4j.Level.ERROR); + fireEvent(true, StatusConstants.UNKNOWN_ERROR); + return; + } + this.currentJob = job; + + KeyCounter missing = job.missingItems(); + if (!missing.isEmpty()) { + fireEvent(true, StatusConstants.MISSING_ITEMS); + calculationNotSuccessful = true; + return; + } + + IGrid grid = node.getGrid(); + + ICraftingService craftingService = grid.getService(ICraftingService.class); + ICraftingSubmitResult submitResult = craftingService.submitJob(job, requester, targetCpu, false, this.source); + if (!submitResult.successful()) { + calculationNotSuccessful = true; + fireEvent(true, submitResult.errorCode().toString()); + return; + } + + this.jobLink = submitResult.link(); + this.futureJob = null; + setStartedCrafting(); + prepareCPUAndStatus(craftingService); + } + + public void jobStateChanged() { + ICraftingLink jobLink = this.jobLink; + if (jobLink == null) { + fireEvent(true, StatusConstants.UNKNOWN_ERROR); + return; + } + + if (jobLink.isCanceled() && !isJobCanceled) { + fireEvent(false, StatusConstants.JOB_CANCELED); + setJobCanceled(); + return; + } + + if (jobLink.isDone() && !isJobDone) { + fireEvent(false, StatusConstants.JOB_DONE); + setJobDone(); + } + } + + private void prepareCPUAndStatus(ICraftingService service) { + if (jobLink == null || jobStatus != null || !startedCrafting) { + return; + } + for (ICraftingCPU cpu : service.getCpus()) { + if (cpu instanceof CraftingCPUCluster cpuCluster) { + if (cpuCluster.craftingLogic.getLastLink() != null && cpuCluster.craftingLogic.getLastLink().getCraftingID().equals(jobLink.getCraftingID())) { + this.jobStatus = () -> { + // Compare the id of the job in the cpu. This job object can exist longer than the job needs time to complete. So the cpu could have a new job + if (cpuCluster.craftingLogic.getLastLink() != null && cpuCluster.craftingLogic.getLastLink().getCraftingID().equals(jobLink.getCraftingID())) + return cpuCluster.getJobStatus(); + return null; + }; + cpuCluster.craftingLogic.addListener((key) -> { + // The last time the listeners are called from the cpu logic is when the job is finished + // These listeners are not intended by ae2 to be used like this, but it works, and we don't modify the key + if (cpuCluster.getJobStatus() != null) { + this.cachedStatus = cpuCluster.getJobStatus(); + } + }); + this.targetCpu = cpu; + return; + } + } + } + AdvancedPeripherals.debug("Could not find CPU or job link even after job started", org.apache.logging.log4j.Level.WARN); + } + + private CraftingJobStatus getJobStatus() { + if (jobStatus == null || jobStatus.get() == null && cachedStatus != null) { + return cachedStatus; + } + cachedStatus = jobStatus.get(); + return jobStatus.get(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeBridgeEntityListener.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEBridgeEntityListener.java similarity index 57% rename from src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeBridgeEntityListener.java rename to src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEBridgeEntityListener.java index 1aee16c85..439caf900 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeBridgeEntityListener.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEBridgeEntityListener.java @@ -1,21 +1,20 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; +package de.srendi.advancedperipherals.common.addons.ae2; import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNodeListener; import de.srendi.advancedperipherals.common.blocks.blockentities.MeBridgeEntity; -//TODO: Maybe do something special with these methods? -public class MeBridgeEntityListener implements IGridNodeListener { +public class MEBridgeEntityListener implements IGridNodeListener { - public static final MeBridgeEntityListener INSTANCE = new MeBridgeEntityListener(); + public static final MEBridgeEntityListener INSTANCE = new MEBridgeEntityListener(); @Override public void onSecurityBreak(MeBridgeEntity nodeOwner, IGridNode node) { - + // Maybe do something special with these methods? } @Override public void onSaveChanges(MeBridgeEntity nodeOwner, IGridNode node) { - + // Maybe do something special with these methods? } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeFluidHandler.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEFluidHandler.java similarity index 77% rename from src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeFluidHandler.java rename to src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEFluidHandler.java index 8072a777d..73936fb83 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeFluidHandler.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEFluidHandler.java @@ -1,9 +1,10 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; +package de.srendi.advancedperipherals.common.addons.ae2; import appeng.api.config.Actionable; import appeng.api.networking.security.IActionSource; import appeng.api.stacks.AEFluidKey; import appeng.api.storage.MEStorage; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MEBridgePeripheral; import de.srendi.advancedperipherals.common.util.Pair; import de.srendi.advancedperipherals.common.util.inventory.FluidFilter; import de.srendi.advancedperipherals.common.util.inventory.IStorageSystemFluidHandler; @@ -12,23 +13,24 @@ /** * Used to transfer item between an inventory and the ME system. - * @see de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MeBridgePeripheral + * + * @see MEBridgePeripheral */ -public class MeFluidHandler implements IStorageSystemFluidHandler { +public class MEFluidHandler implements IStorageSystemFluidHandler { @NotNull private final MEStorage storageMonitor; @NotNull private final IActionSource actionSource; - public MeFluidHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { + public MEFluidHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { this.storageMonitor = storageMonitor; this.actionSource = actionSource; } @Override public int fill(FluidStack resource, FluidAction action) { - if(resource.isEmpty()) + if (resource.isEmpty()) return 0; AEFluidKey itemKey = AEFluidKey.of(resource.getFluid()); long inserted = storageMonitor.insert(itemKey, resource.getAmount(), action == FluidAction.SIMULATE ? Actionable.SIMULATE : Actionable.MODULATE, actionSource); @@ -39,8 +41,8 @@ public int fill(FluidStack resource, FluidAction action) { @NotNull @Override public FluidStack drain(FluidFilter filter, FluidAction simulate) { - Pair itemKey = AppEngApi.findAEFluidFromFilter(storageMonitor, null, filter); - if(itemKey == null) + Pair itemKey = AEApi.findAEFluidFromFilter(storageMonitor, null, filter); + if (itemKey == null) return FluidStack.EMPTY; long extracted = storageMonitor.extract(itemKey.getRight(), filter.getCount(), simulate == FluidAction.SIMULATE ? Actionable.SIMULATE : Actionable.MODULATE, actionSource); return new FluidStack(itemKey.getRight().getFluid(), (int) Math.min(extracted, Integer.MAX_VALUE)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeItemHandler.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEItemHandler.java similarity index 82% rename from src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeItemHandler.java rename to src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEItemHandler.java index a3542cda3..4fdc79dac 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/MeItemHandler.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/MEItemHandler.java @@ -1,9 +1,10 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; +package de.srendi.advancedperipherals.common.addons.ae2; import appeng.api.config.Actionable; import appeng.api.networking.security.IActionSource; import appeng.api.stacks.AEItemKey; import appeng.api.storage.MEStorage; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MEBridgePeripheral; import de.srendi.advancedperipherals.common.util.Pair; import de.srendi.advancedperipherals.common.util.inventory.IStorageSystemItemHandler; import de.srendi.advancedperipherals.common.util.inventory.ItemFilter; @@ -13,16 +14,16 @@ /** * Used to transfer item between an inventory and the ME system. * - * @see de.srendi.advancedperipherals.common.addons.computercraft.peripheral.MeBridgePeripheral + * @see MEBridgePeripheral */ -public class MeItemHandler implements IStorageSystemItemHandler { +public class MEItemHandler implements IStorageSystemItemHandler { @NotNull private final MEStorage storageMonitor; @NotNull private final IActionSource actionSource; - public MeItemHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { + public MEItemHandler(@NotNull MEStorage storageMonitor, @NotNull IActionSource actionSource) { this.storageMonitor = storageMonitor; this.actionSource = actionSource; } @@ -40,7 +41,7 @@ public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate @Override public ItemStack extractItem(ItemFilter filter, int count, boolean simulate) { - Pair itemKey = AppEngApi.findAEStackFromFilter(storageMonitor, null, filter); + Pair itemKey = AEApi.findAEStackFromFilter(storageMonitor, null, filter); if (itemKey.getRight() == null) return ItemStack.EMPTY; long extracted = storageMonitor.extract(itemKey.getRight(), count, simulate ? Actionable.SIMULATE : Actionable.MODULATE, actionSource); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/WiredCableP2PTunnelPart.java b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/WiredCableP2PTunnelPart.java new file mode 100644 index 000000000..596ce5e62 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/ae2/WiredCableP2PTunnelPart.java @@ -0,0 +1,174 @@ +package de.srendi.advancedperipherals.common.addons.ae2; + +import appeng.api.networking.IGridNodeListener; +import appeng.api.parts.IPartItem; +import appeng.api.parts.IPartModel; +import appeng.items.parts.PartModels; +import appeng.parts.p2p.CapabilityP2PTunnelPart; +import appeng.parts.p2p.P2PModels; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.network.wired.IWiredElement; +import dan200.computercraft.api.network.wired.IWiredNetworkChange; +import dan200.computercraft.api.network.wired.IWiredNode; +import dan200.computercraft.shared.Capabilities; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.Vec3; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; + +public class WiredCableP2PTunnelPart extends CapabilityP2PTunnelPart { + private static final P2PModels MODELS = new P2PModels(AdvancedPeripherals.getRL("part/p2p/p2p_tunnel_cable")); + + private final IWiredElement element = new P2PWiredElement(); + private final IWiredElement outElement = new P2PWiredElement(); + private final IWiredNode node = this.element.getNode(); + private Set connected = new HashSet<>(); + private boolean activated = false; + + public WiredCableP2PTunnelPart(IPartItem> partItem) { + super(partItem, Capabilities.CAPABILITY_WIRED_ELEMENT); + this.inputHandler = outElement; + this.outputHandler = outElement; + this.emptyHandler = null; // should never used + } + + @PartModels + public static List getModels() { + return MODELS.getModels(); + } + + @Override + public IPartModel getStaticModels() { + return MODELS.getModel(this.isPowered(), this.isActive()); + } + + @Override + public void onTunnelConfigChange() { + super.onTunnelConfigChange(); + this.connectionsChanged(); + } + + @Override + public void onTunnelNetworkChange() { + super.onTunnelNetworkChange(); + this.connectionsChanged(); + } + + protected void connectionsChanged() { + if (this.isClientSide()) { + return; + } + if (!this.isActive()) { + return; + } + if (!this.activated) { + this.activated = true; + this.node.connectTo(this.outElement.getNode()); + } + + Stream nodeStream = this.getOutputStream().filter(out -> out != this); + WiredCableP2PTunnelPart in = this.getInput(); + if (in != null && in != this) { + nodeStream = Stream.concat(nodeStream, Stream.of(in)); + } + Set nodes = nodeStream.collect(Collectors.toCollection(HashSet::new)); + + for (WiredCableP2PTunnelPart part : this.connected.stream().filter(n -> !nodes.contains(n)).collect(Collectors.toList())) { + if (part.connected.contains(this)) { + this.node.disconnectFrom(part.node); + part.connected.remove(this); + } + this.connected.remove(part); + } + + for (WiredCableP2PTunnelPart part : nodes) { + if (!this.connected.contains(part)) { + this.node.connectTo(part.node); + this.connected.add(part); + part.connected.add(this); + } + } + } + + @Override + protected void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + if (reason == IGridNodeListener.State.GRID_BOOT) { + return; + } + if (this.isActive()) { + if (!this.getMainNode().hasGridBooted()) { + return; + } + this.connectionsChanged(); + this.refreshConnection(); + } else if (this.activated) { + this.activated = false; + this.node.remove(); + this.connected.clear(); + } + } + + protected BlockPos getFacingPos() { + return this.getHost().getLocation().getPos().relative(this.getSide()); + } + + protected void refreshConnection() { + BlockEntity cable = this.getLevel().getBlockEntity(this.getFacingPos()); + IWiredElement elem = cable == null ? null : cable.getCapability(Capabilities.CAPABILITY_WIRED_ELEMENT, this.getSide().getOpposite()).orElse(null); + if (elem == null) { + return; + } + elem.getNode().connectTo(this.outElement.getNode()); + } + + @Override + public void onNeighborChanged(BlockGetter level, BlockPos pos, BlockPos neighbor) { + if (!this.getFacingPos().equals(neighbor)) { + return; + } + if (this.activated) { + this.refreshConnection(); + } + } + + private class P2PWiredElement implements IWiredElement { + private final IWiredNode node = ComputerCraftAPI.createWiredNodeForElement(this); + + @Nonnull + @Override + public IWiredNode getNode() { + return node; + } + + @Nonnull + @Override + public String getSenderID() { + return "p2p"; + } + + @Nonnull + @Override + public Level getLevel() { + return WiredCableP2PTunnelPart.this.getLevel(); + } + + @Nonnull + @Override + public Vec3 getPosition() { + return Vec3.atCenterOf(WiredCableP2PTunnelPart.this.getBlockEntity().getBlockPos()); + } + + @Override + public void networkChanged(IWiredNetworkChange change) {} + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/AppEngApi.java b/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/AppEngApi.java deleted file mode 100644 index 3bc0c6d8e..000000000 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/AppEngApi.java +++ /dev/null @@ -1,641 +0,0 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; - -import appeng.api.inventories.InternalInventory; -import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.CraftingJobStatus; -import appeng.api.networking.crafting.ICraftingCPU; -import appeng.api.networking.crafting.ICraftingService; -import appeng.api.networking.storage.IStorageService; -import appeng.api.stacks.*; -import appeng.api.storage.AEKeyFilter; -import appeng.api.storage.IStorageProvider; -import appeng.api.storage.MEStorage; -import appeng.api.storage.cells.IBasicCellItem; -import appeng.blockentity.storage.DriveBlockEntity; -import appeng.parts.storagebus.StorageBusPart; -import com.the9grounds.aeadditions.item.storage.StorageCell; -import com.the9grounds.aeadditions.item.storage.SuperStorageCell; -import dan200.computercraft.shared.util.NBTUtil; -import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.common.addons.APAddons; -import de.srendi.advancedperipherals.common.util.LuaConverter; -import de.srendi.advancedperipherals.common.util.Pair; -import de.srendi.advancedperipherals.common.util.inventory.FluidFilter; -import de.srendi.advancedperipherals.common.util.inventory.ItemFilter; -import de.srendi.advancedperipherals.common.util.inventory.ItemUtil; -import io.github.projectet.ae2things.item.DISKDrive; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import me.ramidzkh.mekae2.ae2.MekanismKey; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.registries.ForgeRegistries; -import org.apache.logging.log4j.Level; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class AppEngApi { - - public static Pair findAEStackFromStack(MEStorage monitor, @Nullable ICraftingService crafting, ItemStack item) { - return findAEStackFromFilter(monitor, crafting, ItemFilter.fromStack(item)); - } - - public static Pair findAEStackFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, ItemFilter item) { - for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { - if (temp.getKey() instanceof AEItemKey key && item.test(key.toStack())) - return Pair.of(temp.getLongValue(), key); - } - - if (crafting == null) - return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); - - for (var temp : crafting.getCraftables(param -> true)) { - if (temp instanceof AEItemKey key && item.test(key.toStack())) - return Pair.of(0L, key); - } - - return Pair.of(0L, AEItemKey.of(ItemStack.EMPTY)); - } - - public static Pair findAEFluidFromStack(MEStorage monitor, @Nullable ICraftingService crafting, FluidStack item) { - return findAEFluidFromFilter(monitor, crafting, FluidFilter.fromStack(item)); - } - - public static Pair findAEFluidFromFilter(MEStorage monitor, @Nullable ICraftingService crafting, FluidFilter item) { - for (Object2LongMap.Entry temp : monitor.getAvailableStacks()) { - if (temp.getKey() instanceof AEFluidKey key && item.test(key.toStack(1))) - return Pair.of(temp.getLongValue(), key); - } - - if (crafting == null) - return null; - - for (var temp : crafting.getCraftables(param -> true)) { - if (temp instanceof AEFluidKey key && item.test(key.toStack(1))) - return Pair.of(0L, key); - } - - return null; - } - - public static List listStacks(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - KeyCounter keyCounter = monitor.getAvailableStacks(); - for (Object2LongMap.Entry aeKey : keyCounter) { - if (aeKey.getKey() instanceof AEItemKey itemKey) { - items.add(getObjectFromStack(Pair.of(aeKey.getLongValue(), itemKey), service)); - } - } - return items; - } - - public static List listCraftableStacks(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - KeyCounter keyCounter = monitor.getAvailableStacks(); - Set craftables = service.getCraftables(AEKeyFilter.none()); - for (AEKey aeKey : craftables) { - if (aeKey instanceof AEItemKey) { - items.add(getObjectFromStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); - } - } - return items; - } - - public static List listFluids(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { - if (aeKey.getKey() instanceof AEFluidKey itemKey) { - items.add(getObjectFromStack(Pair.of(aeKey.getLongValue(), itemKey), service)); - } - } - return items; - } - - public static List listGases(MEStorage monitor, ICraftingService service, int flag) { - List items = new ArrayList<>(); - for (Object2LongMap.Entry aeKey : monitor.getAvailableStacks()) { - if (APAddons.appMekLoaded && aeKey.getKey() instanceof MekanismKey itemKey) { - items.add(getObjectFromStack(Pair.of(aeKey.getLongValue(), itemKey), service)); - } - } - return items; - } - - public static List listCraftableFluids(MEStorage monitor, ICraftingService service) { - List items = new ArrayList<>(); - KeyCounter keyCounter = monitor.getAvailableStacks(); - Set craftables = service.getCraftables(AEKeyFilter.none()); - for (AEKey aeKey : craftables) { - if (aeKey instanceof AEFluidKey) { - items.add(getObjectFromStack(Pair.of(keyCounter.get(aeKey), aeKey), service)); - } - } - return items; - } - - public static Map getObjectFromStack(Pair stack, @Nullable ICraftingService service) { - if (stack.getRight() == null) - return Collections.emptyMap(); - if (stack.getRight() instanceof AEItemKey itemKey) - return getObjectFromItemStack(Pair.of(stack.getLeft(), itemKey), service); - if (stack.getRight() instanceof AEFluidKey fluidKey) - return getObjectFromFluidStack(Pair.of(stack.getLeft(), fluidKey), service); - if (APAddons.appMekLoaded && (stack.getRight() instanceof MekanismKey gasKey)) - return getObjectFromGasStack(Pair.of(stack.getLeft(), gasKey), service); - - AdvancedPeripherals.debug("Could not create table from unknown stack " + stack.getRight().getClass() + " - Report this to the maintainer of ap", Level.ERROR); - return Collections.emptyMap(); - } - - private static Map getObjectFromItemStack(Pair stack, @Nullable ICraftingService craftingService) { - Map map = new HashMap<>(); - String displayName = stack.getRight().getDisplayName().getString(); - CompoundTag nbt = stack.getRight().toTag(); - long amount = stack.getLeft(); - map.put("fingerprint", ItemUtil.getFingerprint(stack.getRight().toStack())); - map.put("name", ItemUtil.getRegistryKey(stack.getRight().getItem()).toString()); - map.put("amount", amount); - map.put("displayName", displayName); - map.put("nbt", NBTUtil.toLua(nbt)); - map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getItem().builtInRegistryHolder().tags())); - map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); - - return map; - } - - private static Map getObjectFromFluidStack(Pair stack, @Nullable ICraftingService craftingService) { - Map map = new HashMap<>(); - long amount = stack.getLeft(); - map.put("name", ForgeRegistries.FLUIDS.getKey(stack.getRight().getFluid()).toString()); - map.put("amount", amount); - map.put("displayName", stack.getRight().getDisplayName().getString()); - map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getFluid().builtInRegistryHolder().tags())); - map.put("isCraftable", craftingService != null && craftingService.isCraftable(stack.getRight())); - - return map; - } - - private static Map getObjectFromGasStack(Pair stack, @Nullable ICraftingService craftingService) { - Map map = new HashMap<>(); - long amount = stack.getLeft(); - map.put("name", stack.getRight().getStack().getTypeRegistryName().toString()); - map.put("amount", amount); - map.put("displayName", stack.getRight().getDisplayName().getString()); - map.put("tags", LuaConverter.tagsToList(() -> stack.getRight().getStack().getType().getTags())); - - return map; - } - - public static Map getObjectFromCPU(ICraftingCPU cpu) { - Map map = new HashMap<>(); - long storage = cpu.getAvailableStorage(); - int coProcessors = cpu.getCoProcessors(); - boolean isBusy = cpu.isBusy(); - map.put("storage", storage); - map.put("coProcessors", coProcessors); - map.put("isBusy", isBusy); - map.put("craftingJob", cpu.getJobStatus() != null ? getObjectFromJob(cpu.getJobStatus()) : null); - map.put("name", cpu.getName() != null ? cpu.getName().getString() : "Unnamed"); - map.put("selectionMode", cpu.getSelectionMode().toString()); - - return map; - } - - public static Map getObjectFromJob(CraftingJobStatus job) { - Map map = new HashMap<>(); - map.put("storage", getObjectFromGenericStack(job.crafting())); - map.put("elapsedTimeNanos", job.elapsedTimeNanos()); - map.put("totalItem", job.totalItems()); - map.put("progress", job.progress()); - - return map; - } - - public static Map getObjectFromGenericStack(GenericStack stack) { - if (stack.what() == null) - return Collections.emptyMap(); - if (stack.what() instanceof AEItemKey aeItemKey) - return getObjectFromItemStack(Pair.of(stack.amount(), aeItemKey), null); - if (stack.what() instanceof AEFluidKey aeFluidKey) - return getObjectFromFluidStack(Pair.of(stack.amount(), aeFluidKey), null); - return Collections.emptyMap(); - } - - public static MEStorage getMonitor(IGridNode node) { - return node.getGrid().getService(IStorageService.class).getInventory(); - } - - public static boolean isItemCrafting(MEStorage monitor, ICraftingService grid, ItemFilter filter, - @Nullable ICraftingCPU craftingCPU) { - Pair stack = AppEngApi.findAEStackFromFilter(monitor, grid, filter); - - // If the item stack does not exist, it cannot be crafted. - if (stack == null) - return false; - - // If the passed cpu is null, check all cpus - if (craftingCPU == null) { - // Loop through all crafting cpus and check if the item is being crafted. - for (ICraftingCPU cpu : grid.getCpus()) { - if (cpu.isBusy()) { - CraftingJobStatus jobStatus = cpu.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - continue; - - if (jobStatus.crafting().what().equals(stack.getRight())) - return true; - } - } - } else { - if (craftingCPU.isBusy()) { - CraftingJobStatus jobStatus = craftingCPU.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - return false; - - return jobStatus.crafting().what().equals(stack.getRight()); - } - } - - return false; - } - - public static boolean isFluidCrafting(MEStorage monitor, ICraftingService grid, FluidFilter filter, - @Nullable ICraftingCPU craftingCPU) { - Pair stack = AppEngApi.findAEFluidFromFilter(monitor, grid, filter); - - // If the fluid stack does not exist, it cannot be crafted. - if (stack == null) - return false; - - // If the passed cpu is null, check all cpus - if (craftingCPU == null) { - // Loop through all crafting cpus and check if the fluid is being crafted. - for (ICraftingCPU cpu : grid.getCpus()) { - if (cpu.isBusy()) { - CraftingJobStatus jobStatus = cpu.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - continue; - - if (jobStatus.crafting().what().equals(stack.getRight())) - return true; - } - } - } else { - if (craftingCPU.isBusy()) { - CraftingJobStatus jobStatus = craftingCPU.getJobStatus(); - - // avoid null pointer exception - if (jobStatus == null) - return false; - - return jobStatus.crafting().what().equals(stack.getRight()); - } - } - - return false; - } - - public static long getTotalItemStorage(IGridNode node) { - long total = 0; - - // note: do not query DriveBlockEntity.class specifically here, because it will avoid subclasses, e.g. the ME Extended Drive from ExtendedAE - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { - total += cell.getBytes(null); - } - } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { - if (disk.getKeyType().toString().equals("ae2:i")) { - total += disk.getBytes(null); - } - } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof SuperStorageCell superStorageCell)) { - total += superStorageCell.getKiloBytes() * 1024; - } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { - if (storageCell.getKeyType() != AEKeyType.items()) - continue; - total += storageCell.getKiloBytes() * 1024; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - net.minecraft.world.level.Level level = bus.getLevel(); - BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); - BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); - if (connectedInventoryEntity == null) - continue; - - LazyOptional itemHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.ITEM_HANDLER); - if (itemHandler.isPresent()) { - IItemHandler handler = itemHandler.orElse(null); - for (int i = 0; i < handler.getSlots(); i++) { - total += handler.getSlotLimit(i); - } - } - } - - return total; - } - - public static long getTotalFluidStorage(IGridNode node) { - long total = 0; - - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { - total += cell.getBytes(null); - } - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { - total += superStorageCell.getKiloBytes() * 1024; - } else if (APAddons.aeAdditionsLoaded && (stack.getItem() instanceof StorageCell storageCell)) { - if (storageCell.getKeyType() != AEKeyType.fluids()) - continue; - total += storageCell.getKiloBytes() * 1024; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - net.minecraft.world.level.Level level = bus.getLevel(); - BlockPos connectedInventoryPos = bus.getHost().getBlockEntity().getBlockPos().relative(bus.getSide()); - BlockEntity connectedInventoryEntity = level.getBlockEntity(connectedInventoryPos); - if (connectedInventoryEntity == null) - continue; - - LazyOptional fluidHandler = connectedInventoryEntity.getCapability(ForgeCapabilities.FLUID_HANDLER); - if (fluidHandler.isPresent()) { - IFluidHandler handler = fluidHandler.orElse(null); - for (int i = 0; i < handler.getTanks(); i++) { - total += handler.getTankCapacity(i); - } - } - } - - return total; - } - - public static long getUsedItemStorage(IGridNode node) { - long used = 0; - - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - int bytesPerType = cell.getBytesPerType(null); - - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { - if (stack.getTag() == null) - continue; - int numOfType = stack.getTag().getLongArray("amts").length; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += ((int) Math.ceil(((double) numItemsInCell) / 8)) + ((long) bytesPerType * numOfType); - } - } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { - if (disk.getKeyType().toString().equals("ae2:i")) { - if (stack.getTag() == null) - continue; - long numBytesInCell = stack.getTag().getLong("ic"); - used += numBytesInCell; - } - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { - if (storageCell.getKeyType() != AEKeyType.items()) - continue; - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); - - for (Object2LongMap.Entry aeKey : keyCounter) { - if (aeKey.getKey() instanceof AEItemKey) { - used += aeKey.getLongValue(); - } - } - } - - return used; - } - - public static long getUsedFluidStorage(IGridNode node) { - long used = 0; - - Iterator iterator = node.getGrid().getNodes().iterator(); - - while (iterator.hasNext()) { - if (!(iterator.next().getService(IStorageProvider.class) instanceof DriveBlockEntity entity)) - continue; - - InternalInventory inventory = entity.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.getItem() instanceof IBasicCellItem cell) { - int bytesPerType = cell.getBytesPerType(null); - - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { - if (stack.getTag() == null) - continue; - int numOfType = stack.getTag().getLongArray("amts").length; - long numBucketsInCell = stack.getTag().getLong("ic") / 1000; - - used += ((int) Math.ceil(((double) numBucketsInCell) / 8)) + ((long) bytesPerType * numOfType); - } - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell) { - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof StorageCell storageCell) { - if (storageCell.getKeyType() != AEKeyType.fluids()) - continue; - if (stack.getTag() == null) - continue; - long numItemsInCell = stack.getTag().getLong("ic"); - - used += numItemsInCell; - } - } - } - - iterator = node.getGrid().getMachineNodes(StorageBusPart.class).iterator(); - - while (iterator.hasNext()) { - StorageBusPart bus = (StorageBusPart) iterator.next().getService(IStorageProvider.class); - KeyCounter keyCounter = bus.getInternalHandler().getAvailableStacks(); - - for (Object2LongMap.Entry aeKey : keyCounter) { - if (aeKey.getKey() instanceof AEFluidKey fluidKey) { - used += aeKey.getLongValue(); - } - } - } - - return used; - } - - public static long getAvailableItemStorage(IGridNode node) { - return getTotalItemStorage(node) - getUsedItemStorage(node); - } - - public static long getAvailableFluidStorage(IGridNode node) { - return getTotalFluidStorage(node) - getUsedFluidStorage(node); - } - - public static List listCells(IGridNode node) { - List items = new ArrayList<>(); - - Iterator iterator = node.getGrid().getNodes().iterator(); - - if (!iterator.hasNext()) return items; - while (iterator.hasNext()) { - IStorageProvider entity = iterator.next().getService(IStorageProvider.class); - if (!(entity instanceof DriveBlockEntity drive)) - continue; - - InternalInventory inventory = drive.getInternalInventory(); - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack.isEmpty()) - continue; - - if (stack.getItem() instanceof IBasicCellItem cell) { - items.add(getObjectFromCell(cell, stack)); - } else if (APAddons.aeThingsLoaded && stack.getItem() instanceof DISKDrive disk) { - items.add(getObjectFromDisk(disk, stack)); - } else if (APAddons.aeAdditionsLoaded && stack.getItem() instanceof SuperStorageCell superStorageCell) { - items.add(getObjectFromSuperCell(superStorageCell, stack)); - } - } - } - - return items; - } - - private static Map getObjectFromCell(IBasicCellItem cell, ItemStack stack) { - Map map = new HashMap<>(); - - map.put("item", ItemUtil.getRegistryKey(stack.getItem()).toString()); - - String cellType = ""; - - if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.items().getClass())) { - cellType = "item"; - } else if (cell.getKeyType().getClass().isAssignableFrom(AEKeyType.fluids().getClass())) { - cellType = "fluid"; - } - - map.put("cellType", cellType); - map.put("bytesPerType", cell.getBytesPerType(null)); - map.put("totalBytes", cell.getBytes(null)); - - return map; - } - - private static Map getObjectFromDisk(DISKDrive drive, ItemStack stack) { - Map map = new HashMap<>(); - - map.put("item", stack.getItem().toString()); - - String cellType = ""; - - if (drive.getKeyType().toString().equals("ae2:i")) { - cellType = "item"; - } else if (drive.getKeyType().toString().equals("ae2:f")) { - cellType = "fluid"; - } - - map.put("cellType", cellType); - map.put("totalBytes", drive.getBytes(null)); - - return map; - } - - private static Map getObjectFromSuperCell(SuperStorageCell cell, ItemStack stack) { - Map map = new HashMap<>(); - - map.put("item", stack.getItem().toString()); - - String cellType = "all"; - - map.put("cellType", cellType); - map.put("totalBytes", cell.getBytes(stack)); - - return map; - } -} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/CraftJob.java b/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/CraftJob.java deleted file mode 100644 index 1b2d5d9a9..000000000 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/appliedenergistics/CraftJob.java +++ /dev/null @@ -1,135 +0,0 @@ -package de.srendi.advancedperipherals.common.addons.appliedenergistics; - -import appeng.api.networking.IGrid; -import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.*; -import appeng.api.networking.security.IActionSource; -import appeng.api.stacks.AEKey; -import dan200.computercraft.api.lua.ILuaCallback; -import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.peripheral.IComputerAccess; -import de.srendi.advancedperipherals.AdvancedPeripherals; -import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -public class CraftJob implements ILuaCallback { - - public static final String EVENT = "crafting"; - - private final IComputerAccess computer; - private final IGridNode node; - private final IActionSource source; - private final ICraftingSimulationRequester requester; - private final ICraftingCPU target; - private final AEKey item; - - private final long amount; - private final Level world; - private Future futureJob; - private boolean startedCrafting = false; - - private MethodResult result; - private LuaException exception; - - public CraftJob(Level world, final IComputerAccess computer, IGridNode node, AEKey item, long amount, IActionSource source, - ICraftingSimulationRequester requester, ICraftingCPU target) { - this.computer = computer; - this.node = node; - this.world = world; - this.source = source; - this.item = item; - this.amount = amount; - this.requester = requester; - this.target = target; - } - - protected void fireEvent(boolean success, @Nullable String exception) { - this.result = MethodResult.of(success, exception); - this.exception = new LuaException(exception); - this.computer.queueEvent(EVENT, success, exception); - - } - - protected void fireNotConnected() { - fireEvent(false, "not connected"); - } - - public void setStartedCrafting(boolean startedCrafting) { - this.startedCrafting = startedCrafting; - } - - public boolean isCraftingStarted() { - return startedCrafting; - } - - public void startCrafting() { - IGrid grid = node.getGrid(); - if (grid == null) { //true when the block is not connected - fireNotConnected(); - return; - } - - ICraftingService crafting = grid.getService(ICraftingService.class); - - if (item == null) { - AdvancedPeripherals.debug("Could not get AEItem from monitor", org.apache.logging.log4j.Level.FATAL); - return; - } - - if (!crafting.isCraftable(item)) { - fireEvent(false, item.getId().toString() + " is not craftable"); - return; - } - - futureJob = crafting.beginCraftingCalculation(world, this.requester, item, amount, CalculationStrategy.REPORT_MISSING_ITEMS); - fireEvent(true, "Started calculation of the recipe. After it's finished, the system will start crafting the item."); - } - - public void maybeCraft() { - if (startedCrafting || futureJob == null || !futureJob.isDone()) - return; - ICraftingPlan job; - try { - job = futureJob.get(); - } catch (ExecutionException | InterruptedException ex) { - AdvancedPeripherals.debug("Tried to get job, but job calculation is not done. Should be done.", org.apache.logging.log4j.Level.FATAL); - ex.printStackTrace(); - return; - } - - if (job == null) { - AdvancedPeripherals.debug("Job is null, should not be null.", org.apache.logging.log4j.Level.FATAL); - return; - } - - if (job.simulation()) { - return; - } - - IGrid grid = node.getGrid(); - if (grid == null) { - return; - } - - //TODO: Create events or methods like `isCraftingFinished` or `getCraftingJobState` - ICraftingService crafting = grid.getService(ICraftingService.class); - crafting.submitJob(job, null, target, false, this.source); - - setStartedCrafting(true); - - this.futureJob = null; - } - - @NotNull - @Override - public MethodResult resume(Object[] objects) { - if (result != null) return result; - if (exception != null) return MethodResult.of(exception); - return MethodResult.of(); - } -} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java index a4eb92215..fd45750e4 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaFlowerIntegration.java @@ -16,7 +16,7 @@ public ManaFlowerIntegration(BlockEntity entity) { @NotNull @Override public String getType() { - return "manaFlower"; + return "mana_flower"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java index cea44bbe9..2d2fb83c9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/ManaPoolIntegration.java @@ -15,7 +15,7 @@ public ManaPoolIntegration(BlockEntity entity) { @NotNull @Override public String getType() { - return "manaPool"; + return "mana_pool"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java index e0ea451f9..d615db44f 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/botania/SpreaderIntegration.java @@ -16,7 +16,7 @@ public SpreaderIntegration(BlockEntity entity) { @NotNull @Override public String getType() { - return "manaSpreader"; + return "mana_spreader"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java index 09e655726..0a35755df 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/BeaconIntegration.java @@ -2,7 +2,6 @@ import dan200.computercraft.api.lua.LuaFunction; import de.srendi.advancedperipherals.lib.peripherals.BlockEntityIntegrationPeripheral; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; @@ -20,9 +19,7 @@ public BeaconIntegration(BlockEntity entity) { @LuaFunction(mainThread = true) public final int getLevel() { - // because levels are now protected field .... why? - CompoundTag savedData = blockEntity.saveWithoutMetadata(); - return savedData.getInt("Levels"); + return blockEntity.levels; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java index f5c2fef95..eaf6cda03 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java @@ -3,6 +3,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.addons.APAddons; import de.srendi.advancedperipherals.common.util.Platform; import de.srendi.advancedperipherals.lib.integrations.IPeripheralIntegration; import de.srendi.advancedperipherals.lib.peripherals.BlockEntityIntegrationPeripheral; @@ -23,7 +24,14 @@ public class IntegrationPeripheralProvider implements IPeripheralProvider { - private static final String[] SUPPORTED_MODS = new String[]{"botania", "create", "mekanism", "powah"}; + private static final String[] SUPPORTED_MODS = new String[]{ + APAddons.BOTANIA_MODID, + APAddons.CREATE_MODID, + APAddons.MEKANISM_MODID, + APAddons.POWAH_MODID, + APAddons.DIMSTORAGE_MODID, + APAddons.VALKYRIEN_SKIES_MODID, + }; private static final PriorityQueue integrations = new PriorityQueue<>(Comparator.comparingInt(IPeripheralIntegration::getPriority)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java index b86b1aa39..5ed3604c4 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SimpleFreeOperation.java @@ -7,7 +7,8 @@ import java.util.Map; public enum SimpleFreeOperation implements IPeripheralOperation { - CHAT_MESSAGE(100); + CHAT_MESSAGE(1000), + SADDLE_CAPTURE(5000); private final int defaultCooldown; private ForgeConfigSpec.IntValue cooldown; @@ -18,7 +19,7 @@ public enum SimpleFreeOperation implements IPeripheralOperation { @Override public void addToConfig(ForgeConfigSpec.Builder builder) { - cooldown = builder.defineInRange(settingsName() + "Cooldown", defaultCooldown, 1_000, Integer.MAX_VALUE); + cooldown = builder.defineInRange(settingsName() + "Cooldown", defaultCooldown, 100, Integer.MAX_VALUE); } @Override diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java index 90205db17..980c329b9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SingleOperation.java @@ -5,16 +5,20 @@ import java.util.HashMap; import java.util.Map; -import java.util.function.Function; +import java.util.function.UnaryOperator; public enum SingleOperation implements IPeripheralOperation { DIG(1000, 1), USE_ON_BLOCK(5000, 1), + UPDATE_BLOCK(500, 1), SUCK(1000, 1), USE_ON_ANIMAL(2500, 10), CAPTURE_ANIMAL(50_000, 100), WARP(1000, DistancePolicy.IGNORED, CountPolicy.MULTIPLY, 1, DistancePolicy.SQRT, CountPolicy.MULTIPLY), - ACCURE_PLACE(1000, DistancePolicy.IGNORED, CountPolicy.MULTIPLY, 1, DistancePolicy.LINEAR, CountPolicy.MULTIPLY); + ACCURE_PLACE(1000, DistancePolicy.IGNORED, CountPolicy.MULTIPLY, 1, DistancePolicy.LINEAR, CountPolicy.MULTIPLY), + PREPARE_PORTAL(3_000, 600), + ACTIVE_PORTAL(60_000, 1), + MOUNT_SHIP(1000, 1); private final int defaultCooldown; private final DistancePolicy distanceCooldownPolicy; @@ -35,7 +39,7 @@ public enum SingleOperation implements IPeripheralOperation d), SQRT(d -> (int) Math.sqrt(d)); - private final Function factorFunction; + private final UnaryOperator factorFunction; - DistancePolicy(Function factorFunction) { + DistancePolicy(UnaryOperator factorFunction) { this.factorFunction = factorFunction; } @@ -90,11 +94,12 @@ public int getFactor(int distance) { } public enum CountPolicy { + IGNORED(c -> 1), MULTIPLY(c -> c); - private final Function factorFunction; + private final UnaryOperator factorFunction; - CountPolicy(Function factorFunction) { + CountPolicy(UnaryOperator factorFunction) { this.factorFunction = factorFunction; } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java index 147b06400..54217cede 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java @@ -9,7 +9,8 @@ public enum SphereOperation implements IPeripheralOperation { SCAN_BLOCKS(2_000, 8, 16, 0.17), - SCAN_ENTITIES(2_000, 8, 16, 0.17); + SCAN_ENTITIES(2_000, 8, 16, 0.17), + SCAN_SHIPS(2_500, 8 * 3, 16 * 10 /* common view distance */, 0.17); private final int defaultCooldown; private final int defaultMaxFreeRadius; @@ -29,7 +30,7 @@ public enum SphereOperation implements IPeripheralOperation, IOwnerAbility> abilities; - public BasePeripheralOwner() { + protected BasePeripheralOwner() { abilities = new HashMap<>(); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java index 2ea0bd6a3..0a593045a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/BlockEntityPeripheralOwner.java @@ -1,7 +1,7 @@ package de.srendi.advancedperipherals.common.addons.computercraft.owner; +import dan200.computercraft.api.peripheral.IPeripheral; import de.srendi.advancedperipherals.common.blocks.base.BaseBlock; -import de.srendi.advancedperipherals.common.blocks.blockentities.InventoryManagerEntity; import de.srendi.advancedperipherals.common.util.DataStorageUtil; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralTileEntity; @@ -11,16 +11,16 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.world.Nameable; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.JigsawBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; -import java.util.function.Function; +import org.apache.commons.lang3.NotImplementedException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class BlockEntityPeripheralOwner extends BasePeripheralOwner { @@ -61,7 +61,7 @@ public BlockPos getPos() { @NotNull @Override public Direction getFacing() { - return tileEntity.getBlockState().getValue(JigsawBlock.ORIENTATION).front(); + return getOrientation().front(); } @NotNull @@ -70,11 +70,15 @@ public FrontAndTop getOrientation() { return tileEntity.getBlockState().getValue(BaseBlock.ORIENTATION); } + @Nullable + @Override + public Entity getHoldingEntity() { + return null; + } + @Nullable @Override public Player getOwner() { - if (tileEntity instanceof InventoryManagerEntity inventoryManagerEntity) - return inventoryManagerEntity.getOwnerPlayer(); return null; } @@ -90,8 +94,8 @@ public void markDataStorageDirty() { } @Override - public T1 withPlayer(Function function) { - throw new RuntimeException("Not implemented yet"); + public T1 withPlayer(APFakePlayer.Action function) { + throw new NotImplementedException(); } @Override @@ -102,7 +106,7 @@ public ItemStack getToolInMainHand() { @Override public ItemStack storeItem(ItemStack stored) { // TODO: tricks with capability needed - throw new RuntimeException("Not implemented yet"); + throw new NotImplementedException(); } @Override @@ -124,4 +128,9 @@ public BlockEntityPeripheralOwner attachFuel() { attachAbility(PeripheralOwnerAbility.FUEL, new TileEntityFuelAbility<>(this)); return this; } + + @Override + public U getConnectedPeripheral(Class type) { + throw new NotImplementedException(); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java index 07245d648..80ecdefb0 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/FuelAbility.java @@ -14,7 +14,7 @@ public abstract class FuelAbility implements IOwnerA protected @NotNull T owner; - public FuelAbility(@NotNull T owner) { + protected FuelAbility(@NotNull T owner) { this.owner = owner; } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java index c99e9442b..fc737aa5a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java @@ -1,19 +1,26 @@ package de.srendi.advancedperipherals.common.addons.computercraft.owner; +import dan200.computercraft.api.peripheral.IPeripheral; +import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.addons.valkyrienskies.ValkyrienSkies; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralOperation; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.OwnableEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import net.minecraft.world.phys.Vec3; import java.util.Collection; -import java.util.function.Function; +import java.util.HashSet; +import java.util.Set; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface IPeripheralOwner { @@ -23,17 +30,47 @@ public interface IPeripheralOwner { @NotNull BlockPos getPos(); + @NotNull + default Vec3 getCenterPos() { + return Vec3.atCenterOf(getPos()); + } + @NotNull Direction getFacing(); @NotNull FrontAndTop getOrientation(); - @Nullable Player getOwner(); + @NotNull + default Vec3 getDirection() { + Vec3 dir = Vec3.atLowerCornerOf(getFacing().getNormal()); + if (!APAddons.vs2Loaded) { + return dir; + } + return ValkyrienSkies.transformToWorldDir(getLevel(), getPos(), dir); + } + + @Nullable Entity getHoldingEntity(); + + @Nullable + default Player getOwner() { + Entity owner = getHoldingEntity(); + Set checked = new HashSet<>(); + while (owner != null && checked.add(owner)) { + if (owner instanceof Player player) { + return (Player) player; + } + if (!(owner instanceof OwnableEntity ownable)) { + break; + } + owner = ownable.getOwner(); + } + return null; + } @NotNull CompoundTag getDataStorage(); void markDataStorageDirty(); - T withPlayer(Function function); + T withPlayer(APFakePlayer.Action function); ItemStack getToolInMainHand(); @@ -64,4 +101,10 @@ default void attachOperation(Collection> operations) { for (IPeripheralOperation> operation : operations) operationAbility.registerOperation(operation); } + + T getConnectedPeripheral(Class type); + + default boolean hasConnectedPeripheral(Class extends IPeripheral> type) { + return getConnectedPeripheral(type) != null; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/InventoryManagerOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/InventoryManagerOwner.java new file mode 100644 index 000000000..c9bc48605 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/InventoryManagerOwner.java @@ -0,0 +1,17 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.owner; + +import de.srendi.advancedperipherals.common.blocks.blockentities.InventoryManagerEntity; +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.Nullable; + +public class InventoryManagerOwner extends BlockEntityPeripheralOwner { + public InventoryManagerOwner(InventoryManagerEntity tile) { + super(tile); + } + + @Nullable + @Override + public Player getOwner() { + return tileEntity.getOwnerPlayer(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java index 4f5627f5e..fefa8a5be 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PeripheralOwnerAbility.java @@ -5,6 +5,6 @@ public class PeripheralOwnerAbility { public static final PeripheralOwnerAbility> FUEL = new PeripheralOwnerAbility<>(); public static final PeripheralOwnerAbility OPERATION = new PeripheralOwnerAbility<>(); - public PeripheralOwnerAbility() { + private PeripheralOwnerAbility() { } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java index 5cd8e588c..21dc65ae6 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java @@ -1,30 +1,35 @@ package de.srendi.advancedperipherals.common.addons.computercraft.owner; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import de.srendi.advancedperipherals.common.configuration.APConfig; import de.srendi.advancedperipherals.common.util.DataStorageUtil; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; +import de.srendi.advancedperipherals.lib.peripherals.IBasePeripheral; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.apache.commons.lang3.NotImplementedException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.function.Function; - public class PocketPeripheralOwner extends BasePeripheralOwner { private final IPocketAccess pocket; + private final IPocketUpgrade upgrade; - public PocketPeripheralOwner(IPocketAccess pocket) { + public PocketPeripheralOwner(IPocketAccess pocket, IPocketUpgrade upgrade) { super(); this.pocket = pocket; - if(APConfig.PERIPHERALS_CONFIG.disablePocketFuelConsumption.get()) + this.upgrade = upgrade; + if (APConfig.PERIPHERALS_CONFIG.disablePocketFuelConsumption.get()) { attachAbility(PeripheralOwnerAbility.FUEL, new InfinitePocketFuelAbility(this)); + } } @Nullable @@ -37,48 +42,58 @@ public String getCustomName() { @Override public Level getLevel() { Entity owner = pocket.getEntity(); - if (owner == null) return null; - return owner.getCommandSenderWorld(); + return owner == null ? null : owner.getCommandSenderWorld(); } @NotNull @Override public BlockPos getPos() { Entity owner = pocket.getEntity(); - if (owner == null) return new BlockPos(0, 0, 0); - return owner.blockPosition(); + return owner == null ? BlockPos.ZERO : new BlockPos(owner.getEyePosition()); } @NotNull @Override - public Direction getFacing() { + public Vec3 getCenterPos() { Entity owner = pocket.getEntity(); - if (owner == null) return Direction.NORTH; - return owner.getDirection(); + return owner == null ? Vec3.ZERO : owner.getEyePosition(); } + @NotNull + @Override + public Direction getFacing() { + Vec3 dir = getDirection(); + return Direction.getNearest(dir.x, dir.y, dir.z); + } - /** - * Not used for pockets - */ @NotNull @Override public FrontAndTop getOrientation() { - return FrontAndTop.NORTH_UP; + Entity owner = pocket.getEntity(); + if (owner == null) { + return FrontAndTop.NORTH_UP; + } + Vec3 up = owner.getUpVector(1.0f); + return FrontAndTop.fromFrontAndTop(getFacing(), Direction.getNearest(up.x, up.y, up.z)); } - @Nullable + @NotNull @Override - public Player getOwner() { + public Vec3 getDirection() { Entity owner = pocket.getEntity(); - if (owner instanceof Player player) return player; - return null; + return owner == null ? /* North */ new Vec3(0, 0, -1) : owner.getLookAngle(); + } + + @Nullable + @Override + public Entity getHoldingEntity() { + return pocket.getEntity(); } @NotNull @Override public CompoundTag getDataStorage() { - return DataStorageUtil.getDataStorage(pocket); + return DataStorageUtil.getDataStorage(pocket, upgrade); } @Override @@ -87,8 +102,8 @@ public void markDataStorageDirty() { } @Override - public T withPlayer(Function function) { - throw new RuntimeException("Not implemented yet"); + public T withPlayer(APFakePlayer.Action function) { + throw new NotImplementedException(); } @Override @@ -98,13 +113,12 @@ public ItemStack getToolInMainHand() { @Override public ItemStack storeItem(ItemStack stored) { - // Tricks with inventory needed - throw new RuntimeException("Not implemented yet"); + throw new NotImplementedException(); } @Override public void destroyUpgrade() { - throw new RuntimeException("Not implemented yet"); + throw new NotImplementedException(); } @Override @@ -116,4 +130,18 @@ public boolean isMovementPossible(@NotNull Level level, @NotNull BlockPos pos) { public boolean move(@NotNull Level level, @NotNull BlockPos pos) { return false; } + + @Override + public T getConnectedPeripheral(Class type) { + IPeripheral foundPeripheral = pocket.getUpgrades().values().stream() + .filter(peripheral -> { + if (peripheral == null || type.isInstance(peripheral)) { + return false; + } + return peripheral instanceof IBasePeripheral basePeripheral ? basePeripheral.isEnabled() : true; + }) + .findFirst() + .orElse(null); + return (T) foundPeripheral; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java index c2709e02d..e8365fcc7 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/TurtlePeripheralOwner.java @@ -2,6 +2,7 @@ import com.mojang.authlib.GameProfile; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.TurtlePermissions; @@ -9,17 +10,20 @@ import de.srendi.advancedperipherals.common.util.DataStorageUtil; import de.srendi.advancedperipherals.common.util.fakeplayer.APFakePlayer; import de.srendi.advancedperipherals.common.util.fakeplayer.FakePlayerProviderTurtle; +import de.srendi.advancedperipherals.lib.peripherals.IBasePeripheral; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraftforge.items.wrapper.InvWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.function.Function; +import java.util.stream.Stream; public class TurtlePeripheralOwner extends BasePeripheralOwner { public final ITurtleAccess turtle; @@ -61,6 +65,12 @@ public FrontAndTop getOrientation() { return FrontAndTop.fromFrontAndTop(getFacing(), Direction.UP); } + @Nullable + @Override + public Entity getHoldingEntity() { + return null; + } + @Nullable @Override public Player getOwner() { @@ -81,7 +91,7 @@ public void markDataStorageDirty() { } @Override - public T withPlayer(Function function) { + public T withPlayer(APFakePlayer.Action function) { return FakePlayerProviderTurtle.withPlayer(turtle, function); } @@ -92,7 +102,7 @@ public ItemStack getToolInMainHand() { @Override public ItemStack storeItem(ItemStack stored) { - return InventoryUtil.storeItems(stored, turtle.getItemHandler(), turtle.getSelectedSlot()); + return InventoryUtil.storeItems(stored, new InvWrapper(turtle.getInventory()), turtle.getSelectedSlot()); } @Override @@ -131,4 +141,19 @@ public TurtlePeripheralOwner attachFuel(int maxFuelConsumptionLevel) { attachAbility(PeripheralOwnerAbility.FUEL, new TurtleFuelAbility(this, maxFuelConsumptionLevel)); return this; } + + @Override + public T getConnectedPeripheral(Class type) { + IPeripheral foundPeripheral = Stream.of(TurtleSide.values()) + .map(side -> turtle.getPeripheral(side)) + .filter(peripheral -> { + if (peripheral == null || type.isInstance(peripheral)) { + return false; + } + return peripheral instanceof IBasePeripheral basePeripheral ? basePeripheral.isEnabled() : true; + }) + .findFirst() + .orElse(null); + return (T) foundPeripheral; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BaseDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BaseDetectorPeripheral.java new file mode 100644 index 000000000..843c5554f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BaseDetectorPeripheral.java @@ -0,0 +1,42 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import dan200.computercraft.api.lua.LuaFunction; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; +import de.srendi.advancedperipherals.common.blocks.base.BaseDetectorEntity; +import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; + +public abstract class BaseDetectorPeripheral extends BasePeripheral> { + protected BaseDetectorPeripheral(String type, E tileEntity) { + super(type, new BlockEntityPeripheralOwner<>(tileEntity)); + } + + @LuaFunction + public final long getMaxTransferRate() { + return owner.tileEntity.getMaxTransferRate(); + } + + @LuaFunction + public final long getTransferRateLimit() { + return owner.tileEntity.getTransferRateLimit(); + } + + @LuaFunction + public final void setTransferRateLimit(long transferRate) { + owner.tileEntity.setTransferRateLimit(transferRate); + } + + @LuaFunction + public final long getTransferRate() { + return owner.tileEntity.getTransferRate(); + } + + @LuaFunction + public final String getLastTransferedId() { + return owner.tileEntity.getLastTransferedId(); + } + + @LuaFunction + public final String getReadyTransferId() { + return owner.tileEntity.getReadyTransferId(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java index 086fa4fe9..ce78b5077 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/BlockReaderPeripheral.java @@ -18,7 +18,7 @@ public class BlockReaderPeripheral extends BasePeripheral> { - public static final String PERIPHERAL_TYPE = "blockReader"; + public static final String PERIPHERAL_TYPE = "block_reader"; public BlockReaderPeripheral(BlockReaderEntity tileEntity) { super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java index 91f82b2e2..920f64f13 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java @@ -7,6 +7,7 @@ import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import de.srendi.advancedperipherals.AdvancedPeripherals; @@ -17,16 +18,16 @@ import de.srendi.advancedperipherals.common.blocks.base.PeripheralBlockEntity; import de.srendi.advancedperipherals.common.configuration.APConfig; import de.srendi.advancedperipherals.common.events.Events; +import de.srendi.advancedperipherals.common.network.APNetworking; +import de.srendi.advancedperipherals.common.network.toclient.ToastToClientPacket; import de.srendi.advancedperipherals.common.util.CoordUtil; import de.srendi.advancedperipherals.common.util.StringUtil; import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralFunction; -import de.srendi.advancedperipherals.network.APNetworking; -import de.srendi.advancedperipherals.network.toclient.ToastToClientPacket; import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentContents; -import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; @@ -35,7 +36,6 @@ import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; import net.minecraftforge.server.ServerLifecycleHooks; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,12 +44,12 @@ import java.util.UUID; import java.util.function.Predicate; -import static de.srendi.advancedperipherals.common.commands.APCommands.ROOT_SAFE_EXEC_LITERAL; import static de.srendi.advancedperipherals.common.addons.computercraft.operations.SimpleFreeOperation.CHAT_MESSAGE; +import static de.srendi.advancedperipherals.common.commands.APCommands.ROOT_SAFE_EXEC_LITERAL; public class ChatBoxPeripheral extends BasePeripheral { - public static final String PERIPHERAL_TYPE = "chatBox"; + public static final String PERIPHERAL_TYPE = "chat_box"; private long lastConsumedMessage; @@ -67,8 +67,8 @@ public ChatBoxPeripheral(ITurtleAccess turtle, TurtleSide side) { this(new TurtlePeripheralOwner(turtle, side)); } - public ChatBoxPeripheral(IPocketAccess pocket) { - this(new PocketPeripheralOwner(pocket)); + public ChatBoxPeripheral(IPocketAccess pocket, IPocketUpgrade upgrade) { + this(new PocketPeripheralOwner(pocket, upgrade)); } @Override @@ -251,7 +251,7 @@ public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) th if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.getLevel().dimension() != dimension) { continue; } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } } @@ -294,7 +294,7 @@ public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaE if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.getLevel().dimension() != dimension) { continue; } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } } @@ -341,7 +341,7 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } return MethodResult.of(true); @@ -399,7 +399,7 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { ToastToClientPacket packet = new ToastToClientPacket(titleComponent, preparedMessage); APNetworking.sendTo(packet, player); } @@ -438,7 +438,7 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage, false); } return MethodResult.of(true); @@ -477,7 +477,7 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getPhysicsPos(), getLevel(), player, range, maxRange)) { ToastToClientPacket packet = new ToastToClientPacket(Component.literal(title), preparedMessage); APNetworking.sendTo(packet, player); } @@ -485,6 +485,7 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw }); } + @Override public void update() { lastConsumedMessage = Events.traverseChatMessages(lastConsumedMessage, message -> { for (IComputerAccess computer : getConnectedComputers()) { diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java index 94829b12f..428574bcb 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChunkyPeripheral.java @@ -1,5 +1,6 @@ package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; @@ -44,6 +45,11 @@ public boolean isEnabled() { return APConfig.PERIPHERALS_CONFIG.enableChunkyTurtle.get(); } + @LuaFunction + public int getRadius() { + return ChunkManager.getMaxLoadRadius(); + } + public void updateChunkState() { // TODO: should find someway to update after turtle moved or while moving, but not every tick ServerLevel level = (ServerLevel) getLevel(); @@ -72,7 +78,7 @@ protected void setLoadedChunk(@Nullable ChunkPos newChunk, ChunkManager manager, } @Override - public void attach(IComputerAccess computer) { + public void attach(@NotNull IComputerAccess computer) { super.attach(computer); ServerLevel level = (ServerLevel) owner.getLevel(); ChunkManager manager = ChunkManager.get(Objects.requireNonNull(level)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java index 5a689c538..8b5a9a1e9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ColonyPeripheral.java @@ -18,6 +18,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import de.srendi.advancedperipherals.AdvancedPeripherals; import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; @@ -32,12 +33,17 @@ import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.ModList; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class ColonyPeripheral extends BasePeripheral { - public static final String PERIPHERAL_TYPE = "colonyIntegrator"; + public static final String PERIPHERAL_TYPE = "colony_integrator"; protected boolean hasPermission = true; @@ -45,8 +51,8 @@ public ColonyPeripheral(PeripheralBlockEntity> tileEntity) { super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); } - public ColonyPeripheral(IPocketAccess access) { - super(PERIPHERAL_TYPE, new PocketPeripheralOwner(access)); + public ColonyPeripheral(IPocketAccess access, IPocketUpgrade upgrade) { + super(PERIPHERAL_TYPE, new PocketPeripheralOwner(access, upgrade)); } @Override @@ -272,7 +278,7 @@ public final Object getRequests() throws LuaException { map.put("state", request.getState().toString()); map.put("count", deliverableRequest.getCount()); map.put("minCount", deliverableRequest.getMinimumCount()); - map.put("items", request.getDisplayStacks().stream().map(LuaConverter::stackToObject).collect(Collectors.toList())); + map.put("items", request.getDisplayStacks().stream().map(LuaConverter::itemStackToObject).collect(Collectors.toList())); map.put("target", request.getRequester().getRequesterDisplayName(requestManager, request).getString()); result.add(map); }); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DisabledPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DisabledPeripheral.java new file mode 100644 index 000000000..0fb89318f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DisabledPeripheral.java @@ -0,0 +1,75 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.IDynamicLuaObject; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; +import dan200.computercraft.api.peripheral.IPeripheral; + +import java.lang.reflect.Method; +import java.util.Objects; +import java.util.stream.Stream; + +public class DisabledPeripheral implements IDynamicPeripheral { + private static final MethodResult TRUE_RESULT = MethodResult.of(true); + + private final IPeripheral basePeripheral; + private final String[] methods; + + public DisabledPeripheral(IPeripheral basePeripheral) { + this.basePeripheral = basePeripheral; + Stream.Builder builder = Stream.builder(); + builder.add("peripheralDisabled"); + for (Method method : basePeripheral.getClass().getMethods()) { + LuaFunction annotation = method.getAnnotation(LuaFunction.class); + if (annotation == null) { + continue; + } + String[] names = annotation.value(); + if (names.length == 0) { + builder.add(method.getName()); + } else { + for (String name : names) { + builder.add(name); + } + } + } + Stream methodStream = builder.build(); + if (basePeripheral instanceof IDynamicPeripheral dynPeripheral) { + methodStream = Stream.concat(methodStream, Stream.of(dynPeripheral.getMethodNames())); + } + this.methods = methodStream.toArray(String[]::new); + } + + @Override + public String getType() { + return this.basePeripheral.getType(); + } + + @Override + public Object getTarget() { + return this.basePeripheral.getTarget(); + } + + @Override + public boolean equals(IPeripheral other) { + return other instanceof DisabledPeripheral disabled && this.basePeripheral.equals(disabled.basePeripheral); + } + + @Override + public String[] getMethodNames() { + return this.methods; + } + + @Override + public MethodResult callMethod(IComputerAccess computer, ILuaContext context, int method, IArguments arguments) throws LuaException { + if (method == 0) { + return TRUE_RESULT; + } + throw new LuaException("This peripheral is disabled, please contact server administrator if you want to use it"); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java new file mode 100644 index 000000000..aeba25afc --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java @@ -0,0 +1,331 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.PocketPeripheralOwner; +import de.srendi.advancedperipherals.common.blocks.blockentities.DistanceDetectorEntity; +import de.srendi.advancedperipherals.common.configuration.APConfig; +import de.srendi.advancedperipherals.common.util.HitResultUtil; +import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +public class DistanceDetectorPeripheral extends BasePeripheral { + + public static final String PERIPHERAL_TYPE = "distance_detector"; + + private final AtomicBoolean isDirty = new AtomicBoolean(false); + private final DistanceDetectorEntity tileEntity; + private final AtomicInteger maxRange; + private volatile float currentDistance; + private final AtomicBoolean showLaser; + private volatile boolean calculatePeriodically; + private volatile boolean ignoreTransparent; + private final AtomicReference detectionType; + + public DistanceDetectorPeripheral(DistanceDetectorEntity tileEntity) { + super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); + this.tileEntity = tileEntity; + this.maxRange = new AtomicInteger(Float.floatToRawIntBits(this.tileEntity.getMaxRange())); + this.currentDistance = this.tileEntity.getCurrentDistance(); + this.showLaser = new AtomicBoolean(this.tileEntity.getShowLaser()); + this.calculatePeriodically = this.tileEntity.getCalculatePeriodically(); + this.ignoreTransparent = this.tileEntity.getIgnoreTransparent(); + this.detectionType = new AtomicReference<>(this.tileEntity.getDetectionType()); + } + + protected DistanceDetectorPeripheral(IPeripheralOwner owner) { + super(PERIPHERAL_TYPE, owner); + this.tileEntity = null; + CompoundTag data = this.owner.getDataStorage(); + this.maxRange = new AtomicInteger(Float.floatToRawIntBits(data.contains("maxRange") ? data.getFloat("maxRange") : this.getConfiguredMaxRange())); + this.currentDistance = data.contains("currentDistance") ? data.getFloat("currentDistance") : -1; + this.showLaser = new AtomicBoolean(data.contains("showLaser") ? data.getBoolean("showLaser") : true); + this.calculatePeriodically = data.contains("calculatePeriodically") ? data.getBoolean("calculatePeriodically") : false; + this.ignoreTransparent = data.contains("ignoreTransparent") ? data.getBoolean("ignoreTransparent") : true; + this.detectionType = new AtomicReference<>(data.contains("detectionType") ? DetectionType.values()[data.getByte("detectionType")] : DetectionType.BOTH); + } + + public DistanceDetectorPeripheral(IPocketAccess pocket, IPocketUpgrade upgrade) { + this(new PocketPeripheralOwner(pocket, upgrade)); + } + + @Override + public boolean isEnabled() { + return APConfig.PERIPHERALS_CONFIG.enableDistanceDetector.get(); + } + + public float getConfiguredMaxRange() { + return APConfig.PERIPHERALS_CONFIG.distanceDetectorRange.get().floatValue(); + } + + public int getUpdateRate() { + return APConfig.PERIPHERALS_CONFIG.distanceDetectorUpdateRate.get(); + } + + public float getMaxRange() { + return Float.intBitsToFloat(this.maxRange.get()); + } + + public void setMaxRange(float maxRange) { + maxRange = Math.min(Math.max(maxRange, 0), this.getConfiguredMaxRange()); + int maxRangeBits = Float.floatToRawIntBits(maxRange); + if (this.maxRange.getAndSet(maxRangeBits) == maxRange) { + return; + } + if (this.tileEntity != null) { + this.tileEntity.setMaxRange(maxRange); + this.tileEntity.sendUpdate(); + } + this.isDirty.set(true); + } + + public float getCurrentDistance() { + return this.currentDistance; + } + + public void setCurrentDistance(float currentDistance) { + this.currentDistance = currentDistance; + if (this.tileEntity != null) { + this.tileEntity.setCurrentDistance(currentDistance); + this.tileEntity.sendUpdate(); + } + this.isDirty.set(true); + } + + public boolean getCalculatePeriodically() { + return this.calculatePeriodically; + } + + public void setCalculatePeriodically(boolean calculatePeriodically) { + this.calculatePeriodically = calculatePeriodically; + if (this.tileEntity != null) { + this.tileEntity.setCalculatePeriodically(calculatePeriodically); + } + this.isDirty.set(true); + } + + public boolean getShowLaser() { + return this.showLaser.get(); + } + + public void setShowLaser(boolean showLaser) { + if (this.showLaser.getAndSet(showLaser) == showLaser) { + return; + } + if (this.tileEntity != null) { + this.tileEntity.setShowLaser(showLaser); + this.tileEntity.sendUpdate(); + } + this.isDirty.set(true); + } + + public boolean getIgnoreTransparent() { + return this.ignoreTransparent; + } + + public void setIgnoreTransparent(boolean ignoreTransparent) { + this.ignoreTransparent = ignoreTransparent; + if (this.tileEntity != null) { + this.tileEntity.setIgnoreTransparent(ignoreTransparent); + } + this.isDirty.set(true); + } + + public DetectionType getDetectionType() { + return this.detectionType.get(); + } + + public void setDetectionType(DetectionType detectionType) { + if (this.detectionType.getAndSet(detectionType) == detectionType) { + return; + } + if (this.tileEntity != null) { + this.tileEntity.setDetectionType(detectionType); + } + this.isDirty.set(true); + } + + @LuaFunction + public final void setLaserVisibility(boolean laser) { + this.setShowLaser(laser); + } + + @LuaFunction + public final boolean getLaserVisibility() { + return this.getShowLaser(); + } + + @LuaFunction(value = "setIgnoreTransparency") + public final void setIgnoreTransparencyLua(boolean enable) { + this.setIgnoreTransparent(enable); + } + + @LuaFunction + public final boolean ignoresTransparency() { + return this.getIgnoreTransparent(); + } + + @LuaFunction + public final void setDetectionMode(IArguments args) throws LuaException { + Object mode = args.get(0); + if (mode == null) { + throw new LuaException("arg #1 must provide a mode name or an index between [0, 2]"); + } + DetectionType detectionType; + if (mode instanceof Number modeInd) { + int index = Math.min(Math.max(modeInd.intValue(), 0), 2); + detectionType = DetectionType.values()[index]; + } else if (mode instanceof String modeStr) { + detectionType = switch (modeStr.toUpperCase()) { + case "BLOCK" -> DetectionType.BLOCK; + case "ENTITY" -> DetectionType.ENTITY; + case "BOTH" -> DetectionType.BOTH; + default -> throw new LuaException("Unknown detection mode '" + mode + "'"); + }; + } else { + throw new LuaException("arg #1 must be a string or a number"); + } + this.setDetectionType(detectionType); + } + + @LuaFunction + public final boolean detectsEntities() { + return this.getDetectionType().detectEntity(); + } + + @LuaFunction + public final boolean detectsBlocks() { + return this.getDetectionType().detectBlock(); + } + + @LuaFunction + public final String getDetectionMode() { + return this.getDetectionType().toString(); + } + + @LuaFunction + public final double getDistance() { + return this.getCurrentDistance(); + } + + @LuaFunction(mainThread = true) + public final double calculateDistance() { + return this.calculateAndUpdateDistance(); + } + + @LuaFunction + public final boolean shouldCalculatePeriodically() { + return this.getCalculatePeriodically(); + } + + @LuaFunction(value = "setCalculatePeriodically") + public final void setCalculatePeriodicallyLua(boolean shouldCalculatePeriodically) { + this.setCalculatePeriodically(shouldCalculatePeriodically); + } + + @LuaFunction(value = "setMaxRange") + public final void setMaxRangeLua(double maxDistance) { + this.setMaxRange((float) maxDistance); + } + + @LuaFunction(value = "getMaxRange") + public final double getMaxRangeLua() { + return this.getMaxRange(); + } + + protected double calculateDistanceImpl() { + final double maxRange = this.getMaxRange(); + Vec3 direction = this.owner.getDirection(); + Vec3 center = this.getPhysicsPos(); + Vec3 from = center; + Vec3 to = from.add(direction.scale(maxRange)); + + HitResult result = this.getHitResult(from, to); + if (result.getType() == HitResult.Type.MISS) { + return -1; + } + double distance = result.getLocation().distanceTo(center); + if (this.tileEntity != null) { + distance -= 0.5; + } + return distance; + } + + /** + * calculateAndUpdateDistance should only invokes from server main thread + */ + public double calculateAndUpdateDistance() { + double distance = this.calculateDistanceImpl(); + this.setCurrentDistance((float) distance); + return distance; + } + + @Override + public void update() { + if (this.getCalculatePeriodically() && this.getLevel().getGameTime() % this.getUpdateRate() == 0) { + // We calculate the distance every 2 ticks, so we do not have to run the getDistance function of the peripheral + // on the main thread which prevents the 1 tick yield time of the function. + // The calculateDistance function is not thread safe, so we have to run it on the main thread. + // It should be okay to run that function every 2 ticks, calculating it does not take too much time. + this.calculateAndUpdateDistance(); + } + + if (this.isDirty.getAndSet(false)) { + if (this.tileEntity == null) { + CompoundTag data = this.owner.getDataStorage(); + data.putFloat("maxRange", this.getMaxRange()); + data.putFloat("currentDistance", this.getCurrentDistance()); + data.putBoolean("showLaser", this.getShowLaser()); + data.putBoolean("calculatePeriodically", this.getCalculatePeriodically()); + data.putBoolean("ignoreTransparent", this.getIgnoreTransparent()); + data.putByte("detectionType", (byte) this.getDetectionType().ordinal()); + } + this.owner.markDataStorageDirty(); + } + } + + protected HitResult getHitResult(Vec3 from, Vec3 to) { + Level level = this.getLevel(); + ClipContext.ShapeGetter shapeGetter = this.ignoreTransparent ? HitResultUtil.IgnoreNoOccludedContext.INSTANCE : ClipContext.Block.COLLIDER; + return switch (this.getDetectionType()) { + case ENTITY -> HitResultUtil.getEntityHitResult(from, to, level, this.owner.getHoldingEntity()); + case BLOCK -> HitResultUtil.getBlockHitResult(from, to, level, shapeGetter, this.getPos()); + case BOTH -> HitResultUtil.getHitResult(from, to, level, shapeGetter, this.owner); + }; + } + + public enum DetectionType { + BLOCK(true, false), + ENTITY(false, true), + BOTH(true, true); + + private final boolean block, entity; + + DetectionType(boolean block, boolean entity) { + this.block = block; + this.entity = entity; + } + + public boolean detectBlock() { + return this.block; + } + + public boolean detectEntity() { + return this.entity; + } + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java index 8b0e016f2..5aff47acd 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnergyDetectorPeripheral.java @@ -1,37 +1,18 @@ package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; -import dan200.computercraft.api.lua.LuaFunction; -import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; import de.srendi.advancedperipherals.common.blocks.blockentities.EnergyDetectorEntity; import de.srendi.advancedperipherals.common.configuration.APConfig; -import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; -public class EnergyDetectorPeripheral extends BasePeripheral> { +public class EnergyDetectorPeripheral extends BaseDetectorPeripheral { - public static final String PERIPHERAL_TYPE = "energyDetector"; + public static final String TYPE = "energy_detector"; public EnergyDetectorPeripheral(EnergyDetectorEntity tileEntity) { - super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); + super(TYPE, tileEntity); } @Override public boolean isEnabled() { return APConfig.PERIPHERALS_CONFIG.enableEnergyDetector.get(); } - - @LuaFunction(mainThread = true) - public final int getTransferRateLimit() { - return owner.tileEntity.storageProxy.getMaxTransferRate(); - } - - @LuaFunction(mainThread = true) - public final void setTransferRateLimit(long transferRate) { - transferRate = Math.max(0, Math.min(APConfig.PERIPHERALS_CONFIG.energyDetectorMaxFlow.get(), transferRate)); - owner.tileEntity.storageProxy.setMaxTransferRate((int) transferRate); - } - - @LuaFunction(mainThread = true) - public final int getTransferRate() { - return owner.tileEntity.transferRate; - } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java index f37aa156e..62db06f6a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java @@ -4,10 +4,11 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; + import de.srendi.advancedperipherals.common.addons.computercraft.operations.SphereOperationContext; import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; @@ -18,13 +19,12 @@ import de.srendi.advancedperipherals.common.util.LuaConverter; import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralPlugin; -import net.minecraft.core.BlockPos; + import net.minecraft.resources.ResourceKey; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LightLayer; @@ -32,28 +32,35 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.SleepingTimeCheckEvent; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.server.ServerLifecycleHooks; -import org.jetbrains.annotations.NotNull; - -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.function.Function; +import org.jetbrains.annotations.NotNull; import static de.srendi.advancedperipherals.common.addons.computercraft.operations.SphereOperation.SCAN_ENTITIES; public class EnvironmentDetectorPeripheral extends BasePeripheral { - public static final String PERIPHERAL_TYPE = "environmentDetector"; - private static final List> PERIPHERAL_PLUGINS = new LinkedList<>(); + public static final String PERIPHERAL_TYPE = "environment_detector"; + private static final List> PERIPHERAL_PLUGINS = new ArrayList<>(); protected EnvironmentDetectorPeripheral(IPeripheralOwner owner) { super(PERIPHERAL_TYPE, owner); owner.attachOperation(SCAN_ENTITIES); - for (Function plugin : PERIPHERAL_PLUGINS) + for (Function plugin : PERIPHERAL_PLUGINS) { addPlugin(plugin.apply(owner)); + } } public EnvironmentDetectorPeripheral(PeripheralBlockEntity> tileEntity) { @@ -64,8 +71,8 @@ public EnvironmentDetectorPeripheral(ITurtleAccess turtle, TurtleSide side) { this(new TurtlePeripheralOwner(turtle, side).attachFuel(1)); } - public EnvironmentDetectorPeripheral(IPocketAccess pocket) { - this(new PocketPeripheralOwner(pocket)); + public EnvironmentDetectorPeripheral(IPocketAccess pocket, IPocketUpgrade upgrade) { + this(new PocketPeripheralOwner(pocket, upgrade)); } private static int estimateCost(int radius) { @@ -89,24 +96,24 @@ public boolean isEnabled() { @LuaFunction(mainThread = true) public final String getBiome() { - Optional