diff --git a/build.gradle b/build.gradle index b176a7695..5829e0134 100644 --- a/build.gradle +++ b/build.gradle @@ -314,11 +314,11 @@ dependencies { compileOnly fg.deobf("com.ldtteam:domum_ornamentum:${domumornamentum_version}:universal") compileOnly fg.deobf("com.ldtteam:blockui:${blockui_version}") // IMPORTANT. This should be removed/commented 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}") + // 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}") @@ -331,8 +331,8 @@ dependencies { // 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}") + // 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}") diff --git a/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 b/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 index fe9b9c502..315f2e75d 100644 --- a/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 +++ b/src/generated/resources/.cache/67cce32b1c3cbbcb1f646605f4914e3f196986c2 @@ -1,17 +1,18 @@ -// 1.19.2 2024-05-28T14:53:16.656615 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 -4dcad851450e4ddd8d28a0017a417bf6e5579bda data/advancedperipherals/loot_tables/blocks/distance_detector.json -1d1b858d09538dc66bab2c33a2f9c58361a9c472 data/advancedperipherals/loot_tables/blocks/energy_detector.json -317004b1358ef9bf83957d2d6796529a226161c7 data/advancedperipherals/loot_tables/blocks/environment_detector.json -df6186990887f77b7db37ebb8ee50a7e7f096b0a data/advancedperipherals/loot_tables/blocks/fluid_detector.json -cea5a036d4ccdcc6ef026d1a226b5e13f1060676 data/advancedperipherals/loot_tables/blocks/gas_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 2024-07-22T18:12:14.617845 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 +e4e12e83f3fe31e9d7e751ebed1d68787af737c9 data/advancedperipherals/loot_tables/blocks/ultimate_monitor.json diff --git a/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 b/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 index 01ccc33ab..e07994eb6 100644 --- a/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 +++ b/src/generated/resources/.cache/b8526e444ae7356037f3a813274f6835d1f3dd16 @@ -1,4 +1,4 @@ -// 1.19.2 2024-05-28T14:53:16.658228 Block States: advancedperipherals +// 1.19.2 2024-07-22T22:10:50.227118 Block States: advancedperipherals 5e28ce1be9a6996d982641e5df1fa7162090b8cc assets/advancedperipherals/blockstates/block_reader.json f42bdde60f84fdb312f7cf3b2be461d9c11ebdc8 assets/advancedperipherals/blockstates/chat_box.json 1227aa092fcf1327547ace6ccc9db230e45891b0 assets/advancedperipherals/blockstates/colony_integrator.json @@ -15,6 +15,7 @@ d1fe6188b0b0ce8779cb9795a746177858cbaa41 assets/advancedperipherals/blockstates/ ff12c7217911184266589813a2c8f9b0d46cfd65 assets/advancedperipherals/blockstates/player_detector.json 726cf2599b0c765bcfacda88a1943be74f985877 assets/advancedperipherals/blockstates/redstone_integrator.json 6b176e8fdb048f7b6678bfbc1c4baf2bcfa67a1f assets/advancedperipherals/blockstates/rs_bridge.json +4b72ba2f7dfee76e138eea29f0b76c856456afca assets/advancedperipherals/blockstates/ultimate_monitor.json 544ff1ecb58622350b58940036b4b1908e1146da assets/advancedperipherals/models/block/block_reader.json fbaa69d6c98549d3f2d4a1c7bebd9b6b80d56621 assets/advancedperipherals/models/block/chat_box.json 68f9d37bd85649937150ba0bb8f4496bb2ef218d assets/advancedperipherals/models/block/colony_integrator.json @@ -31,3 +32,21 @@ f6cb0dda1ce8217563903d2dfaf5ef0297939750 assets/advancedperipherals/models/block 5a1679b4dcc8da2d8c67674216d242456bb51366 assets/advancedperipherals/models/block/player_detector.json d08b8946e1eb01cc9c8af4fa297b582614d1034b assets/advancedperipherals/models/block/redstone_integrator.json 41cf7d22016a995aeda9df9d9cbf1d4069b99f9e assets/advancedperipherals/models/block/rs_bridge.json +4d1d80c69bca9055b4cbb887f43ee6fce944d46f assets/advancedperipherals/models/block/ultimate_monitor.json +cce2709f323a71a029523533d7225dd6062b1243 assets/advancedperipherals/models/block/ultimate_monitor_d.json +db96f3c5231c785b10b37457ca104337c34acf7a assets/advancedperipherals/models/block/ultimate_monitor_item.json +1d704566dcc73c0a471a60c17e1139859f6b4087 assets/advancedperipherals/models/block/ultimate_monitor_l.json +03a49d3bebc2538c1bdbb21fc5bd3b96fe4e5be7 assets/advancedperipherals/models/block/ultimate_monitor_ld.json +987050c372fc907ae6dc9d759e693572da0d919a assets/advancedperipherals/models/block/ultimate_monitor_lr.json +1a13dca8e31d9b27f9391ed34fefa4dd1493d4cb assets/advancedperipherals/models/block/ultimate_monitor_lrd.json +9001072a7c861839313cf3e43b2628aad9a475ed assets/advancedperipherals/models/block/ultimate_monitor_lru.json +4d864eefd1a7522f5d0a73bcc35cf6557b2c421c assets/advancedperipherals/models/block/ultimate_monitor_lrud.json +82c5b1847ced8a2a2b9dd431e7a604fc03861bad assets/advancedperipherals/models/block/ultimate_monitor_lu.json +6ff46ed73c890105f2b24de9011e130658753ee1 assets/advancedperipherals/models/block/ultimate_monitor_lud.json +dbcfbec0493edfd68c64f7b0cf49157b1fded7e9 assets/advancedperipherals/models/block/ultimate_monitor_r.json +c0d0a974d391e336691058e09cb0f49c29a48c5f assets/advancedperipherals/models/block/ultimate_monitor_rd.json +63686a2dc96294e37d3129f0bb196caa77079712 assets/advancedperipherals/models/block/ultimate_monitor_ru.json +9116783ed78d59bccbf1333194ce1d633abe85d7 assets/advancedperipherals/models/block/ultimate_monitor_rud.json +c4752b33dfed1cce0d20c10ddd8250dd01fd7b3e assets/advancedperipherals/models/block/ultimate_monitor_u.json +14433cf178dc4e4c2e706f11704ef7aae46f3ae4 assets/advancedperipherals/models/block/ultimate_monitor_ud.json +fc1b1b273f7c7f9280402df88b0f8e31963f8978 assets/advancedperipherals/models/item/ultimate_monitor.json diff --git a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index ea5891f84..21fc917d5 100644 --- a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2024-05-28T14:53:16.658014 Languages: en_us -2580077212426421e05822910bde2edff88e2346 assets/advancedperipherals/lang/en_us.json +// 1.19.2 2024-07-22T18:16:05.152428 Languages: en_us +b6442b87d0f767417402f3a7c3e32438286f9ed4 assets/advancedperipherals/lang/en_us.json diff --git a/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 b/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 index 25f180a23..096763328 100644 --- a/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 +++ b/src/generated/resources/.cache/f95c7003282837dabaa33e3ffceec4e6865b5218 @@ -1,4 +1,6 @@ -// 1.19.2 2024-05-28T14:53:16.656337 Block tags +// 1.19.2 2024-07-22T18:12:14.620084 Block tags +cf893e68a6390f614a4c2c2e22f421f452754a81 data/computercraft/tags/blocks/monitor.json +cf893e68a6390f614a4c2c2e22f421f452754a81 data/forge/tags/blocks/needs_gold_tool.json e1f71dcb4f9e7e36e29b0ad09d6520dc3adfa4a6 data/forge/tags/blocks/needs_wood_tool.json -ef4684e10e5054e8cfd515dffa4a98169d281078 data/minecraft/tags/blocks/mineable/pickaxe.json +3816f0e77b104dc7cb9a3f5ac6e5c58ae645f13f data/minecraft/tags/blocks/mineable/pickaxe.json 8de9358ffeaa8d5f015774f70244a93b915427b8 data/minecraft/tags/blocks/needs_iron_tool.json diff --git a/src/generated/resources/assets/advancedperipherals/blockstates/ultimate_monitor.json b/src/generated/resources/assets/advancedperipherals/blockstates/ultimate_monitor.json new file mode 100644 index 000000000..3cbefee83 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/blockstates/ultimate_monitor.json @@ -0,0 +1,964 @@ +{ + "variants": { + "facing=east,orientation=down,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=north,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=up,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 270, + "y": 90 + }, + "facing=north,orientation=down,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=north,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=up,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 270, + "y": 0 + }, + "facing=south,orientation=down,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=north,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=up,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 270, + "y": 180 + }, + "facing=west,orientation=down,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=north,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=up,state=d": { + "model": "advancedperipherals:block/ultimate_monitor_d", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=l": { + "model": "advancedperipherals:block/ultimate_monitor_l", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ld": { + "model": "advancedperipherals:block/ultimate_monitor_ld", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lr": { + "model": "advancedperipherals:block/ultimate_monitor_lr", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lrd": { + "model": "advancedperipherals:block/ultimate_monitor_lrd", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lru": { + "model": "advancedperipherals:block/ultimate_monitor_lru", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lrud": { + "model": "advancedperipherals:block/ultimate_monitor_lrud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lu": { + "model": "advancedperipherals:block/ultimate_monitor_lu", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lud": { + "model": "advancedperipherals:block/ultimate_monitor_lud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=none": { + "model": "advancedperipherals:block/ultimate_monitor", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=r": { + "model": "advancedperipherals:block/ultimate_monitor_r", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=rd": { + "model": "advancedperipherals:block/ultimate_monitor_rd", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ru": { + "model": "advancedperipherals:block/ultimate_monitor_ru", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=rud": { + "model": "advancedperipherals:block/ultimate_monitor_rud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=u": { + "model": "advancedperipherals:block/ultimate_monitor_u", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ud": { + "model": "advancedperipherals:block/ultimate_monitor_ud", + "x": 270, + "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 4533665e0..ada534ca4 100644 --- a/src/generated/resources/assets/advancedperipherals/lang/en_us.json +++ b/src/generated/resources/assets/advancedperipherals/lang/en_us.json @@ -32,6 +32,7 @@ "block.advancedperipherals.player_detector": "Player Detector", "block.advancedperipherals.redstone_integrator": "Redstone Integrator", "block.advancedperipherals.rs_bridge": "RS Bridge", + "block.advancedperipherals.ultimate_monitor": "Ultimate Monitor", "curios.identifier.glasses": "Glasses", "entity.minecraft.villager.advancedperipherals.advancedperipherals:computer_scientist": "Computer Scientist", "item.advancedperipherals.chunk_controller": "Chunk Controller", @@ -72,6 +73,7 @@ "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.", "item.advancedperipherals.tooltip.show_desc": "&b[&7%s&b] &7For Description", + "item.advancedperipherals.tooltip.ultimate_monitor": "&7A more advanced monitor. Can identify the operator and allow lights to pass through.", "item.advancedperipherals.tooltip.weak_automata_core": "&7Upgrade for turtles, which makes turtles more useful.", "item.advancedperipherals.weak_automata_core": "Weak Automata Core", "itemGroup.advancedperipheralstab": "Advanced Peripherals", diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor.json new file mode 100644 index 000000000..8123d1396 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_16", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_d.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_d.json new file mode 100644 index 000000000..4d8a6fb2f --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_d.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_20", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_item.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_item.json new file mode 100644 index 000000000..f0ffbc99b --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_item.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_15", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_l.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_l.json new file mode 100644 index 000000000..6cd80236d --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_l.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_19", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ld.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ld.json new file mode 100644 index 000000000..cd0537521 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ld.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_31", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lr.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lr.json new file mode 100644 index 000000000..5147808d9 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lr.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_18", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lrd.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lrd.json new file mode 100644 index 000000000..503301bc0 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lrd.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_30", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lru.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lru.json new file mode 100644 index 000000000..04e1dc282 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lru.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_24", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lrud.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lrud.json new file mode 100644 index 000000000..b9a951475 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lrud.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_27", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lu.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lu.json new file mode 100644 index 000000000..63f57a3e1 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lu.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_25", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lud.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lud.json new file mode 100644 index 000000000..3e3d84a08 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_lud.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_28", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_r.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_r.json new file mode 100644 index 000000000..869fe696f --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_r.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_17", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_rd.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_rd.json new file mode 100644 index 000000000..4155d4d7e --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_rd.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_29", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ru.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ru.json new file mode 100644 index 000000000..487d97be3 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ru.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_23", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_rud.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_rud.json new file mode 100644 index 000000000..0139f2e13 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_rud.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_26", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_u.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_u.json new file mode 100644 index 000000000..8befdeb4c --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_u.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_22", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ud.json b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ud.json new file mode 100644 index 000000000..524f5fa48 --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/block/ultimate_monitor_ud.json @@ -0,0 +1,9 @@ +{ + "parent": "advancedperipherals:block/monitor_base", + "textures": { + "back": "advancedperipherals:block/transparent", + "front": "advancedperipherals:block/ultimate_monitor_21", + "side": "advancedperipherals:block/transparent", + "top": "advancedperipherals:block/transparent" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/advancedperipherals/models/item/ultimate_monitor.json b/src/generated/resources/assets/advancedperipherals/models/item/ultimate_monitor.json new file mode 100644 index 000000000..3b78001fa --- /dev/null +++ b/src/generated/resources/assets/advancedperipherals/models/item/ultimate_monitor.json @@ -0,0 +1,3 @@ +{ + "parent": "advancedperipherals:block/ultimate_monitor_item" +} \ 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 index 21855bf71..4da55fb18 100644 --- a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/distance_detector.json +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/distance_detector.json @@ -11,6 +11,12 @@ "entries": [ { "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], "name": "advancedperipherals:distance_detector" } ], 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 index 731bc1f02..a57de0eab 100644 --- a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/fluid_detector.json +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/fluid_detector.json @@ -11,6 +11,12 @@ "entries": [ { "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], "name": "advancedperipherals:fluid_detector" } ], 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 index dadeb8bc5..be3a1af68 100644 --- a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/gas_detector.json +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/gas_detector.json @@ -11,6 +11,12 @@ "entries": [ { "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], "name": "advancedperipherals:gas_detector" } ], diff --git a/src/generated/resources/data/advancedperipherals/loot_tables/blocks/ultimate_monitor.json b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/ultimate_monitor.json new file mode 100644 index 000000000..70101b63b --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/loot_tables/blocks/ultimate_monitor.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:ultimate_monitor" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/blocks/monitor.json b/src/generated/resources/data/computercraft/tags/blocks/monitor.json new file mode 100644 index 000000000..d8b92db14 --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/blocks/monitor.json @@ -0,0 +1,5 @@ +{ + "values": [ + "advancedperipherals:ultimate_monitor" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/needs_gold_tool.json b/src/generated/resources/data/forge/tags/blocks/needs_gold_tool.json new file mode 100644 index 000000000..d8b92db14 --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/needs_gold_tool.json @@ -0,0 +1,5 @@ +{ + "values": [ + "advancedperipherals:ultimate_monitor" + ] +} \ 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 8f9cf40b9..5bc92ba71 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -15,6 +15,7 @@ "advancedperipherals:geo_scanner", "advancedperipherals:colony_integrator", "advancedperipherals:nbt_storage", - "advancedperipherals:distance_detector" + "advancedperipherals:distance_detector", + "advancedperipherals:ultimate_monitor" ] } \ No newline at end of file diff --git a/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java b/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java index 8b3d01dac..5c18365ae 100644 --- a/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java +++ b/src/main/java/de/srendi/advancedperipherals/client/ClientEventSubscriber.java @@ -1,23 +1,35 @@ package de.srendi.advancedperipherals.client; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; 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.Camera; import net.minecraft.client.player.Input; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.phys.Vec3; 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.event.RenderLevelStageEvent; 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; +import java.util.ArrayList; +import java.util.List; + @Mod.EventBusSubscriber(modid = AdvancedPeripherals.MOD_ID, value = Dist.CLIENT) public class ClientEventSubscriber { + public static final Minecraft MINECRAFT = Minecraft.getInstance(); + @SubscribeEvent public static void renderingHuds(RenderGuiOverlayEvent.Pre event) { if (ClientRegistry.SADDLE_TURTLE_OVERLAY.shouldRenderFuelBar() && event.getOverlay().id().equals(VanillaGuiOverlay.EXPERIENCE_BAR.id())) { @@ -30,15 +42,14 @@ public static void renderingHuds(RenderGuiOverlayEvent.Pre event) { @SubscribeEvent public static void playerTryDismount(InputEvent.Key event) { - Minecraft minecraft = Minecraft.getInstance(); - if (!minecraft.options.keyShift.matches(event.getKey(), event.getScanCode())) { + if (!MINECRAFT.options.keyShift.matches(event.getKey(), event.getScanCode())) { return; } switch (event.getAction()) { case InputConstants.PRESS: sneaking = true; if (ClientRegistry.SADDLE_TURTLE_OVERLAY.isPlayerMountedOnTurtle()) { - minecraft.options.keyShift.setDown(false); + MINECRAFT.options.keyShift.setDown(false); } break; case InputConstants.RELEASE: @@ -52,7 +63,7 @@ public static void playerTryDismount(InputEvent.Key event) { @SubscribeEvent public static void playerMounting(EntityMountEvent event) { - if (event.isMounting() && event.getEntityMounting() == Minecraft.getInstance().player && event.getEntityBeingMounted() instanceof TurtleSeatEntity) { + if (event.isMounting() && event.getEntityMounting() == MINECRAFT.player && event.getEntityBeingMounted() instanceof TurtleSeatEntity) { // clear last key records lastInput.up = false; lastInput.down = false; @@ -81,4 +92,41 @@ public static void playerMove(MovementInputUpdateEvent event) { APNetworking.sendToServer(new SaddleTurtleControlPacket(input.up, input.down, input.left, input.right, input.jumping, sneaking)); } } + + private static final List renderers = new ArrayList<>(); + + public static void addRenderer(LazyRenderer r) { + renderers.add(r); + } + + // Reference https://github.com/mekanism/Mekanism/blob/1.19.x/src/main/java/mekanism/client/render/RenderTickHandler.java#L152 + @SubscribeEvent + public static void renderWorld(RenderLevelStageEvent event) { + if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) { + if (renderers.isEmpty()) { + return; + } + Camera camera = event.getCamera(); + PoseStack matrix = event.getPoseStack(); + MultiBufferSource buffer = MINECRAFT.renderBuffers().bufferSource(); + float partialTicks = event.getPartialTick(); + + matrix.pushPose(); + // here we translate based on the inverse position of the client viewing camera to get back to 0, 0, 0 + Vec3 camVec = camera.getPosition(); + matrix.translate(-camVec.x, -camVec.y, -camVec.z); + + renderers.forEach((r) -> { + r.render(partialTicks, matrix, buffer); + }); + renderers.clear(); + + matrix.popPose(); + } + } + + public static interface LazyRenderer { + void render(float partialTicks, PoseStack transform, MultiBufferSource bufferSource); + Vec3 getCenterPos(float partialTicks); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java b/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java index 9eaf6025f..f9d49d6e0 100644 --- a/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java +++ b/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java @@ -4,6 +4,7 @@ import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller; import de.srendi.advancedperipherals.AdvancedPeripherals; import de.srendi.advancedperipherals.client.renderer.DistanceDetectorRenderer; +import de.srendi.advancedperipherals.client.renderer.UltimateMonitorRenderer; import de.srendi.advancedperipherals.client.screens.InventoryManagerScreen; import de.srendi.advancedperipherals.client.screens.SaddleTurtleScreen; import de.srendi.advancedperipherals.client.screens.SmartGlassesScreen; @@ -66,6 +67,7 @@ public static void registeringKeymappings(RegisterKeyMappingsEvent event) { @SubscribeEvent public static void registeringRenderers(EntityRenderersEvent.RegisterRenderers event) { event.registerBlockEntityRenderer(APBlockEntityTypes.DISTANCE_DETECTOR.get(), DistanceDetectorRenderer::new); + event.registerBlockEntityRenderer(APBlockEntityTypes.ULTIMATE_MONITOR.get(), UltimateMonitorRenderer::new); } @SubscribeEvent diff --git a/src/main/java/de/srendi/advancedperipherals/client/renderer/RenderTypes.java b/src/main/java/de/srendi/advancedperipherals/client/renderer/RenderTypes.java new file mode 100644 index 000000000..0716ec02e --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/renderer/RenderTypes.java @@ -0,0 +1,117 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.client.renderer; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderStateShard; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RegisterShadersEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import javax.annotation.Nonnull; +import java.io.IOException; + +@Mod.EventBusSubscriber(modid = AdvancedPeripherals.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) +public class RenderTypes { + public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20); + + private static UltimateMonitorTextureBufferShader monitorTboShader; + + /** + * Renders a fullbright terminal. + */ + public static final RenderType TERMINAL = Types.TERMINAL; + + /** + * Renders a monitor with the TBO shader. + * + * @see UltimateMonitorTextureBufferShader + */ + public static final RenderType MONITOR_TBO = Types.MONITOR_TBO; + + /** + * A variant of {@link #TERMINAL} which uses the lightmap rather than rendering fullbright. + */ + public static final RenderType PRINTOUT_TEXT = RenderType.text( FixedWidthFontRenderer.FONT ); + + /** + * Printout's background texture. {@link RenderType#text(ResourceLocation)} is a little questionable, but + * it is what maps use, so should behave the same as vanilla in both item frames and in-hand. + */ + public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/printout.png" ) ); + + @Nonnull + static UltimateMonitorTextureBufferShader getMonitorTextureBufferShader() + { + if( monitorTboShader == null ) throw new NullPointerException( "MonitorTboShader has not been registered" ); + return monitorTboShader; + } + + @Nonnull + static ShaderInstance getTerminalShader() + { + return GameRenderer.getRendertypeTextShader(); + } + + @SubscribeEvent + public static void registerShaders( RegisterShadersEvent event ) throws IOException + { + event.registerShader( + new UltimateMonitorTextureBufferShader( + event.getResourceManager(), + new ResourceLocation( AdvancedPeripherals.MOD_ID, "monitor_tbo" ), + MONITOR_TBO.format() + ), + x -> monitorTboShader = (UltimateMonitorTextureBufferShader) x + ); + } + + private static final class Types extends RenderStateShard { + private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new TextureStateShard( + FixedWidthFontRenderer.FONT, + false, false // blur, minimap + ); + + public static final RenderType TERMINAL = RenderType.create( + "text", + DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, + VertexFormat.Mode.QUADS, + 256, + false, + true, + RenderType.CompositeState.builder() + .setShaderState(RENDERTYPE_TEXT_SHADER) + .setTextureState(TERM_FONT_TEXTURE) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setLightmapState(LIGHTMAP) + .createCompositeState(true) + ); + + static final RenderType MONITOR_TBO = RenderType.create( + "monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128, + true, true, // useDelegate, needsSorting + RenderType.CompositeState.builder() + .setTextureState(TERM_FONT_TEXTURE) + .setShaderState(new ShaderStateShard(RenderTypes::getMonitorTextureBufferShader)) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setOutputState(TRANSLUCENT_TARGET) + .createCompositeState(true) + ); + + private Types(String name, Runnable setup, Runnable destroy) { + super(name, setup, destroy); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/renderer/UltimateMonitorRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/renderer/UltimateMonitorRenderer.java new file mode 100644 index 000000000..f91e43919 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/renderer/UltimateMonitorRenderer.java @@ -0,0 +1,278 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.client.renderer; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.MemoryTracker; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import dan200.computercraft.client.util.DirectBuffers; +import dan200.computercraft.client.util.DirectVertexBuffer; +import dan200.computercraft.shared.integration.ShaderMod; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; +import dan200.computercraft.shared.util.DirectionUtil; +import de.srendi.advancedperipherals.client.ClientEventSubscriber; +import de.srendi.advancedperipherals.client.renderer.text.DirectFixedWidthFontRenderer; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor.UltimateClientMonitor; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor.UltimateMonitorEntity; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; +import net.minecraft.Util; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL31; + +import javax.annotation.Nonnull; +import java.nio.ByteBuffer; +import java.util.function.Consumer; +import java.util.function.IntFunction; + +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; + +public class UltimateMonitorRenderer implements BlockEntityRenderer { + + /** + * {@link UltimateMonitorEntity#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between + * the monitor frame and contents. + */ + private static final float MARGIN = (float) (UltimateMonitorEntity.RENDER_MARGIN * 1.1); + + private static final Matrix3f IDENTITY_NORMAL = Util.make( new Matrix3f(), Matrix3f::setIdentity ); + + private static ByteBuffer backingBuffer; + + public UltimateMonitorRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + public void render( @Nonnull UltimateMonitorEntity monitor, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource bufferSource, int lightmapCoord, int overlayLight ) { + // Render from the origin monitor + UltimateClientMonitor originTerminal = monitor.getClientMonitor(); + + if (originTerminal == null) { + return; + } + UltimateMonitorEntity origin = originTerminal.getOrigin(); + UltimateNetworkedTerminal terminal = originTerminal.getTerminal(); + float panelDepth = terminal == null ? 0 : terminal.getPanelDepth(); + BlockPos monitorPos = monitor.getBlockPos(); + // Ensure each monitor terminal is rendered only once. We allow rendering a specific tile + // multiple times in a single frame to ensure compatibility with shaders which may run a + // pass multiple times. + long renderFrame = FrameInfo.getRenderFrame(); + if (originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals(originTerminal.lastRenderPos)) { + return; + } + + originTerminal.lastRenderFrame = renderFrame; + originTerminal.lastRenderPos = monitorPos; + + BlockPos originPos = origin.getBlockPos(); + double oHeight = origin.getHeight(); + double oWidth = origin.getWidth(); + double xSize = oWidth - 2.0 * (UltimateMonitorEntity.RENDER_MARGIN + UltimateMonitorEntity.RENDER_BORDER); + double ySize = oHeight - 2.0 * (UltimateMonitorEntity.RENDER_MARGIN + UltimateMonitorEntity.RENDER_BORDER); + + // Determine orientation + Direction dir = origin.getDirection(); + Direction front = origin.getFront(); + float yaw = dir.toYRot(); + float pitch = DirectionUtil.toPitchAngle(front); + + // Setup initial transform + transform.pushPose(); + transform.translate( + originPos.getX() - monitorPos.getX() + 0.5, + originPos.getY() - monitorPos.getY() + 0.5, + originPos.getZ() - monitorPos.getZ() + 0.5 + ); + + transform.mulPose(Vector3f.YN.rotationDegrees(yaw)); + transform.mulPose(Vector3f.XP.rotationDegrees(pitch)); + transform.translate( + -0.5 + UltimateMonitorEntity.RENDER_BORDER + UltimateMonitorEntity.RENDER_MARGIN, + oHeight - 0.5 - (UltimateMonitorEntity.RENDER_BORDER + UltimateMonitorEntity.RENDER_MARGIN) + 0, + 0.5 - panelDepth + ); + + transform.pushPose(); + RenderSystem.disableCull(); + + // Draw the contents + if (terminal != null) { + // Draw a terminal + int width = terminal.getWidth(), height = terminal.getHeight(); + int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; + double xScale = xSize / pixelWidth; + double yScale = ySize / pixelHeight; + + transform.scale((float) xScale, (float) -yScale, 1.0f); + + Matrix4f matrix = transform.last().pose(); + renderTerminal( matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) ); + } else { + FixedWidthFontRenderer.drawEmptyTerminal( + FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.TERMINAL ) ), + -MARGIN, MARGIN, + (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) + ); + } + + RenderSystem.enableCull(); + transform.popPose(); + transform.popPose(); + } + + // TODO: High-priority: make the transparency works without cutting other renders behind it. + // TODO: High-priority: the renderer will ignore alpha channel (means render as a = 1) when camera is close to the panel enough and/or looking at some specific angle + private static void renderTerminal(Matrix4f matrix, UltimateClientMonitor monitor, float xMargin, float yMargin) { + UltimateNetworkedTerminal terminal = monitor.getTerminal(); + int width = terminal.getWidth(), height = terminal.getHeight(); + int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; + + MonitorRenderer renderType = MonitorRenderer.current(); + boolean redraw = monitor.pollTerminalChanged(); + if( monitor.createBuffer( renderType ) ) redraw = true; + + switch(renderType) { + case TBO: + { + if (redraw) { + var terminalBuffer = getBuffer( width * height * 3 ); + UltimateMonitorTextureBufferShader.setTerminalData( terminalBuffer, terminal ); + DirectBuffers.setBufferData( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer, terminalBuffer, GL20.GL_STATIC_DRAW ); + + var uniformBuffer = getBuffer( UltimateMonitorTextureBufferShader.UNIFORM_SIZE ); + UltimateMonitorTextureBufferShader.setUniformData( uniformBuffer, terminal ); + DirectBuffers.setBufferData( GL31.GL_UNIFORM_BUFFER, monitor.tboUniform, uniformBuffer, GL20.GL_STATIC_DRAW ); + } + + // Nobody knows what they're doing! + int active = GlStateManager._getActiveTexture(); + RenderSystem.activeTexture( UltimateMonitorTextureBufferShader.TEXTURE_INDEX ); + GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture ); + RenderSystem.activeTexture( active ); + + UltimateMonitorTextureBufferShader shader = RenderTypes.getMonitorTextureBufferShader(); + shader.setupUniform(monitor.tboUniform); + + BufferBuilder buffer = Tesselator.getInstance().getBuilder(); + buffer.begin(RenderTypes.MONITOR_TBO.mode(), RenderTypes.MONITOR_TBO.format()); + tboVertex(buffer, matrix, -xMargin, -yMargin); + tboVertex(buffer, matrix, -xMargin, pixelHeight + yMargin); + tboVertex(buffer, matrix, pixelWidth + xMargin, -yMargin); + tboVertex(buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin); + RenderTypes.MONITOR_TBO.end(buffer, 0, 0, 0); + + break; + } + + case VBO: + { + var backgroundBuffer = monitor.backgroundBuffer; + var foregroundBuffer = monitor.foregroundBuffer; + if (redraw) { + int size = DirectFixedWidthFontRenderer.getVertexCount(terminal); + + // In an ideal world we could upload these both into one buffer. However, we can't render VBOs with + // and starting and ending offset, and so need to use two buffers instead. + + renderToBuffer(backgroundBuffer, size, sink -> + DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin)); + + renderToBuffer(foregroundBuffer, size, sink -> { + DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal); + // If the cursor is visible, we append it to the end of our buffer. When rendering, we can either + // render n or n+1 quads and so toggle the cursor on and off. + DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal); + }); + } + + // Our VBO doesn't transform its vertices with the provided pose stack, which means that the inverse view + // rotation matrix gives entirely wrong numbers for fog distances. We just set it to the identity which + // gives a good enough approximation. + Matrix3f oldInverseRotation = RenderSystem.getInverseViewRotationMatrix(); + RenderSystem.setInverseViewRotationMatrix( IDENTITY_NORMAL ); + + RenderTypes.TERMINAL.setupRenderState(); + + // Render background geometry + backgroundBuffer.bind(); + backgroundBuffer.drawWithShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() ); + + // Render foreground geometry with glPolygonOffset enabled. + GL11.glPolygonOffset( -1.0f, -10.0f ); + GL11.glEnable( GL11.GL_POLYGON_OFFSET_FILL ); + + foregroundBuffer.bind(); + foregroundBuffer.drawWithShader( + matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(), + // As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each + // // quad has an index count of 6. + FixedWidthFontRenderer.isCursorVisible( terminal ) && FrameInfo.getGlobalCursorBlink() + ? foregroundBuffer.getIndexCount() + 6 : foregroundBuffer.getIndexCount() + ); + + // Clear state + GL11.glPolygonOffset( 0.0f, -0.0f ); + GL11.glDisable( GL11.GL_POLYGON_OFFSET_FILL ); + RenderTypes.TERMINAL.clearRenderState(); + VertexBuffer.unbind(); + + RenderSystem.setInverseViewRotationMatrix( oldInverseRotation ); + + break; + } + } + } + + private static DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, IntFunction makeBuffer) { + return new DirectFixedWidthFontRenderer.ByteBufferEmitter( + makeBuffer.apply(RenderTypes.TERMINAL.format().getVertexSize() * vertexCount * 4) + ); + } + + private static void renderToBuffer(DirectVertexBuffer vbo, int size, Consumer draw) { + var sink = getQuadEmitter(size, UltimateMonitorRenderer::getBuffer); + var buffer = sink.buffer(); + + draw.accept(sink); + buffer.flip(); + vbo.upload(buffer.limit() / sink.format().getVertexSize(), RenderTypes.TERMINAL.mode(), sink.format(), buffer); + } + + private static void tboVertex(VertexConsumer builder, Matrix4f matrix, float x, float y) { + // We encode position in the UV, as that's not transformed by the matrix. + builder.vertex(matrix, x, y, 0).uv(x, y).endVertex(); + } + + @Nonnull + private static ByteBuffer getBuffer(int capacity) { + ByteBuffer buffer = backingBuffer; + if (buffer == null || buffer.capacity() < capacity) { + buffer = backingBuffer = buffer == null ? MemoryTracker.create(capacity) : MemoryTracker.resize(buffer, capacity); + } + buffer.clear(); + return buffer; + } + + @Override + public int getViewDistance() { + return ComputerCraft.monitorDistance; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/renderer/UltimateMonitorTextureBufferShader.java b/src/main/java/de/srendi/advancedperipherals/client/renderer/UltimateMonitorTextureBufferShader.java new file mode 100644 index 000000000..04519bd5f --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/renderer/UltimateMonitorTextureBufferShader.java @@ -0,0 +1,124 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.client.renderer; + +import com.mojang.blaze3d.shaders.Uniform; +import com.mojang.blaze3d.vertex.VertexFormat; +import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceProvider; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL31; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.ByteBuffer; + +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.getColour; + +public class UltimateMonitorTextureBufferShader extends ShaderInstance { + public static final int UNIFORM_SIZE = 4 * 4 * 16 + 4 + 4 + 2 * 4 + 4; + + static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; + + private static final Logger LOGGER = LogManager.getLogger(); + + private final int monitorData; + private int uniformBuffer = 0; + + private final Uniform cursorBlink; + + public UltimateMonitorTextureBufferShader( ResourceProvider provider, ResourceLocation location, VertexFormat format ) throws IOException + { + super( provider, location, format ); + monitorData = GL31.glGetUniformBlockIndex( getId(), "MonitorData" ); + if( monitorData == -1 ) throw new IllegalStateException( "Could not find MonitorData uniform." ); + + cursorBlink = getUniformChecked( "CursorBlink" ); + + Uniform tbo = getUniformChecked( "Tbo" ); + if( tbo != null ) tbo.set( TEXTURE_INDEX - GL13.GL_TEXTURE0 ); + } + + public void setupUniform( int buffer ) + { + uniformBuffer = buffer; + + int cursorAlpha = FrameInfo.getGlobalCursorBlink() ? 1 : 0; + if( cursorBlink != null && cursorBlink.getIntBuffer().get( 0 ) != cursorAlpha ) cursorBlink.set( cursorAlpha ); + } + + @Override + public void apply() + { + super.apply(); + GL31.glBindBufferBase( GL31.GL_UNIFORM_BUFFER, monitorData, uniformBuffer ); + } + + @Nullable + private Uniform getUniformChecked( String name ) + { + Uniform uniform = getUniform( name ); + if( uniform == null ) + { + LOGGER.warn( "Monitor shader {} should have uniform {}, but it was not present.", getName(), name ); + } + + return uniform; + } + + public static void setTerminalData(ByteBuffer buffer, UltimateNetworkedTerminal terminal) { + int width = terminal.getWidth(), height = terminal.getHeight(); + + int pos = 0; + for( int y = 0; y < height; y++ ) + { + TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y ); + for( int x = 0; x < width; x++ ) + { + buffer.put( pos, (byte) (text.charAt( x ) & 0xFF) ); + buffer.put( pos + 1, (byte) getColour( textColour.charAt( x ), Colour.WHITE ) ); + buffer.put( pos + 2, (byte) getColour( background.charAt( x ), Colour.BLACK ) ); + pos += 3; + } + } + + buffer.limit( pos ); + } + + public static void setUniformData(ByteBuffer buffer, UltimateNetworkedTerminal terminal) { + int pos = 0; + var palette = terminal.getPalette(); + for (int i = 0; i < 16; i++) { + double[] colour = palette.getColour(i); + float alpha = terminal.getPaletteTransparency(i); + buffer + .putFloat(pos, (float) colour[0]) + .putFloat(pos + 4, (float) colour[1]) + .putFloat(pos + 8, (float) colour[2]) + .putFloat(pos + 12, alpha); + + pos += 4 * 4; // std140 requires these are 4-wide + } + + boolean showCursor = FixedWidthFontRenderer.isCursorVisible(terminal); + buffer + .putInt(pos, terminal.getWidth()) + .putInt(pos + 4, terminal.getHeight()) + .putInt(pos + 8, showCursor ? terminal.getCursorX() : -2) + .putInt(pos + 12, showCursor ? terminal.getCursorY() : -2) + .putInt(pos + 16, 15 - terminal.getTextColour()); + + buffer.limit( UNIFORM_SIZE ); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/client/renderer/text/DirectFixedWidthFontRenderer.java b/src/main/java/de/srendi/advancedperipherals/client/renderer/text/DirectFixedWidthFontRenderer.java new file mode 100644 index 000000000..f05703a90 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/client/renderer/text/DirectFixedWidthFontRenderer.java @@ -0,0 +1,274 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.client.renderer.text; + +import com.mojang.blaze3d.platform.MemoryTracker; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; +import dan200.computercraft.client.render.RenderTypes; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.Palette; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; +import org.lwjgl.system.MemoryUtil; + +import javax.annotation.Nonnull; +import java.nio.ByteBuffer; + +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*; +import static org.lwjgl.system.MemoryUtil.*; + +/** + * An optimised copy of {@link FixedWidthFontRenderer} emitter emits directly to a {@link QuadEmitter} rather than + * emitting to {@link VertexConsumer}. This allows us to emit vertices very quickly, when using the VBO renderer. + *

+ * There are some limitations here: + *

    + *
  • No transformation matrix (not needed for VBOs).
  • + *
  • Only works with {@link DefaultVertexFormat#POSITION_COLOR_TEX_LIGHTMAP}.
  • + *
  • The buffer MUST be allocated with {@link MemoryTracker}, and not through any other means.
  • + *
+ *

+ * Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate, + * it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}. + * + * IMPORTANT: When making changes to this class, please check if you need to make the same changes to + * {@link FixedWidthFontRenderer}. + */ +public final class DirectFixedWidthFontRenderer +{ + static final float WIDTH = 256.0f; + static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; + static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; + + private DirectFixedWidthFontRenderer() + { + } + + private static void drawChar( QuadEmitter emitter, float x, float y, int index, byte[] colour, int alpha ) + { + // Short circuit to avoid the common case - the texture should be blank here after all. + if( index == '\0' || index == ' ' ) return; + + int column = index % 16; + int row = index / 16; + + int xStart = 1 + column * (FONT_WIDTH + 2); + int yStart = 1 + row * (FONT_HEIGHT + 2); + + quad( + emitter, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, 0, colour, + xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, + alpha + ); + } + + private static void drawQuad(QuadEmitter emitter, float x, float y, float width, float height, UltimateNetworkedTerminal terminal, char colourIndex) { + int color = getColour(colourIndex, Colour.BLACK); + byte[] colour = terminal.getPalette().getRenderColours(color); + int alpha = terminal.getPaletteTransparencyByte(color); + quad(emitter, x, y, x + width, y + height, 0f, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, alpha); + } + + private static void drawBackground( + @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull UltimateNetworkedTerminal terminal, + float leftMarginSize, float rightMarginSize, float height + ) { + if (leftMarginSize > 0) { + drawQuad(emitter, x - leftMarginSize, y, leftMarginSize, height, terminal, backgroundColour.charAt(0)); + } + + if (rightMarginSize > 0) { + drawQuad(emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, terminal, backgroundColour.charAt(backgroundColour.length() - 1)); + } + + // Batch together runs of identical background cells. + int blockStart = 0; + char blockColour = '\0'; + for (int i = 0; i < backgroundColour.length(); i++) { + char colourIndex = backgroundColour.charAt(i); + if (colourIndex == blockColour) { + continue; + } + + if (blockColour != '\0') { + drawQuad(emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, terminal, blockColour); + } + + blockColour = colourIndex; + blockStart = i; + } + + if (blockColour != '\0') { + drawQuad(emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, terminal, blockColour); + } + } + + public static void drawString(@Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull UltimateNetworkedTerminal terminal) { + for (int i = 0; i < text.length(); i++) { + int color = getColour(textColour.charAt(i), Colour.BLACK); + byte[] colour = terminal.getPalette().getRenderColours(color); + int alpha = terminal.getPaletteTransparencyByte(color); + + int index = text.charAt(i); + if (index > 255) { + index = '?'; + } + drawChar(emitter, x + i * FONT_WIDTH, y, index, colour, alpha); + } + + } + + public static void drawTerminalForeground(@Nonnull QuadEmitter emitter, float x, float y, @Nonnull UltimateNetworkedTerminal terminal) { + int height = terminal.getHeight(); + + // The main text + for (int i = 0; i < height; i++) { + float rowY = y + FONT_HEIGHT * i; + drawString(emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i), terminal); + } + } + + public static void drawTerminalBackground( + @Nonnull QuadEmitter emitter, float x, float y, @Nonnull UltimateNetworkedTerminal terminal, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) { + int height = terminal.getHeight(); + + // Top and bottom margins + drawBackground( + emitter, x, y - topMarginSize, terminal.getBackgroundColourLine(0), terminal, + leftMarginSize, rightMarginSize, topMarginSize + ); + + drawBackground( + emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine(height - 1), terminal, + leftMarginSize, rightMarginSize, bottomMarginSize + ); + + // The main text + for (int i = 0; i < height; i++) { + float rowY = y + FONT_HEIGHT * i; + drawBackground( + emitter, x, rowY, terminal.getBackgroundColourLine(i), terminal, + leftMarginSize, rightMarginSize, FONT_HEIGHT + ); + } + } + + public static void drawCursor(@Nonnull QuadEmitter emitter, float x, float y, @Nonnull UltimateNetworkedTerminal terminal) { + if (isCursorVisible(terminal)) { + int color = 15 - terminal.getTextColour(); + byte[] colour = terminal.getPalette().getRenderColours(color); + int alpha = terminal.getPaletteTransparencyByte(color); + drawChar(emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, alpha); + } + } + + public static int getVertexCount(UltimateNetworkedTerminal terminal) { + return (terminal.getHeight() + 2) * (terminal.getWidth() + 2) * 2; + } + + private static void quad(QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int alpha) { + buffer.quad(x1, y1, x2, y2, z, rgba, u1, v1, u2, v2, alpha); + } + + public interface QuadEmitter { + VertexFormat format(); + + ByteBuffer buffer(); + + void quad(float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int alpha); + } + + public record ByteBufferEmitter(ByteBuffer buffer) implements QuadEmitter + { + @Override + public VertexFormat format() + { + return RenderTypes.TERMINAL.format(); + } + + @Override + public void quad( float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int alpha) + { + DirectFixedWidthFontRenderer.quad( buffer, x1, y1, x2, y2, z, rgba, u1, v1, u2, v2, alpha ); + } + } + + static void quad(ByteBuffer buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int alpha) { + // Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the + // underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write. + // This provides significant performance gains, at the cost of well, using Unsafe. + // Each vertex is 28 bytes, giving 112 bytes in total. Vertices are of the form (xyz:FFF)(rgba:BBBB)(uv1:FF)(uv2:SS), + // which matches the POSITION_COLOR_TEX_LIGHTMAP vertex format. + + int position = buffer.position(); + long addr = MemoryUtil.memAddress( buffer ); + + // We're doing terrible unsafe hacks below, so let's be really sure that what we're doing is reasonable. + if( position < 0 || 112 > buffer.limit() - position ) throw new IndexOutOfBoundsException(); + // Require the pointer to be aligned to a 32-bit boundary. + if( (addr & 3) != 0 ) throw new IllegalStateException( "Memory is not aligned" ); + // Also assert the length of the array. This appears to help elide bounds checks on the array in some circumstances. + if( rgba.length != 4 ) throw new IllegalStateException(); + + memPutFloat( addr + 0, x1 ); + memPutFloat( addr + 4, y1 ); + memPutFloat( addr + 8, z ); + memPutByte( addr + 12, rgba[0] ); + memPutByte( addr + 13, rgba[1] ); + memPutByte( addr + 14, rgba[2] ); + memPutByte( addr + 15, (byte)(alpha) ); + memPutFloat( addr + 16, u1 ); + memPutFloat( addr + 20, v1 ); + memPutShort( addr + 24, (short) 0xF0 ); + memPutShort( addr + 26, (short) 0xF0 ); + + memPutFloat( addr + 28, x1 ); + memPutFloat( addr + 32, y2 ); + memPutFloat( addr + 36, z ); + memPutByte( addr + 40, rgba[0] ); + memPutByte( addr + 41, rgba[1] ); + memPutByte( addr + 42, rgba[2] ); + memPutByte( addr + 43, (byte)(alpha) ); + memPutFloat( addr + 44, u1 ); + memPutFloat( addr + 48, v2 ); + memPutShort( addr + 52, (short) 0xF0 ); + memPutShort( addr + 54, (short) 0xF0 ); + + memPutFloat( addr + 56, x2 ); + memPutFloat( addr + 60, y2 ); + memPutFloat( addr + 64, z ); + memPutByte( addr + 68, rgba[0] ); + memPutByte( addr + 69, rgba[1] ); + memPutByte( addr + 70, rgba[2] ); + memPutByte( addr + 71, (byte)(alpha) ); + memPutFloat( addr + 72, u2 ); + memPutFloat( addr + 76, v2 ); + memPutShort( addr + 80, (short) 0xF0 ); + memPutShort( addr + 82, (short) 0xF0 ); + + memPutFloat( addr + 84, x2 ); + memPutFloat( addr + 88, y1 ); + memPutFloat( addr + 92, z ); + memPutByte( addr + 96, rgba[0] ); + memPutByte( addr + 97, rgba[1] ); + memPutByte( addr + 98, rgba[2] ); + memPutByte( addr + 99, (byte)(alpha) ); + memPutFloat( addr + 100, u2 ); + memPutFloat( addr + 104, v1 ); + memPutShort( addr + 108, (short) 0xF0 ); + memPutShort( addr + 110, (short) 0xF0 ); + + // Finally increment the position. + buffer.position( position + 112 ); + + // Well done for getting to the end of this method. I recommend you take a break and go look at cute puppies. + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateBlockMonitor.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateBlockMonitor.java new file mode 100644 index 000000000..db2707709 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateBlockMonitor.java @@ -0,0 +1,125 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import dan200.computercraft.shared.common.BlockGeneric; +import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState; +import de.srendi.advancedperipherals.common.blocks.base.IHarvestableBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraftforge.common.Tags; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.registries.RegistryObject; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class UltimateBlockMonitor extends BlockGeneric implements IHarvestableBlock { + public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation", + Direction.UP, Direction.DOWN, Direction.NORTH ); + + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + + public static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class ); + + public UltimateBlockMonitor( Properties settings, RegistryObject> type ) + { + super( settings, type ); + // TODO: Test underwater - do we need isSolid at all? + registerDefaultState( getStateDefinition().any() + .setValue( ORIENTATION, Direction.NORTH ) + .setValue( FACING, Direction.NORTH ) + .setValue( STATE, MonitorEdgeState.NONE ) ); + } + + @Override + public TagKey getHarvestTag() { + return Tags.Blocks.NEEDS_GOLD_TOOL; + } + + @Override + protected void createBlockStateDefinition( StateDefinition.Builder builder ) + { + builder.add( ORIENTATION, FACING, STATE ); + } + + @Nonnull + @Override + @Deprecated + public BlockState mirror( BlockState state, Mirror mirrorIn ) + { + return state.rotate( mirrorIn.getRotation( state.getValue( FACING ) ) ); + } + + @Nonnull + @Override + @Deprecated + public BlockState rotate( BlockState state, Rotation rot ) + { + return state.setValue( FACING, rot.rotate( state.getValue( FACING ) ) ); + } + + @Override + @Nullable + public BlockState getStateForPlacement( BlockPlaceContext context ) + { + float pitch = context.getPlayer() == null ? 0 : context.getPlayer().getXRot(); + Direction orientation; + if( pitch > 66.5f ) + { + // If the player is looking down, place it facing upwards + orientation = Direction.UP; + } + else if( pitch < -66.5f ) + { + // If they're looking up, place it down. + orientation = Direction.DOWN; + } + else + { + orientation = Direction.NORTH; + } + + return defaultBlockState() + .setValue( FACING, context.getHorizontalDirection().getOpposite() ) + .setValue( ORIENTATION, orientation ); + } + + @Override + public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, @Nonnull ItemStack itemStack ) + { + super.setPlacedBy( world, pos, blockState, livingEntity, itemStack ); + + BlockEntity entity = world.getBlockEntity( pos ); + if( entity instanceof UltimateMonitorEntity monitor && !world.isClientSide ) + { + // Defer the block update if we're being placed by another TE. See #691 + if( livingEntity == null || livingEntity instanceof FakePlayer ) + { + monitor.updateNeighborsDeferred(); + return; + } + + monitor.expand(); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateClientMonitor.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateClientMonitor.java new file mode 100644 index 000000000..65c8ac52c --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateClientMonitor.java @@ -0,0 +1,201 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import com.mojang.blaze3d.platform.GlStateManager; +import dan200.computercraft.client.util.DirectBuffers; +import dan200.computercraft.client.util.DirectVertexBuffer; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; +import dan200.computercraft.shared.peripheral.monitor.XYPair; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateTerminalState; +import net.minecraft.core.BlockPos; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL31; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public final class UltimateClientMonitor +{ + private static final Set allMonitors = new HashSet<>(); + + private final UltimateMonitorEntity origin; + + public long lastRenderFrame = -1; + public BlockPos lastRenderPos = null; + + public int tboBuffer; + public int tboTexture; + public int tboUniform; + public DirectVertexBuffer backgroundBuffer; + public DirectVertexBuffer foregroundBuffer; + private UltimateNetworkedTerminal terminal; + private boolean terminalChanged; + + public UltimateClientMonitor( UltimateMonitorEntity origin ) + { + this.origin = origin; + } + + public UltimateMonitorEntity getOrigin() + { + return origin; + } + + /** + * Create the appropriate buffer if needed. + * + * @param renderer The renderer to use. This can be fetched from {@link MonitorRenderer#current()}. + * @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer, + * or this mode does not require one. + */ + @OnlyIn( Dist.CLIENT ) + public boolean createBuffer( MonitorRenderer renderer ) + { + switch( renderer ) + { + case TBO: + { + if( tboBuffer != 0 ) return false; + + deleteBuffers(); + + tboBuffer = DirectBuffers.createBuffer(); + DirectBuffers.setEmptyBufferData( GL31.GL_TEXTURE_BUFFER, tboBuffer, GL15.GL_STATIC_DRAW ); + tboTexture = GlStateManager._genTexture(); + GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture ); + GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, tboBuffer ); + GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 ); + + tboUniform = DirectBuffers.createBuffer(); + DirectBuffers.setEmptyBufferData( GL31.GL_UNIFORM_BUFFER, tboUniform, GL15.GL_STATIC_DRAW ); + + addMonitor(); + return true; + } + + case VBO: + if( backgroundBuffer != null ) return false; + + deleteBuffers(); + backgroundBuffer = new DirectVertexBuffer(); + foregroundBuffer = new DirectVertexBuffer(); + addMonitor(); + return true; + + default: + return false; + } + } + + private void addMonitor() + { + synchronized( allMonitors ) + { + allMonitors.add( this ); + } + } + + private void deleteBuffers() + { + + if( tboBuffer != 0 ) + { + DirectBuffers.deleteBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer ); + tboBuffer = 0; + } + + if( tboTexture != 0 ) + { + GlStateManager._deleteTexture( tboTexture ); + tboTexture = 0; + } + + if( tboUniform != 0 ) + { + DirectBuffers.deleteBuffer( GL31.GL_UNIFORM_BUFFER, tboUniform ); + tboUniform = 0; + } + + if( backgroundBuffer != null ) + { + backgroundBuffer.close(); + backgroundBuffer = null; + } + + if( foregroundBuffer != null ) + { + foregroundBuffer.close(); + foregroundBuffer = null; + } + } + + @OnlyIn( Dist.CLIENT ) + public void destroy() + { + if( tboBuffer != 0 || backgroundBuffer != null ) + { + synchronized( allMonitors ) + { + allMonitors.remove( this ); + } + + deleteBuffers(); + } + } + + @OnlyIn( Dist.CLIENT ) + public static void destroyAll() + { + synchronized( allMonitors ) + { + for( Iterator iterator = allMonitors.iterator(); iterator.hasNext(); ) + { + UltimateClientMonitor monitor = iterator.next(); + monitor.deleteBuffers(); + + iterator.remove(); + } + } + } + + public boolean pollTerminalChanged() + { + boolean changed = terminalChanged; + terminalChanged = false; + return changed; + } + + public UltimateNetworkedTerminal getTerminal() + { + return terminal; + } + + void read( UltimateTerminalState state ) + { + if( state.hasTerminal() ) + { + if( terminal == null ) terminal = new UltimateNetworkedTerminal( state.width, state.height ); + state.apply( terminal ); + terminalChanged = true; + } + else + { + if( terminal != null ) + { + terminal = null; + terminalChanged = true; + } + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateExpander.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateExpander.java new file mode 100644 index 000000000..0907a3c2d --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateExpander.java @@ -0,0 +1,111 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import dan200.computercraft.ComputerCraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + +import java.util.Objects; + +/** + * Expands a monitor into available space. This tries to expand in each direction until a fixed point is reached. + */ +class UltimateExpander +{ + private final Level level; + private final Direction down; + private final Direction right; + + private UltimateMonitorEntity origin; + private int width; + private int height; + + UltimateExpander( UltimateMonitorEntity origin ) + { + this.origin = origin; + width = origin.getWidth(); + height = origin.getHeight(); + + level = Objects.requireNonNull( origin.getLevel(), "level cannot be null" ); + down = origin.getDown(); + right = origin.getRight(); + } + + void expand() + { + int changedCount = 0; + + // Impose a limit on the number of resizes we can attempt. There's a risk of getting into an infinite loop + // if we merge right/down and the next monitor has a width/height of 0. This /should/ never happen - validation + // will catch it - but I also have a complete lack of faith in the code. + // As an aside, I think the actual limit is width+height resizes, but again - complete lack of faith. + int changeLimit = ComputerCraft.monitorWidth * ComputerCraft.monitorHeight + 1; + while( expandIn( true, false ) || expandIn( true, true ) || + expandIn( false, false ) || expandIn( false, true ) + ) + { + changedCount++; + if( changedCount > changeLimit ) + { + ComputerCraft.log.error( "Monitor has grown too much. This suggests there's an empty monitor in the world." ); + break; + } + } + + if( changedCount > 0 ) origin.resize( width, height ); + } + + /** + * Attempt to expand a monitor in a particular direction as much as possible. + * + * @param useXAxis {@literal true} if we're expanding on the X Axis, {@literal false} if on the Y. + * @param isPositive {@literal true} if we're expanding in the positive direction, {@literal false} if negative. + * @return If the monitor changed. + */ + private boolean expandIn( boolean useXAxis, boolean isPositive ) + { + BlockPos pos = origin.getBlockPos(); + int height = this.height, width = this.width; + + int otherOffset = isPositive ? (useXAxis ? width : height) : -1; + BlockPos otherPos = useXAxis ? pos.relative( right, otherOffset ) : pos.relative( down, otherOffset ); + BlockEntity other = level.getBlockEntity( otherPos ); + if( !(other instanceof UltimateMonitorEntity otherMonitor) || !origin.isCompatible( otherMonitor ) ) return false; + + if( useXAxis ) + { + if( otherMonitor.getYIndex() != 0 || otherMonitor.getHeight() != height ) return false; + width += otherMonitor.getWidth(); + if( width > ComputerCraft.monitorWidth ) return false; + } + else + { + if( otherMonitor.getXIndex() != 0 || otherMonitor.getWidth() != width ) return false; + height += otherMonitor.getHeight(); + if( height > ComputerCraft.monitorHeight ) return false; + } + + if( !isPositive ) + { + BlockEntity otherOrigin = level.getBlockEntity( otherMonitor.toWorldPos( 0, 0 ) ); + if( !(otherOrigin instanceof UltimateMonitorEntity originMonitor) || !origin.isCompatible( originMonitor ) ) + { + return false; + } + + origin = originMonitor; + } + + this.width = width; + this.height = height; + + return true; + } + +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorEntity.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorEntity.java new file mode 100644 index 000000000..b9a555fb3 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorEntity.java @@ -0,0 +1,662 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import com.google.common.annotations.VisibleForTesting; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState; +import dan200.computercraft.shared.peripheral.monitor.XYPair; +import dan200.computercraft.shared.util.CapabilityUtil; +import dan200.computercraft.shared.util.TickScheduler; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateTerminalState; +import de.srendi.advancedperipherals.common.setup.APBlockEntityTypes; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; + +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + +public class UltimateMonitorEntity extends TileGeneric { + public static final double RENDER_BORDER = 2.0 / 16.0; + public static final double RENDER_MARGIN = 0.5 / 16.0; + public static final double RENDER_PIXEL_SCALE = 1.0 / 64.0; + + private static final String NBT_X = "XIndex"; + private static final String NBT_Y = "YIndex"; + private static final String NBT_WIDTH = "Width"; + private static final String NBT_HEIGHT = "Height"; + + private UltimateServerMonitor serverMonitor; + private UltimateClientMonitor clientMonitor; + private UltimateMonitorPeripheral peripheral; + private LazyOptional peripheralCap; + private final Set computers = new HashSet<>(); + + private boolean needsUpdate = false; + private boolean needsValidating = false; + private boolean destroyed = false; + + // MonitorWatcher state. + boolean enqueued; + UltimateTerminalState cached; + + private int width = 1; + private int height = 1; + private int xIndex = 0; + private int yIndex = 0; + + private BlockPos bbPos; + private BlockState bbState; + private int bbX, bbY, bbWidth, bbHeight; + private AABB boundingBox; + + TickScheduler.Token tickToken = new TickScheduler.Token( this ); + + public UltimateMonitorEntity( BlockPos pos, BlockState state ) + { + super( APBlockEntityTypes.ULTIMATE_MONITOR.get(), pos, state ); + } + + @Override + public void clearRemoved() // TODO: Switch back to onLood + { + super.clearRemoved(); + needsValidating = true; // Same, tbh + TickScheduler.schedule( tickToken ); + } + + @Override + public void destroy() + { + // TODO: Call this before using the block + if( destroyed ) return; + destroyed = true; + if( !getLevel().isClientSide ) contractNeighbours(); + } + + @Override + public void setRemoved() + { + super.setRemoved(); + if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) clientMonitor.destroy(); + } + + @Override + public void onChunkUnloaded() + { + super.onChunkUnloaded(); + if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) clientMonitor.destroy(); + } + + @Nonnull + @Override + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) + { + if( !player.isCrouching() && getFront() == hit.getDirection() ) + { + if( !getLevel().isClientSide ) + { + monitorTouched( + (float) (hit.getLocation().x - hit.getBlockPos().getX()), + (float) (hit.getLocation().y - hit.getBlockPos().getY()), + (float) (hit.getLocation().z - hit.getBlockPos().getZ()), + player + ); + } + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + @Override + public void saveAdditional( CompoundTag tag ) + { + tag.putInt( NBT_X, xIndex ); + tag.putInt( NBT_Y, yIndex ); + tag.putInt( NBT_WIDTH, width ); + tag.putInt( NBT_HEIGHT, height ); + super.saveAdditional( tag ); + } + + @Override + public void load( @Nonnull CompoundTag nbt ) + { + super.load( nbt ); + + xIndex = nbt.getInt( NBT_X ); + yIndex = nbt.getInt( NBT_Y ); + width = nbt.getInt( NBT_WIDTH ); + height = nbt.getInt( NBT_HEIGHT ); + } + + @Override + public void blockTick() + { + if( needsValidating ) + { + needsValidating = false; + validate(); + } + + if( needsUpdate ) + { + needsUpdate = false; + expand(); + } + + if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return; + + if( serverMonitor.pollResized() ) eachComputer( c -> c.queueEvent( "monitor_resize", c.getAttachmentName() ) ); + if( serverMonitor.pollTerminalChanged() ) UltimateMonitorWatcher.enqueue( this ); + } + + @Override + public void invalidateCaps() + { + super.invalidateCaps(); + peripheralCap = CapabilityUtil.invalidate( peripheralCap ); + } + + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) + { + if( cap == CAPABILITY_PERIPHERAL ) + { + createServerMonitor(); // Ensure the monitor is created before doing anything else. + if( peripheral == null ) peripheral = new UltimateMonitorPeripheral( this ); + if( peripheralCap == null ) peripheralCap = LazyOptional.of( () -> peripheral ); + return peripheralCap.cast(); + } + return super.getCapability( cap, side ); + } + + @Nullable + @VisibleForTesting + public UltimateServerMonitor getCachedServerMonitor() + { + return serverMonitor; + } + + @Nullable + private UltimateServerMonitor getServerMonitor() + { + if( serverMonitor != null ) return serverMonitor; + + UltimateMonitorEntity origin = getOrigin().getMonitor(); + if( origin == null ) return null; + + return serverMonitor = origin.serverMonitor; + } + + @Nullable + private UltimateServerMonitor createServerMonitor() + { + if( serverMonitor != null ) return serverMonitor; + + if( xIndex == 0 && yIndex == 0 ) + { + // If we're the origin, set up the new monitor + serverMonitor = new UltimateServerMonitor( this ); + serverMonitor.rebuild(); + + // And propagate it to child monitors + for( int x = 0; x < width; x++ ) + { + for( int y = 0; y < height; y++ ) + { + UltimateMonitorEntity monitor = getLoadedMonitor( x, y ).getMonitor(); + if( monitor != null ) monitor.serverMonitor = serverMonitor; + } + } + + return serverMonitor; + } + else + { + // Otherwise fetch the origin and attempt to get its monitor + // Note this may load chunks, but we don't really have a choice here. + BlockEntity te = level.getBlockEntity( toWorldPos( 0, 0 ) ); + if( !(te instanceof UltimateMonitorEntity monitor) ) return null; + + return serverMonitor = monitor.createServerMonitor(); + } + } + + @Nullable + public UltimateClientMonitor getClientMonitor() + { + if( clientMonitor != null ) return clientMonitor; + + BlockEntity te = level.getBlockEntity( toWorldPos( 0, 0 ) ); + if( !(te instanceof UltimateMonitorEntity monitor) ) return null; + + return clientMonitor = monitor.clientMonitor; + } + + // Networking stuff + + @Nonnull + @Override + public final ClientboundBlockEntityDataPacket getUpdatePacket() + { + return ClientboundBlockEntityDataPacket.create( this ); + } + + @Nonnull + @Override + public final CompoundTag getUpdateTag() + { + CompoundTag nbt = super.getUpdateTag(); + nbt.putInt( NBT_X, xIndex ); + nbt.putInt( NBT_Y, yIndex ); + nbt.putInt( NBT_WIDTH, width ); + nbt.putInt( NBT_HEIGHT, height ); + return nbt; + } + + @Override + public final void handleUpdateTag( @Nonnull CompoundTag nbt ) + { + super.handleUpdateTag( nbt ); + + int oldXIndex = xIndex; + int oldYIndex = yIndex; + + xIndex = nbt.getInt( NBT_X ); + yIndex = nbt.getInt( NBT_Y ); + width = nbt.getInt( NBT_WIDTH ); + height = nbt.getInt( NBT_HEIGHT ); + + if( oldXIndex != xIndex || oldYIndex != yIndex ) + { + // If our index has changed then it's possible the origin monitor has changed. Thus + // we'll clear our cache. If we're the origin then we'll need to remove the glList as well. + if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null ) clientMonitor.destroy(); + clientMonitor = null; + } + + if( xIndex == 0 && yIndex == 0 ) + { + // If we're the origin terminal then create it. + if( clientMonitor == null ) clientMonitor = new UltimateClientMonitor( this ); + } + } + + public final void read( UltimateTerminalState state ) + { + if( xIndex != 0 || yIndex != 0 ) + { + ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getBlockPos() ); + return; + } + + if( clientMonitor == null ) clientMonitor = new UltimateClientMonitor( this ); + clientMonitor.read( state ); + } + + // Sizing and placement stuff + + private void updateBlockState() + { + getLevel().setBlock( getBlockPos(), getBlockState() + .setValue( UltimateBlockMonitor.STATE, MonitorEdgeState.fromConnections( + yIndex < height - 1, yIndex > 0, + xIndex > 0, xIndex < width - 1 ) ), 2 ); + } + + // region Sizing and placement stuff + public Direction getDirection() + { + // Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's + // fun problems with the block being missing on the client. + BlockState state = getBlockState(); + return state.hasProperty( UltimateBlockMonitor.FACING ) ? state.getValue( UltimateBlockMonitor.FACING ) : Direction.NORTH; + } + + public Direction getOrientation() + { + BlockState state = getBlockState(); + return state.hasProperty( UltimateBlockMonitor.ORIENTATION ) ? state.getValue( UltimateBlockMonitor.ORIENTATION ) : Direction.NORTH; + } + + public Direction getFront() + { + Direction orientation = getOrientation(); + return orientation == Direction.NORTH ? getDirection() : orientation; + } + + public Direction getRight() + { + return getDirection().getCounterClockWise(); + } + + public Direction getDown() + { + Direction orientation = getOrientation(); + if( orientation == Direction.NORTH ) return Direction.UP; + return orientation == Direction.DOWN ? getDirection() : getDirection().getOpposite(); + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getXIndex() + { + return xIndex; + } + + public int getYIndex() + { + return yIndex; + } + + boolean isCompatible( UltimateMonitorEntity other ) + { + return !other.destroyed && getOrientation() == other.getOrientation() && getDirection() == other.getDirection(); + } + + /** + * Get a tile within the current monitor only if it is loaded and compatible. + * + * @param x Absolute X position in monitor coordinates + * @param y Absolute Y position in monitor coordinates + * @return The located monitor + */ + @Nonnull + private UltimateMonitorState getLoadedMonitor( int x, int y ) + { + if( x == xIndex && y == yIndex ) return UltimateMonitorState.present( this ); + BlockPos pos = toWorldPos( x, y ); + + Level world = getLevel(); + if( world == null || !world.isLoaded( pos ) ) return UltimateMonitorState.UNLOADED; + + BlockEntity tile = world.getBlockEntity( pos ); + if( !(tile instanceof UltimateMonitorEntity monitor) ) return UltimateMonitorState.MISSING; + + return isCompatible( monitor ) ? UltimateMonitorState.present( monitor ) : UltimateMonitorState.MISSING; + } + + private UltimateMonitorState getOrigin() + { + return getLoadedMonitor( 0, 0 ); + } + + /** + * Convert monitor coordinates to world coordinates. + * + * @param x Absolute X position in monitor coordinates + * @param y Absolute Y position in monitor coordinates + * @return The monitor's position. + */ + BlockPos toWorldPos( int x, int y ) + { + if( xIndex == x && yIndex == y ) return getBlockPos(); + return getBlockPos().relative( getRight(), -xIndex + x ).relative( getDown(), -yIndex + y ); + } + + void resize( int width, int height ) + { + // If we're not already the origin then we'll need to generate a new terminal. + if( xIndex != 0 || yIndex != 0 ) serverMonitor = null; + + xIndex = 0; + yIndex = 0; + System.out.println("resizing: " + this + " " + width + ", " + height); + this.width = width; + this.height = height; + + // Determine if we actually need a monitor. In order to do this, simply check if + // any component monitor been wrapped as a peripheral. Whilst this flag may be + // out of date, + boolean needsTerminal = false; + terminalCheck: + for( int x = 0; x < width; x++ ) + { + for( int y = 0; y < height; y++ ) + { + UltimateMonitorEntity monitor = getLoadedMonitor( x, y ).getMonitor(); + if( monitor != null && monitor.peripheral != null ) + { + needsTerminal = true; + break terminalCheck; + } + } + } + + // Either delete the current monitor or sync a new one. + if( needsTerminal ) + { + if( serverMonitor == null ) serverMonitor = new UltimateServerMonitor( this ); + } + else + { + serverMonitor = null; + } + + // Update the terminal's width and height and rebuild it. This ensures the monitor + // is consistent when syncing it to other monitors. + if( serverMonitor != null ) serverMonitor.rebuild(); + + // Update the other monitors, setting coordinates, dimensions and the server terminal + BlockPos pos = getBlockPos(); + Direction down = getDown(), right = getRight(); + for( int x = 0; x < width; x++ ) + { + for( int y = 0; y < height; y++ ) + { + BlockEntity other = getLevel().getBlockEntity( pos.relative( right, x ).relative( down, y ) ); + if( !(other instanceof UltimateMonitorEntity monitor) || !isCompatible( monitor ) ) continue; + + monitor.xIndex = x; + monitor.yIndex = y; + monitor.width = width; + monitor.height = height; + monitor.serverMonitor = serverMonitor; + monitor.needsUpdate = monitor.needsValidating = false; + monitor.updateBlockState(); + monitor.updateBlock(); + } + } + } + + void updateNeighborsDeferred() + { + needsUpdate = true; + } + + void expand() + { + UltimateMonitorEntity monitor = getOrigin().getMonitor(); + if( monitor != null && monitor.xIndex == 0 && monitor.yIndex == 0 ) new UltimateExpander( monitor ).expand(); + } + + private void contractNeighbours() + { + if( width == 1 && height == 1 ) return; + + BlockPos pos = getBlockPos(); + Direction down = getDown(), right = getRight(); + BlockPos origin = toWorldPos( 0, 0 ); + + UltimateMonitorEntity toLeft = null, toAbove = null, toRight = null, toBelow = null; + if( xIndex > 0 ) toLeft = tryResizeAt( pos.relative( right, -xIndex ), xIndex, 1 ); + if( yIndex > 0 ) toAbove = tryResizeAt( origin, width, yIndex ); + if( xIndex < width - 1 ) toRight = tryResizeAt( pos.relative( right, 1 ), width - xIndex - 1, 1 ); + if( yIndex < height - 1 ) + { + toBelow = tryResizeAt( origin.relative( down, yIndex + 1 ), width, height - yIndex - 1 ); + } + + if( toLeft != null ) toLeft.expand(); + if( toAbove != null ) toAbove.expand(); + if( toRight != null ) toRight.expand(); + if( toBelow != null ) toBelow.expand(); + } + + @Nullable + private UltimateMonitorEntity tryResizeAt( BlockPos pos, int width, int height ) + { + BlockEntity tile = level.getBlockEntity( pos ); + if( tile instanceof UltimateMonitorEntity monitor && isCompatible( monitor ) ) + { + monitor.resize( width, height ); + return monitor; + } + + return null; + } + + + private boolean checkMonitorAt( int xIndex, int yIndex ) + { + UltimateMonitorState state = getLoadedMonitor( xIndex, yIndex ); + if( state.isMissing() ) return false; + + UltimateMonitorEntity monitor = state.getMonitor(); + if( monitor == null ) return true; + + return monitor.xIndex == xIndex && monitor.yIndex == yIndex && monitor.width == width && monitor.height == height; + } + + private void validate() + { + if( xIndex == 0 && yIndex == 0 && width == 1 && height == 1 ) return; + + if( xIndex >= 0 && xIndex <= width && width > 0 && width <= ComputerCraft.monitorWidth && + yIndex >= 0 && yIndex <= height && height > 0 && height <= ComputerCraft.monitorHeight && + checkMonitorAt( 0, 0 ) && checkMonitorAt( 0, height - 1 ) && + checkMonitorAt( width - 1, 0 ) && checkMonitorAt( width - 1, height - 1 ) ) + { + return; + } + + // Something in our monitor is invalid. For now, let's just reset ourselves and then try to integrate ourselves + // later. + ComputerCraft.log.warn( "Monitor is malformed, resetting to 1x1." ); + resize( 1, 1 ); + needsUpdate = true; + } + // endregion + + private void monitorTouched(float xPos, float yPos, float zPos, @Nullable Player player) { + XYPair pair = XYPair + .of(xPos, yPos, zPos, getDirection(), getOrientation()) + .add(xIndex, height - yIndex - 1); + + if (pair.x() > width - RENDER_BORDER || pair.y() > height - RENDER_BORDER || pair.x() < RENDER_BORDER || pair.y() < RENDER_BORDER) { + return; + } + + UltimateServerMonitor serverTerminal = getServerMonitor(); + if (serverTerminal == null) { + return; + } + + UltimateNetworkedTerminal originTerminal = serverTerminal.getTerminal(); + if (originTerminal == null) { + return; + } + + double xCharWidth = (width - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getWidth(); + double yCharHeight = (height - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getHeight(); + + // TODO: sight check for depth panel + int xCharPos = (int) Math.min(originTerminal.getWidth(), Math.max((pair.x() - RENDER_BORDER - RENDER_MARGIN) / xCharWidth + 1.0, 1.0)); + int yCharPos = (int) Math.min(originTerminal.getHeight(), Math.max((pair.y() - RENDER_BORDER - RENDER_MARGIN) / yCharHeight + 1.0, 1.0)); + + eachComputer(c -> c.queueEvent("monitor_touch", c.getAttachmentName(), xCharPos, yCharPos, + player == null ? null : player.getName().getString())); + } + + private void eachComputer(Consumer fun) { + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + UltimateMonitorEntity monitor = getLoadedMonitor(x, y).getMonitor(); + if (monitor == null) { + continue; + } + + for (IComputerAccess computer : monitor.computers) { + fun.accept(computer); + } + } + } + } + + void addComputer( IComputerAccess computer ) + { + computers.add( computer ); + } + + void removeComputer( IComputerAccess computer ) + { + computers.remove( computer ); + } + + @Nonnull + @Override + public AABB getRenderBoundingBox() + { + // We attempt to cache the bounding box to save having to do property lookups (and allocations!) on every frame. + // Unfortunately the AABB does depend on quite a lot of state, so we need to add a bunch of extra fields - + // ideally these'd be a single object, but I don't think worth doing until Java has value types. + if( boundingBox != null && getBlockState().equals( bbState ) && getBlockPos().equals( bbPos ) && + xIndex == bbX && yIndex == bbY && width == bbWidth && height == bbHeight ) + { + return boundingBox; + } + + bbState = getBlockState(); + bbPos = getBlockPos(); + bbX = xIndex; + bbY = yIndex; + bbWidth = width; + bbHeight = height; + + BlockPos startPos = toWorldPos( 0, 0 ); + BlockPos endPos = toWorldPos( width, height ); + return boundingBox = new AABB( + Math.min( startPos.getX(), endPos.getX() ), + Math.min( startPos.getY(), endPos.getY() ), + Math.min( startPos.getZ(), endPos.getZ() ), + Math.max( startPos.getX(), endPos.getX() ) + 1, + Math.max( startPos.getY(), endPos.getY() ) + 1, + Math.max( startPos.getZ(), endPos.getZ() ) + 1 + ); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorPeripheral.java new file mode 100644 index 000000000..aa9ba4cf2 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorPeripheral.java @@ -0,0 +1,524 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.LuaValues; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.apis.TableHelper; +import dan200.computercraft.core.apis.TermMethods; +import dan200.computercraft.shared.util.Palette; +import dan200.computercraft.shared.util.StringUtil; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.BlockEntityPeripheralOwner; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; +import org.apache.commons.lang3.ArrayUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +public class UltimateMonitorPeripheral implements IPeripheral { + private final UltimateMonitorEntity monitor; + + public UltimateMonitorPeripheral(UltimateMonitorEntity monitor) { + this.monitor = monitor; + } + + @Override + public String getType() { + return "monitor"; + } + + @LuaFunction + public boolean isUltimate() { + return true; + } + + @LuaFunction + public double getPanelDepth() throws LuaException { + return (double)(this.getTerminal().getPanelDepth()); + } + + @LuaFunction + public void setPanelDepth(double panelDepth) throws LuaException { + this.getTerminal().setPanelDepth((float)(panelDepth)); + } + + /** + * Set the scale of this monitor. A larger scale will result in the monitor having a lower resolution, but display + * text much larger. + * + * @param scaleArg The monitor's scale. This must be a multiple of 0.1 between 0.1 and 5. + * @throws LuaException If the scale is out of range. + * @see #getTextScale() + */ + @LuaFunction + public final void setTextScale(double scaleArg) throws LuaException { + int scale = (int) (LuaValues.checkFinite(0, scaleArg) * 10.0); + if (scale < 1 || scale > 10 * 5) { + throw new LuaException( "Expected number in range 0.1-10" ); + } + getMonitor().setTextScale(scale); + } + + /** + * Get the monitor's current text scale. + * + * @return The monitor's current scale. + * @throws LuaException If the monitor cannot be found. + * @cc.since 1.81.0 + */ + @LuaFunction + public final double getTextScale() throws LuaException + { + return getMonitor().getTextScale() / 10.0; + } + + @Override + public void attach( @Nonnull IComputerAccess computer ) + { + monitor.addComputer( computer ); + } + + @Override + public void detach( @Nonnull IComputerAccess computer ) + { + monitor.removeComputer( computer ); + } + + @Override + public boolean equals( IPeripheral other ) + { + return other instanceof UltimateMonitorPeripheral && monitor == ((UltimateMonitorPeripheral) other).monitor; + } + + @Nonnull + private UltimateServerMonitor getMonitor() throws LuaException { + UltimateServerMonitor monitor = this.monitor.getCachedServerMonitor(); + if (monitor == null) { + throw new LuaException("Monitor has been detached"); + } + return monitor; + } + + @Nonnull + public UltimateNetworkedTerminal getTerminal() throws LuaException { + UltimateNetworkedTerminal terminal = getMonitor().getTerminal(); + if (terminal == null) { + throw new LuaException("Monitor has been detached"); + } + return terminal; + } + + @Nullable + @Override + public Object getTarget() { + return monitor; + } + + //// From dan200.computercraft.core.apis.TermMethods /// + + private static int getHighestBit( int group ) + { + int bit = 0; + while( group > 0 ) + { + group >>= 1; + bit++; + } + return bit; + } + + /** + * Write {@code text} at the current cursor position, moving the cursor to the end of the text. + *

+ * Unlike functions like {@code write} and {@code print}, this does not wrap the text - it simply copies the + * text to the current terminal line. + * + * @param arguments The text to write. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.param text The text to write. + */ + @LuaFunction + public final void write( IArguments arguments ) throws LuaException + { + String text = StringUtil.toString( arguments.get( 0 ) ); + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.write( text ); + terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() ); + } + } + + /** + * Move all positions up (or down) by {@code y} pixels. + *

+ * Every pixel in the terminal will be replaced by the line {@code y} pixels below it. If {@code y} is negative, it + * will copy pixels from above instead. + * + * @param y The number of lines to move up by. This may be a negative number. + * @throws LuaException (hidden) If the terminal cannot be found. + */ + @LuaFunction + public final void scroll( int y ) throws LuaException + { + getTerminal().scroll( y ); + } + + /** + * Get the position of the cursor. + * + * @return The cursor's position. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.treturn number The x position of the cursor. + * @cc.treturn number The y position of the cursor. + */ + @LuaFunction + public final Object[] getCursorPos() throws LuaException + { + UltimateNetworkedTerminal terminal = getTerminal(); + return new Object[] { terminal.getCursorX() + 1, terminal.getCursorY() + 1 }; + } + + /** + * Set the position of the cursor. {@link #write(IArguments) terminal writes} will begin from this position. + * + * @param x The new x position of the cursor. + * @param y The new y position of the cursor. + * @throws LuaException (hidden) If the terminal cannot be found. + */ + @LuaFunction + public final void setCursorPos( int x, int y ) throws LuaException + { + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setCursorPos( x - 1, y - 1 ); + } + } + + /** + * Checks if the cursor is currently blinking. + * + * @return If the cursor is blinking. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.since 1.80pr1.9 + */ + @LuaFunction + public final boolean getCursorBlink() throws LuaException + { + return getTerminal().getCursorBlink(); + } + + /** + * Sets whether the cursor should be visible (and blinking) at the current {@link #getCursorPos() cursor position}. + * + * @param blink Whether the cursor should blink. + * @throws LuaException (hidden) If the terminal cannot be found. + */ + @LuaFunction + public final void setCursorBlink( boolean blink ) throws LuaException + { + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setCursorBlink( blink ); + } + } + + /** + * Get the size of the terminal. + * + * @return The terminal's size. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.treturn number The terminal's width. + * @cc.treturn number The terminal's height. + */ + @LuaFunction + public final Object[] getSize() throws LuaException + { + UltimateNetworkedTerminal terminal = getTerminal(); + return new Object[] { terminal.getWidth(), terminal.getHeight() }; + } + + /** + * Clears the terminal, filling it with the {@link #getBackgroundColour() current background colour}. + * + * @throws LuaException (hidden) If the terminal cannot be found. + */ + @LuaFunction + public final void clear() throws LuaException + { + getTerminal().clear(); + } + + /** + * Clears the line the cursor is currently on, filling it with the {@link #getBackgroundColour() current background + * colour}. + * + * @throws LuaException (hidden) If the terminal cannot be found. + */ + @LuaFunction + public final void clearLine() throws LuaException + { + getTerminal().clearLine(); + } + + /** + * Return the colour that new text will be written as. + * + * @return The current text colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants, returned by this function. + * @cc.since 1.74 + */ + @LuaFunction( { "getTextColour", "getTextColor" } ) + public final int getTextColour() throws LuaException + { + return encodeColour( getTerminal().getTextColour() ); + } + + /** + * Set the colour that new text will be written as. + * + * @param colourArg The new text colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants. + * @cc.since 1.45 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. + */ + @LuaFunction( { "setTextColour", "setTextColor" } ) + public final void setTextColour( int colourArg ) throws LuaException + { + int colour = parseColour( colourArg ); + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setTextColour( colour ); + } + } + + /** + * Return the current background colour. This is used when {@link #write writing text} and {@link #clear clearing} + * the terminal. + * + * @return The current background colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants, returned by this function. + * @cc.since 1.74 + */ + @LuaFunction( { "getBackgroundColour", "getBackgroundColor" } ) + public final int getBackgroundColour() throws LuaException + { + return encodeColour( getTerminal().getBackgroundColour() ); + } + + /** + * Set the current background colour. This is used when {@link #write writing text} and {@link #clear clearing} the + * terminal. + * + * @param colourArg The new background colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants. + * @cc.since 1.45 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. + */ + @LuaFunction( { "setBackgroundColour", "setBackgroundColor" } ) + public final void setBackgroundColour( int colourArg ) throws LuaException + { + int colour = parseColour( colourArg ); + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setBackgroundColour( colour ); + } + } + + /** + * Determine if this terminal supports colour. + *

+ * Terminals which do not support colour will still allow writing coloured text/backgrounds, but it will be + * displayed in greyscale. + * + * @return Whether this terminal supports colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.since 1.45 + */ + @LuaFunction( { "isColour", "isColor" } ) + public final boolean getIsColour() throws LuaException + { + return true; + } + + /** + * Writes {@code text} to the terminal with the specific foreground and background characters. + *

+ * As with {@link #write(IArguments)}, the text will be written at the current cursor location, with the cursor + * moving to the end of the text. + *

+ * {@code textColour} and {@code backgroundColour} must both be strings the same length as {@code text}. All + * characters represent a single hexadecimal digit, which is converted to one of CC's colours. For instance, + * {@code "a"} corresponds to purple. + * + * @param text The text to write. + * @param textColour The corresponding text colours. + * @param backgroundColour The corresponding background colours. + * @throws LuaException If the three inputs are not the same length. + * @cc.see colors For a list of colour constants, and their hexadecimal values. + * @cc.since 1.74 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. + * @cc.usage Prints "Hello, world!" in rainbow text. + *

{@code
+     * term.blit("Hello, world!","01234456789ab","0000000000000")
+     * }
+ */ + @LuaFunction + public final void blit( ByteBuffer text, ByteBuffer textColour, ByteBuffer backgroundColour ) throws LuaException + { + if( textColour.remaining() != text.remaining() || backgroundColour.remaining() != text.remaining() ) + { + throw new LuaException( "Arguments must be the same length" ); + } + + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.blit( text, textColour, backgroundColour ); + terminal.setCursorPos( terminal.getCursorX() + text.remaining(), terminal.getCursorY() ); + } + } + + /** + * Set the palette for a specific colour. + *

+ * ComputerCraft's palette system allows you to change how a specific colour should be displayed. For instance, you + * can make @{colors.red} more red by setting its palette to #FF0000. This does now allow you to draw more + * colours - you are still limited to 16 on the screen at one time - but you can change which colours are + * used. + * + * @param args The new palette values. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.tparam [1] number index The colour whose palette should be changed. + * @cc.tparam number colour A 24-bit integer representing the RGB value of the colour. For instance the integer + * `0xFF0000` corresponds to the colour #FF0000. + * @cc.tparam [2] number index The colour whose palette should be changed. + * @cc.tparam number r The intensity of the red channel, between 0 and 1. + * @cc.tparam number g The intensity of the green channel, between 0 and 1. + * @cc.tparam number b The intensity of the blue channel, between 0 and 1. + * @cc.usage Change the @{colors.red|red colour} from the default #CC4C4C to #FF0000. + *

{@code
+     * term.setPaletteColour(colors.red, 0xFF0000)
+     * term.setTextColour(colors.red)
+     * print("Hello, world!")
+     * }
+ * @cc.usage As above, but specifying each colour channel separately. + *
{@code
+     * term.setPaletteColour(colors.red, 1, 0, 0)
+     * term.setTextColour(colors.red)
+     * print("Hello, world!")
+     * }
+ * @cc.see colors.unpackRGB To convert from the 24-bit format to three separate channels. + * @cc.see colors.packRGB To convert from three separate channels to the 24-bit format. + * @cc.since 1.80pr1 + */ + @LuaFunction( { "setPaletteColour", "setPaletteColor" } ) + public final void setPaletteColour(IArguments args) throws LuaException { + int colour = 15 - parseColour(args.getInt(0)); + switch (args.count()) { + case 2: + { + int hex = args.getInt(1); + double[] rgb = Palette.decodeRGB8(hex); + setColour(getTerminal(), colour, rgb[0], rgb[1], rgb[2]); + } + break; + case 4: + { + double r = args.getFiniteDouble(1); + double g = args.getFiniteDouble(2); + double b = args.getFiniteDouble(3); + setColour(getTerminal(), colour, r, g, b); + } + break; + case 3: + { + int hex = args.getInt(1); + double a = args.getFiniteDouble(2); + double[] rgb = Palette.decodeRGB8(hex); + setColour(getTerminal(), colour, rgb[0], rgb[1], rgb[2], a); + } + break; + case 5: + { + double r = args.getFiniteDouble(1); + double g = args.getFiniteDouble(2); + double b = args.getFiniteDouble(3); + double a = args.getFiniteDouble(4); + setColour(getTerminal(), colour, r, g, b, a); + } + break; + } + } + + /** + * Get the current palette for a specific colour. + * + * @param colourArg The colour whose palette should be fetched. + * @return The resulting colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.treturn number The red channel, will be between 0 and 1. + * @cc.treturn number The green channel, will be between 0 and 1. + * @cc.treturn number The blue channel, will be between 0 and 1. + * @cc.since 1.80pr1 + */ + @LuaFunction( { "getPaletteColour", "getPaletteColor" } ) + public final Object[] getPaletteColour(int colourArg) throws LuaException { + int colour = 15 - parseColour(colourArg); + UltimateNetworkedTerminal terminal = getTerminal(); + synchronized(terminal) { + double[] rgb = terminal.getPalette().getColour(colour); + if (rgb == null) { + return null; + } + double a = terminal.getPaletteTransparency(colour); + return ArrayUtils.toObject(new double[]{ + rgb[0], + rgb[1], + rgb[2], + a, + }); + } + } + + public static int parseColour( int colour ) throws LuaException + { + if( colour <= 0 ) throw new LuaException( "Colour out of range" ); + colour = getHighestBit( colour ) - 1; + if( colour < 0 || colour > 15 ) throw new LuaException( "Colour out of range" ); + return colour; + } + + + public static int encodeColour(int colour) { + return 1 << colour; + } + + public static void setColour(UltimateNetworkedTerminal terminal, int colour, double r, double g, double b) { + terminal.getPalette().setColour(colour, r, g, b); + terminal.setChanged(); + } + + public static void setColour(UltimateNetworkedTerminal terminal, int colour, double r, double g, double b, double a) { + terminal.setPaletteTransparency(colour, (float)(a)); + setColour(terminal, colour, r, g, b); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorState.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorState.java new file mode 100644 index 000000000..fb54affe7 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorState.java @@ -0,0 +1,52 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +final class UltimateMonitorState +{ + public static final UltimateMonitorState UNLOADED = new UltimateMonitorState( State.UNLOADED, null ); + public static final UltimateMonitorState MISSING = new UltimateMonitorState( State.MISSING, null ); + + private final State state; + private final UltimateMonitorEntity monitor; + + private UltimateMonitorState( @Nonnull State state, @Nullable UltimateMonitorEntity monitor ) + { + this.state = state; + this.monitor = monitor; + } + + public static UltimateMonitorState present( @Nonnull UltimateMonitorEntity monitor ) + { + return new UltimateMonitorState( State.PRESENT, monitor ); + } + + public boolean isPresent() + { + return state == State.PRESENT; + } + + public boolean isMissing() + { + return state == State.MISSING; + } + + @Nullable + public UltimateMonitorEntity getMonitor() + { + return monitor; + } + + enum State + { + UNLOADED, + MISSING, + PRESENT, + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorWatcher.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorWatcher.java new file mode 100644 index 000000000..d00ca869e --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateMonitorWatcher.java @@ -0,0 +1,101 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import dan200.computercraft.ComputerCraft; +import de.srendi.advancedperipherals.common.network.APNetworking; +import de.srendi.advancedperipherals.common.network.toclient.UltimateMonitorClientPacket; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateTerminalState; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.level.ChunkWatchEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.ArrayDeque; +import java.util.Queue; + +@Mod.EventBusSubscriber( modid = AdvancedPeripherals.MOD_ID ) +public final class UltimateMonitorWatcher +{ + private static final Queue watching = new ArrayDeque<>(); + + private UltimateMonitorWatcher() + { + } + + static void enqueue( UltimateMonitorEntity monitor ) + { + if( monitor.enqueued ) return; + + monitor.enqueued = true; + monitor.cached = null; + watching.add( monitor ); + } + + @SubscribeEvent + public static void onWatch( ChunkWatchEvent.Watch event ) + { + // Find all origin monitors who are not already on the queue and send the + // monitor data to the player. + for( BlockEntity te : event.getChunk().getBlockEntities().values() ) + { + if( !(te instanceof UltimateMonitorEntity monitor) ) continue; + + UltimateServerMonitor serverMonitor = getMonitor( monitor ); + if( serverMonitor == null || monitor.enqueued ) continue; + + UltimateTerminalState state = getState( monitor, serverMonitor ); + APNetworking.sendToClient( new UltimateMonitorClientPacket( monitor.getBlockPos(), state ), event.getPlayer() ); + } + } + + @SubscribeEvent + public static void onTick( TickEvent.ServerTickEvent event ) + { + // Find all enqueued monitors and send their contents to all nearby players. + + if( event.phase != TickEvent.Phase.END ) return; + + long limit = ComputerCraft.monitorBandwidth; + boolean obeyLimit = limit > 0; + + UltimateMonitorEntity tile; + while( (!obeyLimit || limit > 0) && (tile = watching.poll()) != null ) + { + tile.enqueued = false; + UltimateServerMonitor monitor = getMonitor( tile ); + if( monitor == null ) continue; + + BlockPos pos = tile.getBlockPos(); + Level world = tile.getLevel(); + if( !(world instanceof ServerLevel) ) continue; + + UltimateTerminalState state = getState( tile, monitor ); + APNetworking.sendToAllTracking( new UltimateMonitorClientPacket( pos, state ), world, pos ); + + limit -= state.size(); + } + } + + private static UltimateServerMonitor getMonitor( UltimateMonitorEntity monitor ) + { + return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null; + } + + private static UltimateTerminalState getState( UltimateMonitorEntity tile, UltimateServerMonitor monitor ) { + UltimateTerminalState state = tile.cached; + if (state == null) { + state = tile.cached = new UltimateTerminalState(monitor.getTerminal()); + } + return state; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateServerMonitor.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateServerMonitor.java new file mode 100644 index 000000000..983de37c7 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/monitor/UltimateServerMonitor.java @@ -0,0 +1,88 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor; + +import com.google.common.annotations.VisibleForTesting; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.util.TickScheduler; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateNetworkedTerminal; + +import javax.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + +public class UltimateServerMonitor { + private final UltimateMonitorEntity origin; + + private int textScale = 10; + private @Nullable UltimateNetworkedTerminal terminal; + private final AtomicBoolean resized = new AtomicBoolean( false ); + private final AtomicBoolean changed = new AtomicBoolean( false ); + + UltimateServerMonitor(UltimateMonitorEntity origin) { + this.origin = origin; + } + + synchronized void rebuild() { + Terminal oldTerm = getTerminal(); + int oldWidth = oldTerm == null ? -1 : oldTerm.getWidth(); + int oldHeight = oldTerm == null ? -1 : oldTerm.getHeight(); + + double textScale = this.textScale * 0.1; + int termWidth = (int) Math.max( + Math.round( (origin.getWidth() - 2.0 * (UltimateMonitorEntity.RENDER_BORDER + UltimateMonitorEntity.RENDER_MARGIN)) / (textScale * 6.0 * UltimateMonitorEntity.RENDER_PIXEL_SCALE) ), + 1.0 + ); + int termHeight = (int) Math.max( + Math.round( (origin.getHeight() - 2.0 * (UltimateMonitorEntity.RENDER_BORDER + UltimateMonitorEntity.RENDER_MARGIN)) / (textScale * 9.0 * UltimateMonitorEntity.RENDER_PIXEL_SCALE) ), + 1.0 + ); + + if (terminal == null) { + terminal = new UltimateNetworkedTerminal(termWidth, termHeight, this::markChanged); + markChanged(); + } else { + terminal.resize(termWidth, termHeight); + } + + if (oldWidth != termWidth || oldHeight != termHeight) { + terminal.clear(); + resized.set(true); + markChanged(); + } + } + + private void markChanged() { + if (!changed.getAndSet(true)) { + TickScheduler.schedule(origin.tickToken); + } + } + + int getTextScale() { + return textScale; + } + + synchronized void setTextScale(int textScale) { + if (this.textScale == textScale) { + return; + } + this.textScale = textScale; + rebuild(); + } + + boolean pollResized() { + return resized.getAndSet(false); + } + + boolean pollTerminalChanged() { + return changed.getAndSet(false); + } + + @Nullable + @VisibleForTesting + public UltimateNetworkedTerminal getTerminal() { + return terminal; + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/terminal/UltimateNetworkedTerminal.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/terminal/UltimateNetworkedTerminal.java new file mode 100644 index 000000000..2292678b2 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/terminal/UltimateNetworkedTerminal.java @@ -0,0 +1,99 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.terminal; + +import dan200.computercraft.shared.computer.terminal.NetworkedTerminal; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; + +import java.util.Arrays; + +public class UltimateNetworkedTerminal extends NetworkedTerminal { + private static final int PALETTE_SIZE = 16; // sync with dan200.computercraft.shared.util.Palette + + private float panelDepth = 0; + private final byte[] transparencies = new byte[PALETTE_SIZE]; + + public UltimateNetworkedTerminal(int width, int height) { + this(width, height, null); + } + + public UltimateNetworkedTerminal(int width, int height, Runnable changedCallback) { + super(width, height, true, changedCallback); + for (int i = 0; i < this.transparencies.length; i++) { + this.transparencies[i] = (byte)(0xff); + } + } + + public float getPanelDepth() { + return this.panelDepth; + } + + public void setPanelDepth(float z) { + z = Math.min(Math.max(z, 0), 1); + if (this.panelDepth == z) { + return; + } + this.panelDepth = z; + setChanged(); + } + + public int getPaletteTransparencyByte(int color) { + return (int)(this.transparencies[color]) & 0xff; + } + + public float getPaletteTransparency(int color) { + if (color < 0 || color >= this.transparencies.length) { + return 1; + } + return (float)((int)(this.transparencies[color]) & 0xff) / 255.0f; + } + + public void setPaletteTransparency(int color, float a) { + if (color < 0 || color >= this.transparencies.length) { + return; + } + a = Math.min(Math.max(a, 0), 1); + this.transparencies[color] = (byte)((int)(a * 0xff)); + } + + @Override + public synchronized void reset() { + super.reset(); + this.panelDepth = 0; + for (int i = 0; i < this.transparencies.length; i++) { + this.transparencies[i] = (byte)(0xff); + } + setChanged(); + } + + @Override + public synchronized void write(FriendlyByteBuf buffer) { + super.write(buffer); + buffer.writeFloat(this.panelDepth); + buffer.writeBytes(this.transparencies); + } + + @Override + public synchronized void read(FriendlyByteBuf buffer) { + super.read(buffer); + this.panelDepth = buffer.readFloat(); + buffer.readBytes(this.transparencies); + setChanged(); + } + + @Override + public synchronized CompoundTag writeToNBT(CompoundTag nbt) { + super.writeToNBT(nbt); + nbt.putFloat("term_panelDepth", this.panelDepth); + nbt.putByteArray("term_paletteTransparencies", this.transparencies); + return nbt; + } + + @Override + public synchronized void readFromNBT(CompoundTag nbt) { + super.readFromNBT(nbt); + this.panelDepth = nbt.getFloat("term_panelDepth"); + byte[] transparencies = nbt.getByteArray("term_paletteTransparencies"); + System.arraycopy(transparencies, 0, this.transparencies, 0, Math.min(transparencies.length, this.transparencies.length)); + setChanged(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/terminal/UltimateTerminalState.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/terminal/UltimateTerminalState.java new file mode 100644 index 000000000..ae6d584bc --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/terminal/UltimateTerminalState.java @@ -0,0 +1,187 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.addons.computercraft.terminal; + +import dan200.computercraft.shared.util.IoUtil; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * A snapshot of a terminal's state. + *

+ * This is somewhat memory inefficient (we build a buffer, only to write it elsewhere), however it means we get a + * complete and accurate description of a terminal, which avoids a lot of complexities with resizing terminals, dirty + * states, etc... + */ +public class UltimateTerminalState +{ + public final int width; + public final int height; + + private final boolean compress; + + @Nullable + private final ByteBuf buffer; + + private ByteBuf compressed; + + public UltimateTerminalState( @Nullable UltimateNetworkedTerminal terminal ) + { + this( terminal, true ); + } + + public UltimateTerminalState( @Nullable UltimateNetworkedTerminal terminal, boolean compress ) + { + this.compress = compress; + + if( terminal == null ) + { + width = height = 0; + buffer = null; + } + else + { + width = terminal.getWidth(); + height = terminal.getHeight(); + + ByteBuf buf = buffer = Unpooled.buffer(); + terminal.write( new FriendlyByteBuf( buf ) ); + } + } + + public UltimateTerminalState( FriendlyByteBuf buf ) + { + buf.readBoolean(); + compress = buf.readBoolean(); + + if( buf.readBoolean() ) + { + width = buf.readVarInt(); + height = buf.readVarInt(); + + int length = buf.readVarInt(); + buffer = readCompressed( buf, length, compress ); + } + else + { + width = height = 0; + buffer = null; + } + } + + public void write( FriendlyByteBuf buf ) + { + buf.writeBoolean( true ); + buf.writeBoolean( compress ); + + buf.writeBoolean( buffer != null ); + if( buffer != null ) + { + buf.writeVarInt( width ); + buf.writeVarInt( height ); + + ByteBuf sendBuffer = getCompressed(); + buf.writeVarInt( sendBuffer.readableBytes() ); + buf.writeBytes( sendBuffer, sendBuffer.readerIndex(), sendBuffer.readableBytes() ); + } + } + + public boolean hasTerminal() + { + return buffer != null; + } + + public int size() + { + return buffer == null ? 0 : buffer.readableBytes(); + } + + public void apply( UltimateNetworkedTerminal terminal ) + { + if( buffer == null ) throw new NullPointerException( "buffer" ); + terminal.resize( width, height ); + terminal.read( new FriendlyByteBuf( buffer ) ); + } + + public UltimateNetworkedTerminal create() + { + if( buffer == null ) throw new NullPointerException( "Terminal does not exist" ); + UltimateNetworkedTerminal terminal = new UltimateNetworkedTerminal( width, height ); + terminal.read( new FriendlyByteBuf( buffer ) ); + return terminal; + } + + private ByteBuf getCompressed() + { + if( buffer == null ) throw new NullPointerException( "buffer" ); + if( !compress ) return buffer; + if( compressed != null ) return compressed; + + ByteBuf compressed = Unpooled.buffer(); + OutputStream stream = null; + try + { + stream = new GZIPOutputStream( new ByteBufOutputStream( compressed ) ); + stream.write( buffer.array(), buffer.arrayOffset(), buffer.readableBytes() ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + finally + { + IoUtil.closeQuietly( stream ); + } + + return this.compressed = compressed; + } + + private static ByteBuf readCompressed( ByteBuf buf, int length, boolean compress ) + { + if( compress ) + { + ByteBuf buffer = Unpooled.buffer(); + InputStream stream = null; + try + { + stream = new GZIPInputStream( new ByteBufInputStream( buf, length ) ); + byte[] swap = new byte[8192]; + while( true ) + { + int bytes = stream.read( swap ); + if( bytes == -1 ) break; + buffer.writeBytes( swap, 0, bytes ); + } + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + finally + { + IoUtil.closeQuietly( stream ); + } + return buffer; + } + else + { + ByteBuf buffer = Unpooled.buffer( length ); + buf.readBytes( buffer, length ); + return buffer; + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java b/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java index 8ed5cd8ba..79ec89f4a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java +++ b/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java @@ -107,6 +107,9 @@ public class PeripheralsConfig implements IAPConfig { public final ForgeConfigSpec.BooleanValue enableSaddleTurtle; public final ForgeConfigSpec.BooleanValue allowSaddleTurtleCapturePlayer; + // Ultimate monitor + public final ForgeConfigSpec.BooleanValue enableUltimateMonitor; + private static final List chatBoxDefaultBannedCommands = Arrays.asList( "/execute", "/op", @@ -242,6 +245,10 @@ public PeripheralsConfig() { enableSaddleTurtle = builder.comment("Enable saddle turtle").define("enableSaddleTurtle", true); allowSaddleTurtleCapturePlayer = builder.comment("Allow saddle turtle to capture player").define("allowSaddleTurtleCapturePlayer", true); + + pop("Ultimate_Monitor", builder); + + enableUltimateMonitor = builder.comment("Enable ultimate monitor").define("enableUltimateMonitor", true); pop("Operations", builder); diff --git a/src/main/java/de/srendi/advancedperipherals/common/data/BlockStatesAndModelsProvider.java b/src/main/java/de/srendi/advancedperipherals/common/data/BlockStatesAndModelsProvider.java index ae80747a0..71f03891c 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/data/BlockStatesAndModelsProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/data/BlockStatesAndModelsProvider.java @@ -1,13 +1,26 @@ package de.srendi.advancedperipherals.common.data; +import com.google.gson.JsonObject; +import com.google.gson.JsonElement; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState; import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor.UltimateBlockMonitor; import de.srendi.advancedperipherals.common.blocks.base.BaseBlock; import de.srendi.advancedperipherals.common.setup.APBlocks; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; +import net.minecraft.data.CachedOutput; import net.minecraft.data.DataGenerator; +import net.minecraft.data.DataProvider; +import net.minecraft.data.models.BlockModelGenerators; +import net.minecraft.data.models.blockstates.*; +import net.minecraft.data.models.model.*; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraftforge.client.model.generators.BlockModelBuilder; import net.minecraftforge.client.model.generators.BlockStateProvider; import net.minecraftforge.client.model.generators.ConfiguredModel; @@ -16,12 +29,31 @@ import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.registries.ForgeRegistries; +import java.io.IOException; +import java.nio.file.Path; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static net.minecraft.data.models.model.ModelLocationUtils.getModelLocation; +import static net.minecraft.data.models.model.TextureMapping.getBlockTexture; public class BlockStatesAndModelsProvider extends BlockStateProvider { + private final DataGenerator generator; + private Consumer addBlockState = null; + private BiConsumer> modelOutput = null; public BlockStatesAndModelsProvider(DataGenerator packOutput, ExistingFileHelper exFileHelper) { super(packOutput, AdvancedPeripherals.MOD_ID, exFileHelper); + this.generator = packOutput; } @Override @@ -141,4 +173,183 @@ private ResourceLocation key(Block block) { private String name(Block block) { return key(block).getPath(); } + + @Override + public void run(CachedOutput cache) throws IOException { + doMonitors(this.generator, cache); + super.run(cache); + } + + //// from dan200.computercraft.data.BlockModelGenerator //// + + private static final ModelTemplate MONITOR_BASE = new ModelTemplate( + Optional.of( new ResourceLocation( AdvancedPeripherals.MOD_ID, "block/monitor_base" ) ), + Optional.empty(), + TextureSlot.FRONT, TextureSlot.SIDE, TextureSlot.TOP, TextureSlot.BACK + ); + + private void doMonitors(DataGenerator generator, CachedOutput output) { + DataGenerator.PathProvider blockStatePath = generator.createPathProvider( DataGenerator.Target.RESOURCE_PACK, "blockstates" ); + DataGenerator.PathProvider modelPath = generator.createPathProvider( DataGenerator.Target.RESOURCE_PACK, "models" ); + Map blockStates = new HashMap<>(); + this.addBlockState = gen -> { + Block block = gen.getBlock(); + if( blockStates.containsKey( block ) ) + { + throw new IllegalStateException( "Duplicate blockstate definition for " + block ); + } + blockStates.put( block, gen ); + }; + + Map> models = new HashMap<>(); + this.modelOutput = (id, contents) -> { + if(models.containsKey(id)) { + throw new IllegalStateException("Duplicate model definition for " + id); + } + models.put(id, contents); + }; + Set explicitItems = new HashSet<>(); + BlockModelGenerators blockGen = new BlockModelGenerators(addBlockState, modelOutput, explicitItems::add); + + registerMonitor(blockGen, (UltimateBlockMonitor) APBlocks.ULTIMATE_MONITOR.get()); + + for( Block block : ForgeRegistries.BLOCKS ) + { + if( !blockStates.containsKey( block ) ) continue; + + Item item = Item.BY_BLOCK.get( block ); + if( item == null || explicitItems.contains( item ) ) continue; + + ResourceLocation model = ModelLocationUtils.getModelLocation( item ); + if( !models.containsKey( model ) ) + { + models.put( model, new DelegatedModel( ModelLocationUtils.getModelLocation( block ) ) ); + } + } + + saveCollection( output, blockStates, x -> blockStatePath.json( ForgeRegistries.BLOCKS.getKey( x ) ) ); + saveCollection( output, models, modelPath::json ); + } + + private static void saveCollection( CachedOutput output, Map> items, Function getLocation ) + { + for( Map.Entry> entry : items.entrySet() ) + { + Path path = getLocation.apply( entry.getKey() ); + try + { + DataProvider.saveStable( output, entry.getValue().get(), path ); + } + catch( Exception exception ) + { + ComputerCraft.log.error( "Couldn't save {}", path, exception ); + } + } + } + + private void registerMonitor(BlockModelGenerators generators, UltimateBlockMonitor block) + { + monitorModel( generators, block, "", 16, 4, 0, 32 ); + monitorModel( generators, block, "_d", 20, 7, 0, 36 ); + monitorModel( generators, block, "_l", 19, 4, 1, 33 ); + monitorModel( generators, block, "_ld", 31, 7, 1, 45 ); + monitorModel( generators, block, "_lr", 18, 4, 2, 34 ); + monitorModel( generators, block, "_lrd", 30, 7, 2, 46 ); + monitorModel( generators, block, "_lru", 24, 5, 2, 40 ); + monitorModel( generators, block, "_lrud", 27, 6, 2, 43 ); + monitorModel( generators, block, "_lu", 25, 5, 1, 39 ); + monitorModel( generators, block, "_lud", 28, 6, 1, 42 ); + monitorModel( generators, block, "_r", 17, 4, 3, 35 ); + monitorModel( generators, block, "_rd", 29, 7, 3, 47 ); + monitorModel( generators, block, "_ru", 23, 5, 3, 41 ); + monitorModel( generators, block, "_rud", 26, 6, 3, 44 ); + monitorModel( generators, block, "_u", 22, 5, 0, 38 ); + monitorModel( generators, block, "_ud", 21, 6, 0, 37 ); + + addBlockState.accept( MultiVariantGenerator.multiVariant( block ) + .with( createHorizontalFacingDispatch() ) + .with( createVerticalFacingDispatch( UltimateBlockMonitor.ORIENTATION ) ) + .with( createModelDispatch( UltimateBlockMonitor.STATE, edge -> getModelLocation( block, edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName() ) ) ) + ); + modelOutput.accept( ModelLocationUtils.getModelLocation(block.asItem()), new DelegatedModel(monitorModel( generators, block, "_item", 15, 4, 0, 32 ) )); + } + + private static final ResourceLocation TRANSPARENT_TEXTURE = new ResourceLocation(AdvancedPeripherals.MOD_ID, "block/transparent"); + + private ResourceLocation monitorModel( BlockModelGenerators generators, UltimateBlockMonitor block, String corners, int front, int side, int top, int back ) + { + TextureMapping textureMap = new TextureMapping(); + textureMap.put(TextureSlot.FRONT, getBlockTexture(block, "_" + front)); + // textureMap.put(TextureSlot.SIDE, getBlockTexture(block, "_" + side)); + // textureMap.put(TextureSlot.TOP, getBlockTexture(block, "_" + top)); + // textureMap.put(TextureSlot.BACK, getBlockTexture(block, "_" + back)); + textureMap.put(TextureSlot.SIDE, TRANSPARENT_TEXTURE); + textureMap.put(TextureSlot.TOP, TRANSPARENT_TEXTURE); + textureMap.put(TextureSlot.BACK, TRANSPARENT_TEXTURE); + return MONITOR_BASE.create( + getModelLocation( block, corners ), + textureMap, + modelOutput + ); + } + + private static PropertyDispatch createHorizontalFacingDispatch() + { + var dispatch = PropertyDispatch.property( BlockStateProperties.HORIZONTAL_FACING ); + for( Direction direction : BlockStateProperties.HORIZONTAL_FACING.getPossibleValues() ) + { + dispatch.select( direction, Variant.variant().with( VariantProperties.Y_ROT, toYAngle( direction ) ) ); + } + return dispatch; + } + + private static PropertyDispatch createVerticalFacingDispatch( Property property ) + { + var dispatch = PropertyDispatch.property( property ); + for( Direction direction : property.getPossibleValues() ) + { + dispatch.select( direction, Variant.variant().with( VariantProperties.X_ROT, toXAngle( direction ) ) ); + } + return dispatch; + } + + private static > PropertyDispatch createModelDispatch( Property property, Function makeModel ) + { + var variant = PropertyDispatch.property( property ); + for( T value : property.getPossibleValues() ) + { + variant.select( value, Variant.variant().with( VariantProperties.MODEL, makeModel.apply( value ) ) ); + } + return variant; + } + + private static VariantProperties.Rotation toXAngle( Direction direction ) + { + switch( direction ) + { + default: + return VariantProperties.Rotation.R0; + case UP: + return VariantProperties.Rotation.R270; + case DOWN: + return VariantProperties.Rotation.R90; + } + } + + private static VariantProperties.Rotation toYAngle( Direction direction ) + { + switch( direction ) + { + default: + return VariantProperties.Rotation.R0; + case NORTH: + return VariantProperties.Rotation.R0; + case SOUTH: + return VariantProperties.Rotation.R180; + case EAST: + return VariantProperties.Rotation.R90; + case WEST: + return VariantProperties.Rotation.R270; + } + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/data/BlockTagsProvider.java b/src/main/java/de/srendi/advancedperipherals/common/data/BlockTagsProvider.java index 0ccd4f85e..0273f2c74 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/data/BlockTagsProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/data/BlockTagsProvider.java @@ -1,7 +1,9 @@ package de.srendi.advancedperipherals.common.data; +import dan200.computercraft.api.ComputerCraftTags; import de.srendi.advancedperipherals.AdvancedPeripherals; import de.srendi.advancedperipherals.common.blocks.base.IHarvestableBlock; +import de.srendi.advancedperipherals.common.setup.APBlocks; import net.minecraft.core.Registry; import net.minecraft.data.DataGenerator; import net.minecraft.data.tags.TagsProvider; @@ -33,6 +35,7 @@ public BlockTagsProvider(DataGenerator generator, @Nullable ExistingFileHelper e @Override protected void addTags() { + tag(ComputerCraftTags.Blocks.MONITOR).add(APBlocks.ULTIMATE_MONITOR.get()); blockRegistry.getEntries().stream().map(RegistryObject::get).forEach(block -> { if (!(block instanceof IHarvestableBlock harvesterBlock)) throw new IllegalArgumentException("For any block you should define harvester logic!"); diff --git a/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java b/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java index 53cb3a4bc..497d13ef5 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java @@ -75,6 +75,7 @@ private void addBlocks() { addBlock(APBlocks.PLAYER_DETECTOR, "Player Detector"); addBlock(APBlocks.REDSTONE_INTEGRATOR, "Redstone Integrator"); addBlock(APBlocks.DISTANCE_DETECTOR, "Distance Detector"); + addBlock(APBlocks.ULTIMATE_MONITOR, "Ultimate Monitor"); } private void addTurtles() { @@ -85,7 +86,6 @@ private void addTurtles() { addTurtle(CCRegistration.ID.ENVIRONMENT_TURTLE, "Environment"); addTurtle(CCRegistration.ID.PLAYER_TURTLE, "Player Detector"); addTurtle(CCRegistration.ID.GEOSCANNER_TURTLE, "Geo"); - addTurtle(CCRegistration.ID.COMPASS_TURTLE, "Compass"); addTurtle(CCRegistration.ID.WEAK_AUTOMATA, "Weak automata"); addTurtle(CCRegistration.ID.HUSBANDRY_AUTOMATA, "Husbandry automata"); addTurtle(CCRegistration.ID.END_AUTOMATA, "End automata"); @@ -139,6 +139,7 @@ private void addTooltips() { addTooltip(APItems.OVERPOWERED_HUSBANDRY_AUTOMATA_CORE.get(), "&7Improved version of the husbandry automata core, that provides some overpowered uses! Be careful, the upgrade is very fragile."); addTooltip(APItems.END_AUTOMATA_CORE.get(), "&7Upgrade for turtles, that allows basic interaction with the world and teleportation in one dimension."); addTooltip(APItems.OVERPOWERED_END_AUTOMATA_CORE.get(), "&7Improved version of the end automata core, that provides some overpowered uses! Be careful, the upgrade is very fragile."); + addTooltip(APBlocks.ULTIMATE_MONITOR.get(), "&7A more advanced monitor. Can identify the operator and allow lights to pass through."); } private void addTexts() { diff --git a/src/main/java/de/srendi/advancedperipherals/common/network/APNetworking.java b/src/main/java/de/srendi/advancedperipherals/common/network/APNetworking.java index 1a6751ff4..a68b925cc 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/network/APNetworking.java +++ b/src/main/java/de/srendi/advancedperipherals/common/network/APNetworking.java @@ -5,6 +5,7 @@ import de.srendi.advancedperipherals.common.network.toclient.DistanceDetectorSyncPacket; import de.srendi.advancedperipherals.common.network.toclient.SaddleTurtleInfoPacket; import de.srendi.advancedperipherals.common.network.toclient.ToastToClientPacket; +import de.srendi.advancedperipherals.common.network.toclient.UltimateMonitorClientPacket; import de.srendi.advancedperipherals.common.network.toserver.GlassesHotkeyPacket; import de.srendi.advancedperipherals.common.network.toserver.SaddleTurtleControlPacket; import net.minecraft.core.BlockPos; @@ -38,6 +39,7 @@ public static void init() { registerServerToClient(DistanceDetectorSyncPacket.class, DistanceDetectorSyncPacket::decode); registerServerToClient(SaddleTurtleInfoPacket.class, SaddleTurtleInfoPacket::decode); registerServerToClient(ToastToClientPacket.class, ToastToClientPacket::decode); + registerServerToClient(UltimateMonitorClientPacket.class, UltimateMonitorClientPacket::decode); registerClientToServer(GlassesHotkeyPacket.class, GlassesHotkeyPacket::decode); registerClientToServer(SaddleTurtleControlPacket.class, SaddleTurtleControlPacket::decode); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/network/toclient/UltimateMonitorClientPacket.java b/src/main/java/de/srendi/advancedperipherals/common/network/toclient/UltimateMonitorClientPacket.java new file mode 100644 index 000000000..11eaa82a8 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/network/toclient/UltimateMonitorClientPacket.java @@ -0,0 +1,55 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.common.network.toclient; + +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor.UltimateMonitorEntity; +import de.srendi.advancedperipherals.common.addons.computercraft.terminal.UltimateTerminalState; +import de.srendi.advancedperipherals.common.network.base.IPacket; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.network.NetworkEvent; + +import javax.annotation.Nonnull; + +public class UltimateMonitorClientPacket implements IPacket +{ + private final BlockPos pos; + private final UltimateTerminalState state; + + public UltimateMonitorClientPacket( BlockPos pos, UltimateTerminalState state ) + { + this.pos = pos; + this.state = state; + } + + @Override + public void encode( @Nonnull FriendlyByteBuf buf ) + { + buf.writeBlockPos( pos ); + state.write( buf ); + } + + @Override + public void handle( NetworkEvent.Context context ) + { + LocalPlayer player = Minecraft.getInstance().player; + if( player == null || player.level == null ) return; + + BlockEntity te = player.level.getBlockEntity( pos ); + if( !(te instanceof UltimateMonitorEntity monitor) ) return; + + monitor.read( state ); + } + + public static UltimateMonitorClientPacket decode(FriendlyByteBuf buffer) { + return new UltimateMonitorClientPacket(buffer.readBlockPos(), new UltimateTerminalState(buffer)); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/setup/APBlockEntityTypes.java b/src/main/java/de/srendi/advancedperipherals/common/setup/APBlockEntityTypes.java index ab760488c..4256a4035 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/setup/APBlockEntityTypes.java +++ b/src/main/java/de/srendi/advancedperipherals/common/setup/APBlockEntityTypes.java @@ -2,6 +2,7 @@ import com.google.common.collect.Sets; import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor.UltimateMonitorEntity; import de.srendi.advancedperipherals.common.blocks.blockentities.*; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraftforge.registries.RegistryObject; @@ -26,5 +27,6 @@ protected static void register() { public static final RegistryObject> COLONY_INTEGRATOR = APRegistration.TILE_ENTITIES.register("colony_integrator", () -> new BlockEntityType<>(ColonyIntegratorEntity::new, Sets.newHashSet(APBlocks.COLONY_INTEGRATOR.get()), null)); public static final RegistryObject> NBT_STORAGE = APRegistration.TILE_ENTITIES.register("nbt_storage", () -> new BlockEntityType<>(NBTStorageEntity::new, Sets.newHashSet(APBlocks.NBT_STORAGE.get()), null)); public static final RegistryObject> DISTANCE_DETECTOR = APRegistration.TILE_ENTITIES.register("distance_detector", () -> new BlockEntityType<>(DistanceDetectorEntity::new, Sets.newHashSet(APBlocks.DISTANCE_DETECTOR.get()), null)); + public static final RegistryObject> ULTIMATE_MONITOR = APRegistration.TILE_ENTITIES.register("ultimate_monitor", () -> new BlockEntityType(UltimateMonitorEntity::new, Sets.newHashSet(APBlocks.ULTIMATE_MONITOR.get()), null)); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java b/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java index aab4cdd0b..1a2598874 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java +++ b/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java @@ -1,5 +1,6 @@ package de.srendi.advancedperipherals.common.setup; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.monitor.UltimateBlockMonitor; import de.srendi.advancedperipherals.common.blocks.PlayerDetectorBlock; import de.srendi.advancedperipherals.common.blocks.RedstoneIntegratorBlock; import de.srendi.advancedperipherals.common.blocks.base.APBlockEntityBlock; @@ -39,7 +40,10 @@ protected static void register() { public static final RegistryObject GEO_SCANNER = register("geo_scanner", () -> new APBlockEntityBlock<>(APBlockEntityTypes.GEO_SCANNER, false), () -> new APBlockItem(APBlocks.GEO_SCANNER.get(), APConfig.PERIPHERALS_CONFIG.enableGeoScanner)); public static final RegistryObject COLONY_INTEGRATOR = register("colony_integrator", () -> new APBlockEntityBlock<>(APBlockEntityTypes.COLONY_INTEGRATOR, false), () -> new APBlockItem(APBlocks.COLONY_INTEGRATOR.get(), APConfig.PERIPHERALS_CONFIG.enableColonyIntegrator)); public static final RegistryObject NBT_STORAGE = register("nbt_storage", () -> new APBlockEntityBlock<>(APBlockEntityTypes.NBT_STORAGE, false), () -> new APBlockItem(APBlocks.NBT_STORAGE.get(), APConfig.PERIPHERALS_CONFIG.enableNBTStorage)); - public static final RegistryObject DISTANCE_DETECTOR = register("distance_detector", () -> new APBlockEntityBlock<>(APBlockEntityTypes.DISTANCE_DETECTOR, BlockBehaviour.Properties.of(Material.METAL).noOcclusion(), true), () -> new APBlockItem(APBlocks.DISTANCE_DETECTOR.get(), APConfig.PERIPHERALS_CONFIG.enableNBTStorage)); + public static final RegistryObject DISTANCE_DETECTOR = register("distance_detector", () -> new APBlockEntityBlock<>(APBlockEntityTypes.DISTANCE_DETECTOR, BlockBehaviour.Properties.of(Material.METAL).noOcclusion(), true), () -> new APBlockItem(APBlocks.DISTANCE_DETECTOR.get(), APConfig.PERIPHERALS_CONFIG.enableDistanceDetector)); + public static final RegistryObject ULTIMATE_MONITOR = register("ultimate_monitor", + () -> new UltimateBlockMonitor(BlockBehaviour.Properties.of(Material.BUILDABLE_GLASS).strength(4, 2).noOcclusion().isValidSpawn(APBlocks::never).isRedstoneConductor(APBlocks::never).isSuffocating(APBlocks::never).isViewBlocking(APBlocks::never).lightLevel((state) -> state.getLightEmission()), APBlockEntityTypes.ULTIMATE_MONITOR), + () -> new APBlockItem(APBlocks.ULTIMATE_MONITOR.get(), APConfig.PERIPHERALS_CONFIG.enableUltimateMonitor)); private static RegistryObject registerNoItem(String name, Supplier block) { return APRegistration.BLOCKS.register(name, block); @@ -51,6 +55,10 @@ private static RegistryObject register(String name, Supplie return registryObject; } + public static boolean never(BlockState state, BlockGetter level, BlockPos pos, net.minecraft.world.entity.EntityType entity) { + return false; + } + public static boolean never(BlockState state, BlockGetter level, BlockPos pos) { return false; } diff --git a/src/main/resources/assets/advancedperipherals/models/block/monitor_base.json b/src/main/resources/assets/advancedperipherals/models/block/monitor_base.json new file mode 100644 index 000000000..d3bbbc150 --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/models/block/monitor_base.json @@ -0,0 +1,27 @@ +{ + "parent": "block/block", + "render_type": "minecraft:cutout", + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "texture": "#down", "emissivity": 15, "ambientocclusion": false }, + "up": { "texture": "#up", "emissivity": 15, "ambientocclusion": false }, + "north": { "texture": "#north", "emissivity": 15, "ambientocclusion": false }, + "south": { "texture": "#south", "emissivity": 15, "ambientocclusion": false }, + "west": { "texture": "#west", "emissivity": 15, "ambientocclusion": false }, + "east": { "texture": "#east", "emissivity": 15, "ambientocclusion": false } + } + } + ], + "textures": { + "particle": "#front", + "down": "#top", + "up": "#top", + "north": "#front", + "east": "#side", + "south": "#back", + "west": "#side" + } +} diff --git a/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.fsh b/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.fsh new file mode 100644 index 000000000..78f65482c --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.fsh @@ -0,0 +1,68 @@ +#version 150 + +#moj_import + +#define FONT_WIDTH 6.0 +#define FONT_HEIGHT 9.0 + +uniform sampler2D Sampler0; // Font +uniform usamplerBuffer Tbo; + +layout(std140) uniform MonitorData { + vec4 Palette[16]; + int Width; + int Height; + ivec2 CursorPos; + int CursorColour; +}; +uniform int CursorBlink; + +uniform vec4 ColorModulator; +uniform float FogStart; +uniform float FogEnd; +uniform vec4 FogColor; + +in float vertexDistance; +in vec2 fontPos; + +out vec4 fragColor; + +vec2 texture_corner(int index) { + float x = 1.0 + float(index % 16) * (FONT_WIDTH + 2.0); + float y = 1.0 + float(index / 16) * (FONT_HEIGHT + 2.0); + return vec2(x, y); +} + +vec4 recolour(vec4 texture, int colour) { + return vec4(texture.rgb * Palette[colour].rgb, texture.rgba); +} + +void main() { + vec2 term_pos = vec2(fontPos.x / FONT_WIDTH, fontPos.y / FONT_HEIGHT); + vec2 corner = floor(term_pos); + + ivec2 cell = ivec2(corner); + int index = 3 * (clamp(cell.x, 0, Width - 1) + clamp(cell.y, 0, Height - 1) * Width); + + // 1 if 0 <= x, y < Width, Height, 0 otherwise + vec2 outside = step(vec2(0.0, 0.0), vec2(cell)) * step(vec2(cell), vec2(float(Width) - 1.0, float(Height) - 1.0)); + float mult = outside.x * outside.y; + + int character = int(texelFetch(Tbo, index).r); + int fg = int(texelFetch(Tbo, index + 1).r); + int bg = int(texelFetch(Tbo, index + 2).r); + + vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT); + vec4 charTex = recolour(texture(Sampler0, (texture_corner(character) + pos) / 256.0), fg); + float textTransparency = Palette[fg].a; + + // Applies the cursor on top of the current character if we're blinking and in the current cursor's cell. We do it + // this funky way to avoid branches. + vec4 cursorTex = recolour(texture(Sampler0, (texture_corner(95) + pos) / 256.0), CursorColour); // 95 = '_' + vec4 img = mix(charTex, cursorTex, cursorTex.a * float(CursorBlink) * (CursorPos == cell ? 1.0 : 0.0)); + float textAlpha = img.a * mult * textTransparency; + + vec4 colour = (img.a * mult > 0 ? vec4(img.rgb, textAlpha) : Palette[bg]) * ColorModulator; + + fragColor = linear_fog(colour, vertexDistance, FogStart, FogEnd, FogColor); +} diff --git a/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.json b/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.json new file mode 100644 index 000000000..04973275e --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.json @@ -0,0 +1,19 @@ +{ + "vertex": "advancedperipherals:monitor_tbo", + "fragment": "advancedperipherals:monitor_tbo", + "attributes": [ "Position" ], + "samplers": [ { "name": "Sampler0" } ], + "uniforms": [ + { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "IViewRotMat", "type": "matrix3x3", "count": 9, "values": [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, + { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] }, + { "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] }, + + { "name": "Tbo", "type": "int", "count": 1, "values": [ 3 ] }, + { "name": "CursorBlink", "type": "int", "count": 1, "values": [ 0 ] } + ] +} diff --git a/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.vsh b/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.vsh new file mode 100644 index 000000000..885b20df5 --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/shaders/core/monitor_tbo.vsh @@ -0,0 +1,21 @@ +#version 150 + +#moj_import + +in vec3 Position; +in vec2 UV0; + +uniform mat4 ModelViewMat; +uniform mat4 ProjMat; +uniform mat3 IViewRotMat; +uniform int FogShape; + +out float vertexDistance; +out vec2 fontPos; + +void main() { + gl_Position = ProjMat * ModelViewMat * vec4(Position, 1); + + vertexDistance = fog_distance(ModelViewMat, IViewRotMat * Position, FogShape); + fontPos = UV0; +} diff --git a/src/main/resources/assets/advancedperipherals/textures/block/transparent.png b/src/main/resources/assets/advancedperipherals/textures/block/transparent.png new file mode 100644 index 000000000..432862776 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/transparent.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_0.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_0.png new file mode 100644 index 000000000..932df74c9 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_0.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_1.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_1.png new file mode 100644 index 000000000..9b8e541b5 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_1.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_15.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_15.png new file mode 100644 index 000000000..d26ff56b9 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_15.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_16.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_16.png new file mode 100644 index 000000000..3f007142c Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_16.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_17.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_17.png new file mode 100644 index 000000000..e7f90c3c9 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_17.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_18.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_18.png new file mode 100644 index 000000000..1425de965 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_18.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_19.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_19.png new file mode 100644 index 000000000..59ff8bedb Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_19.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_2.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_2.png new file mode 100644 index 000000000..3c6e465ec Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_2.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_20.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_20.png new file mode 100644 index 000000000..e65d6f6b7 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_20.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_21.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_21.png new file mode 100644 index 000000000..953663a9c Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_21.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_22.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_22.png new file mode 100644 index 000000000..565bb3935 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_22.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_23.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_23.png new file mode 100644 index 000000000..aeb4f6fc8 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_23.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_24.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_24.png new file mode 100644 index 000000000..0045efbda Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_24.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_25.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_25.png new file mode 100644 index 000000000..ffea7b8e0 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_25.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_26.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_26.png new file mode 100644 index 000000000..9d047e8d0 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_26.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_27.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_27.png new file mode 100644 index 000000000..96729e159 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_27.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_28.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_28.png new file mode 100644 index 000000000..76dec1c8b Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_28.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_29.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_29.png new file mode 100644 index 000000000..c8170d688 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_29.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_3.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_3.png new file mode 100644 index 000000000..e42cd59c9 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_3.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_30.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_30.png new file mode 100644 index 000000000..45eb7903f Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_30.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_31.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_31.png new file mode 100644 index 000000000..92d439fc7 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_31.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_32.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_32.png new file mode 100644 index 000000000..55a1c633f Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_32.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_33.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_33.png new file mode 100644 index 000000000..881d99de8 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_33.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_34.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_34.png new file mode 100644 index 000000000..068a59ba6 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_34.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_35.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_35.png new file mode 100644 index 000000000..87f763048 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_35.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_36.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_36.png new file mode 100644 index 000000000..938501b40 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_36.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_37.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_37.png new file mode 100644 index 000000000..a970f8175 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_37.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_38.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_38.png new file mode 100644 index 000000000..91f52201b Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_38.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_39.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_39.png new file mode 100644 index 000000000..c0dc753b6 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_39.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_4.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_4.png new file mode 100644 index 000000000..55a1c633f Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_4.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_40.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_40.png new file mode 100644 index 000000000..53b6811e3 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_40.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_41.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_41.png new file mode 100644 index 000000000..79997fd0d Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_41.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_42.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_42.png new file mode 100644 index 000000000..9053f3261 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_42.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_43.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_43.png new file mode 100644 index 000000000..95bbf5706 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_43.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_44.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_44.png new file mode 100644 index 000000000..1b9270112 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_44.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_45.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_45.png new file mode 100644 index 000000000..845e7fa93 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_45.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_46.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_46.png new file mode 100644 index 000000000..d4cc702af Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_46.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_47.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_47.png new file mode 100644 index 000000000..e2e08d5ef Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_47.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_5.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_5.png new file mode 100644 index 000000000..91f52201b Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_5.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_6.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_6.png new file mode 100644 index 000000000..a970f8175 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_6.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_7.png b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_7.png new file mode 100644 index 000000000..938501b40 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/ultimate_monitor_7.png differ diff --git a/src/main/resources/data/computercraft/lua/rom/autorun/00_advanceperipherals.lua b/src/main/resources/data/computercraft/lua/rom/autorun/00_advanceperipherals.lua new file mode 100644 index 000000000..5bfaa6af2 --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/autorun/00_advanceperipherals.lua @@ -0,0 +1,16 @@ + +settings.define("ap.patch.window", { + description = "Enable window API patch for alpha palette support", + type = "boolean", + default = true, +}) + +-- Not an easter egg +settings.define("ap.power.to.turn.earth.flat", { + type = "number", + default = 0, +}) + +if settings.get("ap.patch.window") then + dofile("rom/patches/advancedperipherals/window.lua") +end diff --git a/src/main/resources/data/computercraft/lua/rom/patches/advancedperipherals/window.lua b/src/main/resources/data/computercraft/lua/rom/patches/advancedperipherals/window.lua new file mode 100644 index 000000000..b2b11db01 --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/patches/advancedperipherals/window.lua @@ -0,0 +1,115 @@ + +local expect = dofile("rom/modules/main/cc/expect.lua").expect + +local tHex = { + [colors.white] = "0", + [colors.orange] = "1", + [colors.magenta] = "2", + [colors.lightBlue] = "3", + [colors.yellow] = "4", + [colors.lime] = "5", + [colors.pink] = "6", + [colors.gray] = "7", + [colors.lightGray] = "8", + [colors.cyan] = "9", + [colors.purple] = "a", + [colors.blue] = "b", + [colors.brown] = "c", + [colors.green] = "d", + [colors.red] = "e", + [colors.black] = "f", +} + +local string_rep = string.rep +local window_create = window.create + +--- patch window.create +function window.create(parent, nX, nY, nWidth, nHeight, bStartVisible) + expect(1, parent, "table") + expect(2, nX, "number") + expect(3, nY, "number") + expect(4, nWidth, "number") + expect(5, nHeight, "number") + expect(6, bStartVisible, "boolean", "nil") + + if parent == term then + error("term is not a recommended window parent, try term.current() instead", 2) + end + + local tPalette = {} + do + for i = 0, 15 do + local c = 2 ^ i + tPalette[c] = { parent.getPaletteColour(c) } + end + end + + local function updatePalette() + for k, v in pairs(tPalette) do + parent.setPaletteColour(k, v[1], v[2], v[3], v[4]) + end + end + + local w = window_create(parent, nX, nY, nWidth, nHeight, bStartVisible) + + function w.isUltimate() + return parent.isUltimate and parent.isUltimate() + end + + --- patch window.setPaletteColour + function w.setPaletteColour(colour, r, g, b, a) + expect(1, colour, "number") + + if tHex[colour] == nil then + error("Invalid color (got " .. colour .. ")" , 2) + end + + expect(2, r, "number", "nil") + expect(3, g, "number", "nil") + expect(4, b, "number", "nil") + expect(5, a, "number", "nil") + local tCol + if g == nil then + tCol = { colours.unpackRGB(r), 1 } + tPalette[colour] = tCol + elseif b == nil then + tCol = { colours.unpackRGB(r), g } + tPalette[colour] = tCol + else + tCol = tPalette[colour] + tCol[1] = r + tCol[2] = g + tCol[3] = b + tCol[4] = a == nil and 1 or a + end + + if bVisible then + return parent.setPaletteColour(colour, tCol[1], tCol[2], tCol[3], tCol[4]) + end + end + + w.setPaletteColor = w.setPaletteColour + + --- patch window.getPaletteColour + function w.getPaletteColour(colour) + expect(1, colour, "number") + if tHex[colour] == nil then + error("Invalid color (got " .. colour .. ")" , 2) + end + local tCol = tPalette[colour] + return tCol[1], tCol[2], tCol[3], tCol[4] + end + + w.getPaletteColor = w.getPaletteColour + + local window_redraw = w.redraw + --- patch window.redraw + function w.redraw() + if w.isVisible() then + window_redraw() + updatePalette() + end + end + + return w +end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/flat.lua b/src/main/resources/data/computercraft/lua/rom/programs/flat.lua index 05956edff..3d640be82 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/flat.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/flat.lua @@ -1 +1,26 @@ -print("The earth is flat, at least in minecraft!") \ No newline at end of file + +print("The earth is flat, at least in minecraft!") + +local power = settings.get("ap.power.to.turn.earth.flat") +settings.set("ap.power.to.turn.earth.flat", power + 1) +settings.save() + +if power >= 100 and power % 10 == 0 then + term.setTextColor(colors.yellow) + term.write('> ') + term.setTextColor(colors.white) + term.setCursorBlink(true) + sleep(1) + term.setCursorBlink(false) + printError('\nERR: power supply is low, entering power saving mode ...') + peripheral.find('monitor', function(_, monitor) + if monitor.isUltimate then + for i = 0, 15 do + local c = 2 ^ i + local r, g, b = monitor.getPaletteColor(c) + monitor.setPaletteColor(c, r, g, b, 0.11) + sleep() + end + end + end) +end