diff --git a/.gitignore b/.gitignore index ddedbd8a..aa56e1e8 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ htmlReport/ *.ipr *.iws +# vs +/.vs + # vscode .settings/ @@ -42,4 +45,5 @@ replay_*.log *.jfr # kotlin -.kotlin/ \ No newline at end of file +.kotlin/ + diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 14b23e36..4b77a040 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -69,6 +69,29 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") implementation(project(":ledger")) + include(project(":ledger")) +} + +sourceSets { + main { + java { + setIncludes( + listOf( + "heckerpowered/matrix/mixin/CameraMixin.java", + "heckerpowered/matrix/mixin/DamageSourceMixin.java", + "heckerpowered/matrix/mixin/DeltaTrackerTimerMixin.java", + "heckerpowered/matrix/mixin/EntityMixin.java", + "heckerpowered/matrix/mixin/GameRendererStandaloneMixin.java", + "heckerpowered/matrix/mixin/KeyboardMixin.java", + "heckerpowered/matrix/mixin/LevelMixin.java", + "heckerpowered/matrix/mixin/LivingEntityMixin.java", + "heckerpowered/matrix/mixin/MinecraftMixin.java", + "heckerpowered/matrix/mixin/MinecraftServerMixin.java", + "heckerpowered/matrix/mixin/MixinInGameHud.java", + ) + ) + } + } } tasks.test { @@ -108,4 +131,4 @@ tasks.jar { from("LICENSE") { rename { "${it}_${archiveBaseName}" } } -} \ No newline at end of file +} diff --git a/common/src/main/generated/assets/matrix/lang/en_us.json b/common/src/main/generated/assets/matrix/lang/en_us.json index 75bb6fa0..e74f5d43 100644 --- a/common/src/main/generated/assets/matrix/lang/en_us.json +++ b/common/src/main/generated/assets/matrix/lang/en_us.json @@ -83,8 +83,12 @@ "item.minecraft.potion.effect.angered": "Potion of Angered", "item.minecraft.splash_potion.effect.angered": "Slash Potion of Angered", "itemGroup.matrix": "Matrix", + "key.category.matrix.key_category": "Matrix", "key.categories.matrix": "Matrix", + "key.categories.matrix.key_category": "Matrix", "key.matrix.next_magic": "Next magic", + "key.matrix.overclock_magic": "Overclock or underclock magic", + "key.matrix.overclock_mana": "Overclock or underclock mana", "key.matrix.previous_magic": "Previous magic", "key.matrix.use_magic": "Channel magic", "matrix.borrowed_time_charge.description": "Borrowed Time Charge: ", @@ -134,6 +138,10 @@ "matrix.magic.tuck_in.name": "Tuck In", "matrix.magic_available": "Ready", "matrix.magic_available.mana_not_enough": "Insufficient Mana Available", + "matrix.magic.available_status.channel_queue_full": "Queue Full", + "matrix.magic.available_status.channel_queue_locked": "Queue Locked", + "matrix.magic.available_status.insufficient_mana": "Insufficient Mana", + "matrix.magic.available_status.target_missing": "Target Missing", "matrix.magic_channel_queue_full": "Queue Full", "matrix.magic_channel_queue_locked": "Queue Locked", "matrix.magic_target_immune": "Target Immune", @@ -142,6 +150,9 @@ "matrix.mana": "Mana", "matrix.mana_cost_increased": "Mana cost increased by", "matrix.mana_cost_reduced": "Mana cost reduced by", + "matrix.hud.magic_list": "Magic selection", + "matrix.hud.selected_magic": "Selected magic", + "matrix.hud.target": "Target", "matrix.overclock.magic": "Overclock or Underclock Magic", "matrix.overclock.mana": "Overclock or Underclock Mana", "matrix.overclock.switch": "Switch Overclock or Underclock", @@ -157,4 +168,4 @@ "matrix.wizard_helmet.accumulated_mana_delta": "Spent/Recovered Mana: ", "matrix.wizard_helmet.blood_pact_conversion_efficiency": "Blood Pact Conversion Efficiency: ", "matrix.wizard_helmet.load.description": "Current load: " -} \ No newline at end of file +} diff --git a/common/src/main/generated/assets/matrix/lang/zh_cn.json b/common/src/main/generated/assets/matrix/lang/zh_cn.json index 776b6ce1..6e5e709f 100644 --- a/common/src/main/generated/assets/matrix/lang/zh_cn.json +++ b/common/src/main/generated/assets/matrix/lang/zh_cn.json @@ -86,8 +86,12 @@ "item.minecraft.potion.effect.angered": "狂暴药水", "item.minecraft.slash_potion.effect.angered": "喷溅型狂暴药水", "itemGroup.matrix": "Matrix", + "key.category.matrix.key_category": "Matrix", "key.categories.matrix": "Matrix", + "key.categories.matrix.key_category": "Matrix", "key.matrix.next_magic": "下一个魔法", + "key.matrix.overclock_magic": "超频或降频魔法", + "key.matrix.overclock_mana": "超频或降频法力", "key.matrix.previous_magic": "上一个魔法", "key.matrix.use_magic": "引导魔法", "matrix.borrowed_time_charge.description": "实境扭曲充能: ", @@ -137,6 +141,10 @@ "matrix.magic.tuck_in.name": "温柔哄睡", "matrix.magic_available": "就绪", "matrix.magic_available.mana_not_enough": "可用法力不足", + "matrix.magic.available_status.channel_queue_full": "队列已满", + "matrix.magic.available_status.channel_queue_locked": "队列已锁定", + "matrix.magic.available_status.insufficient_mana": "可用法力不足", + "matrix.magic.available_status.target_missing": "目标缺失", "matrix.magic_channel_queue_full": "队列已满", "matrix.magic_channel_queue_locked": "队列已锁定", "matrix.magic_target_immune": "目标免疫", @@ -145,6 +153,9 @@ "matrix.mana": "法力值", "matrix.mana_cost_increased": "法力消耗增加", "matrix.mana_cost_reduced": "法力消耗降低", + "matrix.hud.magic_list": "魔法选择", + "matrix.hud.selected_magic": "当前魔法", + "matrix.hud.target": "目标", "matrix.overclock.magic": "超频或降频魔法", "matrix.overclock.mana": "超频或降频法力", "matrix.overclock.switch": "切换超频或降频", @@ -160,4 +171,4 @@ "matrix.wizard_helmet.accumulated_mana_delta": "已使用/回复的法力: ", "matrix.wizard_helmet.blood_pact_conversion_efficiency": "血之契约兑换效率: ", "matrix.wizard_helmet.load.description": "当前负载: " -} \ No newline at end of file +} diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json index 2f8f1889..1683a430 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json index 49e88831..948c84b4 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json index 33568b28..7253c35f 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json index ef58be90..14d8cf76 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json index 34f79f22..06494b53 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json index 0f489250..17f1612b 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json index 8790a21d..b7bc192a 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json index 95e93942..8535e263 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json index 4ea6041f..0e0c8d17 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json index a6f4aaee..90842c7f 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json index e40d3bd2..e54afb3a 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json index bc337542..244d2af9 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json index a87a53ba..f9e23679 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/recipe/coal_axe.json b/common/src/main/generated/data/matrix/recipe/coal_axe.json index d0c1372e..29571ec8 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_axe.json +++ b/common/src/main/generated/data/matrix/recipe/coal_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_boots.json b/common/src/main/generated/data/matrix/recipe/coal_boots.json index dbbafc7c..5752c9ab 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_boots.json +++ b/common/src/main/generated/data/matrix/recipe/coal_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:coal_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_chestplate.json b/common/src/main/generated/data/matrix/recipe/coal_chestplate.json index e37a1c19..b759177b 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/coal_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:coal_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_helmet.json b/common/src/main/generated/data/matrix/recipe/coal_helmet.json index 8602e333..74791ffe 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/coal_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:coal_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_hoe.json b/common/src/main/generated/data/matrix/recipe/coal_hoe.json index 06518122..5f04a78e 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/coal_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_leggings.json b/common/src/main/generated/data/matrix/recipe/coal_leggings.json index 6071780d..687e3785 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/coal_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:coal_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json b/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json index d6492527..ec10aece 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_shovel.json b/common/src/main/generated/data/matrix/recipe/coal_shovel.json index f8286253..caed626a 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/coal_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_sword.json b/common/src/main/generated/data/matrix/recipe/coal_sword.json index c462f3cb..b75b188e 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_sword.json +++ b/common/src/main/generated/data/matrix/recipe/coal_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_axe.json b/common/src/main/generated/data/matrix/recipe/emerald_axe.json index e8f3588c..48a87628 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_axe.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_boots.json b/common/src/main/generated/data/matrix/recipe/emerald_boots.json index 6dfaa36a..0b5ed9a2 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_boots.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:emerald_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json b/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json index 26ff3e3f..04995c4d 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:emerald_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_helmet.json b/common/src/main/generated/data/matrix/recipe/emerald_helmet.json index bfda6e97..28a3c461 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:emerald_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_hoe.json b/common/src/main/generated/data/matrix/recipe/emerald_hoe.json index 6a734683..04f13a22 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_leggings.json b/common/src/main/generated/data/matrix/recipe/emerald_leggings.json index 8020505a..29546863 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:emerald_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json b/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json index 3f15f04b..6c232dc9 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_shovel.json b/common/src/main/generated/data/matrix/recipe/emerald_shovel.json index 6746e0af..737b0160 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_sword.json b/common/src/main/generated/data/matrix/recipe/emerald_sword.json index 0050518e..925ddcaa 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_sword.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json index 4e45780a..5fcbc3a8 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json index a9a607be..8a9081e5 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json index 35529825..4acd798d 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json index 41c6fde3..67ecd4fb 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json index 1e63da9d..2a90bc22 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json index 3fb837f3..ecf17194 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json index 3b05b2a3..79a38505 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json index 033c78e4..28ef0499 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json index 737a48e9..31e08985 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_axe.json b/common/src/main/generated/data/matrix/recipe/redstone_axe.json index 90b6b9e7..118a6262 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_axe.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_boots.json b/common/src/main/generated/data/matrix/recipe/redstone_boots.json index 6ada5096..df0290df 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_boots.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:redstone_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json b/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json index 9732c6b0..412cb605 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:redstone_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_helmet.json b/common/src/main/generated/data/matrix/recipe/redstone_helmet.json index 8192bedf..38312698 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:redstone_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_hoe.json b/common/src/main/generated/data/matrix/recipe/redstone_hoe.json index 0e2f4757..5d77e9ea 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_leggings.json b/common/src/main/generated/data/matrix/recipe/redstone_leggings.json index 7705b1d0..f8e05fd1 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:redstone_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json b/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json index 1aab87fc..6b95f43f 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_shovel.json b/common/src/main/generated/data/matrix/recipe/redstone_shovel.json index 7e957933..0dc26cf2 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json b/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json index afe099a6..2f67867a 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json @@ -1,4 +1,3 @@ { - "type": "minecraft:redstone_suit_charger", - "category": "misc" + "type": "matrix:redstone_suit_charger" } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_sword.json b/common/src/main/generated/data/matrix/recipe/redstone_sword.json index b2b240bc..91fa0d6e 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_sword.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_boots.json b/common/src/main/generated/data/matrix/recipe/stone_boots.json index 0fc952fe..1687cbb9 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_boots.json +++ b/common/src/main/generated/data/matrix/recipe/stone_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:stone_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_chestplate.json b/common/src/main/generated/data/matrix/recipe/stone_chestplate.json index a05c0c87..f41dbde8 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/stone_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:stone_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_helmet.json b/common/src/main/generated/data/matrix/recipe/stone_helmet.json index 9ba3a44a..933c005d 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/stone_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:stone_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_leggings.json b/common/src/main/generated/data/matrix/recipe/stone_leggings.json index 65c27128..cbda85cb 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/stone_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:stone_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_boots.json b/common/src/main/generated/data/matrix/recipe/wooden_boots.json index 215e5f5a..2af07f41 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_boots.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "#minecraft:planks" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:wooden_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json b/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json index eeb6d2e4..f8b45d4b 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "tag": "minecraft:planks" - } + "#": "#minecraft:planks" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:wooden_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_helmet.json b/common/src/main/generated/data/matrix/recipe/wooden_helmet.json index ebbc3f28..ebba0cd2 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "tag": "minecraft:planks" - } + "#": "#minecraft:planks" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:wooden_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_leggings.json b/common/src/main/generated/data/matrix/recipe/wooden_leggings.json index 6629fd93..28ff886f 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "tag": "minecraft:planks" - } + "#": "#minecraft:planks" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:wooden_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/tags/damage_type/magic.json b/common/src/main/generated/data/matrix/tags/damage_type/magic.json index 72d9e2f7..aff06fa1 100644 --- a/common/src/main/generated/data/matrix/tags/damage_type/magic.json +++ b/common/src/main/generated/data/matrix/tags/damage_type/magic.json @@ -1,5 +1,8 @@ { "values": [ - "matrix:magic" + { + "id": "matrix:magic", + "required": false + } ] } \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/damage_type/bypasses_shield.json b/common/src/main/generated/data/minecraft/tags/damage_type/bypasses_shield.json index 72d9e2f7..aff06fa1 100644 --- a/common/src/main/generated/data/minecraft/tags/damage_type/bypasses_shield.json +++ b/common/src/main/generated/data/minecraft/tags/damage_type/bypasses_shield.json @@ -1,5 +1,8 @@ { "values": [ - "matrix:magic" + { + "id": "matrix:magic", + "required": false + } ] } \ No newline at end of file diff --git a/common/src/main/java/heckerpowered/matrix/mixin/CameraMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/CameraMixin.java new file mode 100644 index 00000000..4d01b24e --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/CameraMixin.java @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import heckerpowered.matrix.client.MatrixHud; +import heckerpowered.matrix.client.TimeController; +import heckerpowered.matrix.client.render.MatrixRenderSystem; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.renderer.state.level.CameraRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Camera.class) +class CameraMixin { + private CameraMixin() { + } + + @Inject(method = "getCameraEntityPartialTicks", at = @At("RETURN"), cancellable = true) + private void getCameraEntityPartialTicks(DeltaTracker deltaTracker, CallbackInfoReturnable cir) { + if (TimeController.getPlayerStandaloneRenderTick()) { + cir.setReturnValue(TimeController.standaloneRenderTickCounter.getTickDelta(true)); + } + } + + @Inject(method = "calculateFov", at = @At("RETURN"), cancellable = true) + private void matrix$calculateFov(float partialTick, CallbackInfoReturnable cir) { + cir.setReturnValue(cir.getReturnValueF() * (float) MatrixHud.fovAnimation.getAnimatedValue()); + } + + @Inject(method = "calculateHudFov", at = @At("RETURN"), cancellable = true) + private void matrix$calculateHudFov(float partialTick, CallbackInfoReturnable cir) { + cir.setReturnValue(cir.getReturnValueF() * (float) MatrixHud.fovAnimation.getAnimatedValue()); + } + + @Inject(method = "extractRenderState", at = @At("TAIL")) + private void matrix$extractRenderState(CameraRenderState renderState, float partialTick, CallbackInfo ci) { + MatrixRenderSystem.setupMatrix((Camera) (Object) this, renderState.projectionMatrix); + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java index 4da7edf9..e95b1b17 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java @@ -25,4 +25,14 @@ class DamageSourceMixin implements MatrixDamageSource { public void matrix$setAdditionalDamage(boolean b) { isAdditionalDamage = b; } -} \ No newline at end of file + + @Override + public boolean isAdditionalDamage() { + return isAdditionalDamage; + } + + @Override + public void setAdditionalDamage(boolean b) { + isAdditionalDamage = b; + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/DeltaTrackerTimerMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/DeltaTrackerTimerMixin.java new file mode 100644 index 00000000..2f1269e6 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/DeltaTrackerTimerMixin.java @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import heckerpowered.matrix.client.TimeController; +import it.unimi.dsi.fastutil.floats.FloatUnaryOperator; +import net.minecraft.client.DeltaTracker; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(DeltaTracker.Timer.class) +class DeltaTrackerTimerMixin { + @Shadow + private float deltaTicks; + + @Shadow + private float deltaTickResidual; + + @Shadow + private long lastMs; + + @Shadow + @Final + private float msPerTick; + + @Shadow + @Final + private FloatUnaryOperator targetMsptProvider; + + private DeltaTrackerTimerMixin() { + } + + @Inject(method = "advanceGameTime", at = @At("HEAD"), cancellable = true) + private void advanceGameTime(long timeMillis, CallbackInfoReturnable cir) { + if (!TimeController.shouldScaleClientGameTime()) { + return; + } + + final var timeScale = TimeController.getClientGameTimeScale(); + final var targetMsPerTick = targetMsptProvider.apply(msPerTick); + if (targetMsPerTick <= 0.0F) { + return; + } + + deltaTicks = (timeMillis - lastMs) / (targetMsPerTick / timeScale); + lastMs = timeMillis; + deltaTickResidual += deltaTicks; + final var ticks = (int) deltaTickResidual; + deltaTickResidual -= ticks; + cir.setReturnValue(ticks); + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/GameRendererStandaloneMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/GameRendererStandaloneMixin.java new file mode 100644 index 00000000..9b340af3 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/GameRendererStandaloneMixin.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import heckerpowered.matrix.client.render.PostProcessRenderer; +import heckerpowered.matrix.client.shader.BlurRenderer; +import heckerpowered.matrix.client.TimeController; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.renderer.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GameRenderer.class) +class GameRendererStandaloneMixin { + private GameRendererStandaloneMixin() { + } + + @Inject(method = "resize", at = @At("TAIL")) + private void matrix$onResize(int width, int height, CallbackInfo ci) { + BlurRenderer.onResize(width, height); + PostProcessRenderer.onResize(width, height); + } + + @Inject( + method = "render", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/render/GuiRenderer;render()V", + shift = At.Shift.BEFORE + ) + ) + private void matrix$beforeGuiRender(DeltaTracker deltaTracker, boolean tick, CallbackInfo ci) { + PostProcessRenderer.renderToMinecraftFramebuffer(); + } + + @ModifyVariable(method = "renderItemInHand", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private float useStandaloneHandTickDelta(float tickDelta) { + if (TimeController.getPlayerStandaloneRenderTick()) { + return TimeController.standaloneRenderTickCounter.getTickDelta(true); + } + return tickDelta; + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java index eabb1b96..adf1663d 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java @@ -6,17 +6,18 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.client.MatrixHud; -import net.minecraft.client.Keyboard; +import net.minecraft.client.KeyboardHandler; +import net.minecraft.client.input.KeyEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(Keyboard.class) +@Mixin(KeyboardHandler.class) class KeyboardMixin { - @Inject(method = "onKey", at = @At("HEAD"), cancellable = true) - private void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { - if (MatrixHud.onKey(window, key, scancode, action, modifiers)) { + @Inject(method = "keyPress", at = @At("HEAD"), cancellable = true) + private void onKey(long window, int action, KeyEvent event, CallbackInfo ci) { + if (MatrixHud.onKey(window, event.key(), event.scancode(), action, event.modifiers())) { ci.cancel(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java index b08dd488..135fdf23 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java @@ -5,18 +5,10 @@ package heckerpowered.matrix.mixin; -import com.llamalad7.mixinextras.expression.Definition; -import com.llamalad7.mixinextras.expression.Expression; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalDoubleRef; -import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.serialization.Codec; -import heckerpowered.matrix.Matrix; import heckerpowered.matrix.common.combat.damage.*; import heckerpowered.matrix.common.entity.EntityPolarity; import heckerpowered.matrix.common.entity.ability.HealMeasurementScope; @@ -46,7 +38,6 @@ import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -81,29 +72,29 @@ public LivingEntityMixin(EntityType type, Level level) { @Shadow public abstract ItemStack getItemBySlot(EquipmentSlot slot); - @Intrinsic(displace = true) - private LivingEntity self() { + @Unique + private LivingEntity livingSelf() { return (LivingEntity) (Object) this; } - @Inject(method = "die", at = @At("HEAD"), cancellable = true) - private void die(DamageSource source, CallbackInfo ci, @Local(argsOnly = true, name = "source") LocalRef sourceReference) { - if (self() instanceof Player) return; + @WrapMethod(method = "die") + private void wrapDie(DamageSource source, Operation original) { + if (livingSelf() instanceof Player) { + original.call(source); + return; + } if ((polarity & EntityPolarity.SUPPRESS_DEATH) != 0) { - ci.cancel(); return; } - final var context = new LivingDeathContext(self(), source); + final var context = new LivingDeathContext(livingSelf(), source); EntityRulePipeline.onLivingDeath(context); if (!context.getAllow()) { context.applyDecision(); - ci.cancel(); return; } - if (context.getDamageSource() != source) { - sourceReference.set(context.getDamageSource()); - } + + original.call(context.getDamageSource()); } @WrapOperation(method = "hurtServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;die(Lnet/minecraft/world/damagesource/DamageSource;)V")) @@ -149,80 +140,50 @@ private void actuallyHurt(ServerLevel level, DamageSource source, float dmg, Cal } } - @Inject(method = "hurtServer", at = @At("HEAD"), cancellable = true) - private void hurtServer( - ServerLevel level, DamageSource source, float damage, CallbackInfoReturnable cir, - @Local(argsOnly = true, name = "damage") LocalFloatRef amountReference, - @Share(value = "rawDamage", namespace = Matrix.MOD_ID) LocalFloatRef rawDamageReference - ) { + @WrapMethod(method = "hurtServer") + private boolean wrapHurtServer(ServerLevel level, DamageSource source, float damage, Operation original) { if ((polarity & EntityPolarity.REJECT_DAMAGE) != 0L) { - cir.setReturnValue(false); - return; + return false; } final var self = (LivingEntity) (Object) this; final var attemptContext = new DamageAttemptContext(self, source, damage); DamagePipeline.attempt(attemptContext); if (attemptContext.isCancelled()) { - cir.setReturnValue(false); - return; + return false; } - rawDamageReference.set(damage); final var computationContext = new DamageComputationContext(self, source, damage); DamagePipeline.computation(computationContext); if (computationContext.isCancelled()) { - cir.setReturnValue(false); - return; + return false; } - amountReference.set(computationContext.computeDamage()); - } - - @ModifyArg( - method = "hurtServer", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;F)V"), - index = 1 - ) - private DamageSource wrapSource( - DamageSource source, - @Share(value = "rawDamage", namespace = Matrix.MOD_ID) LocalFloatRef rawDamageReference - ) { - return new DamageSourceEnvelope(source, rawDamageReference.get()); - } - - @ModifyVariable(method = "actuallyHurt", at = @At("HEAD"), argsOnly = true, name = "source") - private DamageSource unwrapSource(DamageSource source, @Share(value = "rawDamage", namespace = Matrix.MOD_ID) LocalFloatRef rawDamageReference) { - if (source instanceof final DamageSourceEnvelope envelope) { - rawDamageReference.set(envelope.getRawDamage()); - return envelope.getOrigin(); - } - rawDamageReference.set(Float.NaN); - return source; + return original.call(level, new DamageSourceEnvelope(source, damage), computationContext.computeDamage()); } - @Definition(id = "getDamageAfterMagicAbsorb", method = "Lnet/minecraft/world/entity/LivingEntity;getDamageAfterMagicAbsorb(Lnet/minecraft/world/damagesource/DamageSource;F)F") - @Expression("? = ?.getDamageAfterMagicAbsorb(?, ?)") @ModifyVariable( method = "actuallyHurt", - at = @At(value = "MIXINEXTRAS:EXPRESSION", shift = At.Shift.AFTER), argsOnly = true, name = "dmg") + at = @At(value = "STORE"), + ordinal = 1) private float actuallyHurt( float dmg, - @Local(argsOnly = true, name = "source") DamageSource source, - @Share(value = "rawDamage", namespace = Matrix.MOD_ID) LocalFloatRef rawDamageReference) { + ServerLevel level, + DamageSource source, + float originalDamage) { final var self = (LivingEntity) (Object) this; - final float referencedRawDamage = rawDamageReference.get(); - final float rawDamage = Float.isFinite(referencedRawDamage) ? referencedRawDamage : dmg; + final var originSource = source instanceof final DamageSourceEnvelope envelope ? envelope.getOrigin() : source; + final float rawDamage = source instanceof final DamageSourceEnvelope envelope ? envelope.getRawDamage() : originalDamage; - final var realizationContext = new DamageRealizationContext(self, source, rawDamage, dmg); + final var realizationContext = new DamageRealizationContext(self, originSource, rawDamage, dmg); DamagePipeline.realization(realizationContext); final var retention = realizationContext.getRetention(); final var realizedDamage = realizationContext.getRealizedDamage(); - final var outcomeContext = new DamageOutcomeContext(self, source, rawDamage, dmg, retention); + final var outcomeContext = new DamageOutcomeContext(self, originSource, rawDamage, dmg, retention); DamagePipeline.outcome(outcomeContext); - final var settlementContext = new DamageSettlementContext(self, source, rawDamage, dmg, realizedDamage); + final var settlementContext = new DamageSettlementContext(self, originSource, rawDamage, dmg, realizedDamage); DamagePipeline.settlement(settlementContext); return settlementContext.getRemainingDamage(); @@ -231,7 +192,7 @@ private float actuallyHurt( /** * @Inject(method = "die", at = @At("HEAD"), cancellable = true) * private void onDeath(DamageSource damageSource, CallbackInfo info) { - * if (LivingDeathCallback.EVENT.invoker().onDeath(self(), damageSource) == ActionResult.FAIL) { + * if (LivingDeathCallback.EVENT.invoker().onDeath(livingSelf(), damageSource) == ActionResult.FAIL) { * info.cancel(); * return; * } @@ -241,7 +202,7 @@ private float actuallyHurt( *

* // TODO: Consider to move this logic to the event. * var restoreAmount = 0; - * final var self = self(); + * final var self = livingSelf(); * final var manaOverload = MatrixStatusEffects.getManaOverloadEffect(); * final var effect = self.getStatusEffect(manaOverload); * if (effect != null) { @@ -256,14 +217,14 @@ private float actuallyHurt( @Inject(method = "addAdditionalSaveData", at = @At("HEAD")) private void addAdditionalSaveData(ValueOutput output, CallbackInfo ci) { - LivingPersistencePipeline.save(new LivingSaveContext(self(), output)); + LivingPersistencePipeline.save(new LivingSaveContext(livingSelf(), output)); output.putLong("matrix_polarity", polarity); - output.putFloat("health_spoof_value", healthSpoofValue); + output.putFloat("matrix_health_spoof_value", healthSpoofValue); } @Inject(method = "readAdditionalSaveData", at = @At("TAIL")) private void readAdditionalSaveData(ValueInput input, CallbackInfo ci) { - LivingPersistencePipeline.load(new LivingLoadContext(self(), input)); + LivingPersistencePipeline.load(new LivingLoadContext(livingSelf(), input)); input.read("matrix_polarity", Codec.LONG).ifPresent(this::matrix$setPolarity); input.read("matrix_health_spoof_value", Codec.FLOAT).ifPresent(this::matrix$setHealthSpoofValue); } @@ -271,14 +232,14 @@ private void readAdditionalSaveData(ValueInput input, CallbackInfo ci) { @Inject(method = "getAttributeValue", at = @At("RETURN"), cancellable = true) public void getAttributeValue(Holder attribute, CallbackInfoReturnable cir) { final var attributeValue = cir.getReturnValueD(); - final var context = new AttributeComputationContext(self(), attribute, attributeValue); + final var context = new AttributeComputationContext(livingSelf(), attribute, attributeValue); EntityRulePipeline.onComputation(context); cir.setReturnValue(context.getFinalValue()); } @Inject(method = "removeEffect", at = @At(value = "HEAD"), cancellable = true) private void removeEffect(Holder effect, CallbackInfoReturnable cir) { - final var context = new EffectRemovalContext(self(), effect); + final var context = new EffectRemovalContext(livingSelf(), effect); EntityRulePipeline.onEffectRemoval(context); if (!context.isAllowed()) { cir.cancel(); @@ -288,37 +249,27 @@ private void removeEffect(Holder effect, CallbackInfoReturnable effects, CallbackInfo ci) { for (final MobEffectInstance effect : effects) { - final var context = new EffectRemovedContext(self(), effect); + final var context = new EffectRemovedContext(livingSelf(), effect); EntityRulePipeline.onEffectRemoved(context); } } @Inject(method = "onEquipItem", at = @At("HEAD")) private void onEquipStack(EquipmentSlot slot, ItemStack oldStack, ItemStack stack, CallbackInfo ci) { - final var context = new EquipItemContext(self(), slot, oldStack, stack); + final var context = new EquipItemContext(livingSelf(), slot, oldStack, stack); EntityRulePipeline.onEquipItem(context); } - @Inject(method = "knockback", at = @At("HEAD"), cancellable = true) - private void knockback( - double power, double x, double z, CallbackInfo ci, - @Local(argsOnly = true, name = "power") LocalDoubleRef powerReference, - @Local(argsOnly = true, name = "xd") LocalDoubleRef xReference, - @Local(argsOnly = true, name = "zd") LocalDoubleRef zReference) { - final var context = new KnockbackContext(self(), power, x, z); + @WrapMethod(method = "knockback") + private void wrapKnockback(double power, double x, double z, Operation original) { + final var context = new KnockbackContext(livingSelf(), power, x, z); EntityRulePipeline.onKnockback(context); if (context.isCancelled()) { - ci.cancel(); return; } - final var newPower = context.getPower(); - final var newX = context.getX(); - final var newZ = context.getZ(); - if (power != newPower) powerReference.set(newPower); - if (x != newX) xReference.set(newX); - if (z != newZ) zReference.set(newZ); + original.call(context.getPower(), context.getX(), context.getZ()); } @Inject(method = "canStandOnFluid", at = @At("HEAD"), cancellable = true) @@ -333,14 +284,14 @@ private void canWalkOnFluid(FluidState fluid, CallbackInfoReturnable ci // stand on, then stepping back down to the walkable fluid surface. Air blocks use // Fluids.EMPTY as their fluid state. If EMPTY is also treated as walkable, the // search may keep moving upward through air forever and cause an infinite loop. - if (WardenSuitKt.isWardenArmorAngered(self()) && fluid != Fluids.EMPTY.defaultFluidState()) { + if (WardenSuitKt.isWardenArmorAngered(livingSelf()) && fluid != Fluids.EMPTY.defaultFluidState()) { cir.setReturnValue(true); } } @Inject(method = "canBeAffected", at = @At("RETURN"), cancellable = true) private void canBeAffected(MobEffectInstance newEffect, CallbackInfoReturnable cir) { - final var context = new EffectRestrictionContext(self(), newEffect); + final var context = new EffectRestrictionContext(livingSelf(), newEffect); EntityRulePipeline.canBeAffected(context); if (!context.isAllowed()) { cir.setReturnValue(false); @@ -361,9 +312,9 @@ private void canBreatheUnderwater(CallbackInfoReturnable cir) { @WrapMethod(method = "heal") private void heal(float heal, Operation original) { - final var previousHealth = self().getHealth(); + final var previousHealth = livingSelf().getHealth(); - final var context = new LivingHealContext(self(), heal); + final var context = new LivingHealContext(livingSelf(), heal); EntityRulePipeline.onHeal(context); final var resolvedAmount = (float) (context.getHealAmount() * context.getMultiplier()); @@ -375,7 +326,7 @@ private void heal(float heal, Operation original) { if (stack != null) { stack.setResolvedAmount(resolvedAmount); - final var restoredHealth = self().getHealth() - previousHealth; + final var restoredHealth = livingSelf().getHealth() - previousHealth; stack.setRestoredHealth(Math.max(restoredHealth, 0)); } } @@ -403,13 +354,14 @@ private void getMaxHealth(CallbackInfoReturnable cir) { } } - @Inject(method = "setHealth", at = @At("HEAD")) - private void setHealth(float health, CallbackInfo ci, @Local(argsOnly = true, name = "health") LocalFloatRef healthReference) { + @ModifyVariable(method = "setHealth", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private float setHealth(float health) { if ((polarity & EntityPolarity.HEALTH_SPOOF) != 0L) { - healthReference.set(Math.max(health, getSpoofedHealth())); + return Math.max(health, getSpoofedHealth()); } else if ((polarity & EntityPolarity.ZERO_HEALTH_SPOOF) != 0) { - healthReference.set(0F); + return 0F; } + return health; } @Inject(method = "attackable", at = @At("HEAD"), cancellable = true) @@ -445,4 +397,4 @@ private void isInvulnerableTo(CallbackInfoReturnable cir) { public @NonNull Map matrix$getChannelQueues() { return channelQueues; } -} \ No newline at end of file +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftMixin.java new file mode 100644 index 00000000..06a41e84 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftMixin.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import heckerpowered.matrix.client.TimeController; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Util; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +abstract class MinecraftMixin { + @Shadow + private volatile boolean pause; + + private MinecraftMixin() { + } + + @Shadow + private boolean isLevelRunningNormally() { + throw new AssertionError(); + } + + @Inject(method = "runTick", at = @At("HEAD")) + private void beginRenderTick(boolean tick, CallbackInfo ci) { + TimeController.beginRenderTick(Util.getMillis(), tick); + } + + @Inject(method = "runTick", at = @At("TAIL")) + private void updateStandaloneRenderTickState(boolean tick, CallbackInfo ci) { + TimeController.standaloneRenderTickCounter.tick(pause); + TimeController.standaloneRenderTickCounter.setTickFrozen(!isLevelRunningNormally()); + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java index 897563ed..51577a19 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java @@ -5,54 +5,59 @@ package heckerpowered.matrix.mixin; -import heckerpowered.matrix.extension.MatrixMinecraftServer; +import heckerpowered.matrix.core.ServerTickTiming; +import heckerpowered.matrix.core.ServerTimeRatio; +import heckerpowered.matrix.core.ServerTimeWarpLease; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ServerTickRateManager; -import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.function.BooleanSupplier; @Mixin(MinecraftServer.class) -@Implements(@Interface(iface = MatrixMinecraftServer.class, prefix = "matrix$")) -class MinecraftServerMixin implements MatrixMinecraftServer { +class MinecraftServerMixin { @Shadow @Final private ServerTickRateManager tickRateManager; - @Unique - long matrix$tickStartTimeNanos; - - @Unique - long matrix$tickEndTimeNanos; - - - private MinecraftServerMixin() { } @Inject(method = "tickServer", at = @At("HEAD")) private void tick(BooleanSupplier haveTime, CallbackInfo ci) { - matrix$tickStartTimeNanos = System.nanoTime(); - matrix$tickEndTimeNanos = matrix$tickStartTimeNanos + tickRateManager.nanosecondsPerTick(); + final var tickStartTimeNanos = System.nanoTime(); + ServerTickTiming.update( + (MinecraftServer) (Object) this, + tickStartTimeNanos, + tickStartTimeNanos + tickRateManager.nanosecondsPerTick() + ); } - public long matrix$getTickStartTimeNanos() { - return matrix$tickStartTimeNanos; + @Inject(method = "stopServer", at = @At("HEAD")) + private void stopServer(CallbackInfo ci) { + matrix$restoreNormalTime(); } - public void matrix$setTickStartTimeNanos(long l) { - matrix$tickStartTimeNanos = l; + @Inject(method = "saveEverything", at = @At("HEAD")) + private void saveEverything(boolean suppressLogs, boolean flush, boolean force, CallbackInfoReturnable ci) { + matrix$restoreNormalTime(); } - public long matrix$getTickEndTimeNanos() { - return matrix$tickEndTimeNanos; + @Inject(method = "saveAllChunks", at = @At("HEAD")) + private void saveAllChunks(boolean suppressLogs, boolean flush, boolean force, CallbackInfoReturnable ci) { + matrix$restoreNormalTime(); } - public void matrix$setTickEndTimeNanos(long l) { - matrix$tickEndTimeNanos = l; + private void matrix$restoreNormalTime() { + final var server = (MinecraftServer) (Object) this; + ServerTimeWarpLease.clear(server); + ServerTimeRatio.restoreNormalTickDuration(server); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java b/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java index 336ba496..d598749f 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java @@ -5,60 +5,36 @@ package heckerpowered.matrix.mixin; -import heckerpowered.matrix.Matrix; +import com.mojang.blaze3d.pipeline.RenderPipeline; import heckerpowered.matrix.client.MatrixHud; -import heckerpowered.matrix.common.effect.ModMobEffects; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.util.Identifier; -import org.joml.Matrix4f; -import org.joml.Matrix4fStack; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.Hud; +import net.minecraft.resources.Identifier; +import org.joml.Vector2f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(InGameHud.class) +@Mixin(Hud.class) class MixinInGameHud { private MixinInGameHud() { } - @Inject(method = "renderMainHud", at = @At("HEAD")) - private void renderMainHud(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { - // UIBlurShader.startUIOverlayDrawing(context, tickCounter.getTickDelta(false)); - } - - @Redirect(method = "drawHeart", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud$HeartType;getTexture(ZZZ)Lnet/minecraft/util/Identifier;")) - private Identifier getTexture(InGameHud.HeartType instance, boolean hardcore, boolean half, boolean blinking) { - final var minecraft = MinecraftClient.getInstance(); - final var player = minecraft.player; - if (instance == InGameHud.HeartType.NORMAL && player != null && player.hasStatusEffect(ModMobEffects.getBloodPactEffect())) { - if (half) { - return blinking ? Matrix.identifier("hud/heart/half_blinking") : Matrix.identifier("hud/heart/half"); - } else { - return blinking ? Matrix.identifier("hud/heart/full_blinking") : Matrix.identifier("hud/heart/full"); - } - } - - return instance.getTexture(hardcore, half, blinking); - } - - @Redirect(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;translate(FFF)Lorg/joml/Matrix4f;", remap = false)) - private Matrix4f translate(Matrix4fStack instance, float x, float y, float z) { - final var translatedCrosshairPosition = MatrixHud.translateCrosshairPosition(x, y); - return instance.translate(translatedCrosshairPosition.x, translatedCrosshairPosition.y, z); - } - - @Redirect(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V")) - private void translate(DrawContext instance, Identifier texture, int x, int y, int width, int height) { + @Redirect( + method = "extractCrosshair(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V" + ) + ) + private void translateCrosshair(GuiGraphicsExtractor extractor, RenderPipeline pipeline, Identifier sprite, int x, int y, int width, int height) { if (width != 15 || height != 15) { - instance.drawGuiTexture(texture, x, y, width, height); + extractor.blitSprite(pipeline, sprite, x, y, width, height); return; } - final var translatedCrosshairPosition = MatrixHud.translateCrosshairPosition(x, y); - instance.drawGuiTexture(texture, (int) translatedCrosshairPosition.x, (int) translatedCrosshairPosition.y, width, height); + + Vector2f translatedCrosshairPosition = MatrixHud.translateCrosshairPosition(x, y); + extractor.blitSprite(pipeline, sprite, (int) translatedCrosshairPosition.x, (int) translatedCrosshairPosition.y, width, height); } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt b/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt index 2f05d200..1d9787e7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt @@ -16,6 +16,9 @@ import heckerpowered.matrix.common.item.ModComponents import heckerpowered.matrix.common.item.ModCreativeTab import heckerpowered.matrix.common.item.ModItems import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.MatrixCommonProxy +import heckerpowered.matrix.common.recipe.RedstoneSuitChargeRecipe +import heckerpowered.matrix.common.network.syncher.ModEntityDataSerializers import net.fabricmc.api.ModInitializer import net.minecraft.resources.Identifier import org.slf4j.Logger @@ -27,6 +30,9 @@ object Matrix : ModInitializer { @JvmField val LOGGER: Logger = LoggerFactory.getLogger("matrix") + @JvmField + var proxy: MatrixCommonProxy = MatrixCommonProxy() + override fun onInitialize() { MatrixServerPlayNetworking.onInitialize() MagicSystem.onInitialize() @@ -34,11 +40,13 @@ object Matrix : ModInitializer { ModEnchantments.onInitialize() MatrixCommands.onInitialize() ModComponents.onInitialize() + ModEntityDataSerializers.onInitialize() ModItems.onInitialize() ModCreativeTab.onInitialize() MatrixPotions.onInitialize() ModEntityTypes.onInitialize() MatrixEntityAttributes.onInitialize() + RedstoneSuitChargeRecipe.onInitialize() } @JvmStatic diff --git a/common/src/main/kotlin/heckerpowered/matrix/MatrixCommonProxy.kt b/common/src/main/kotlin/heckerpowered/matrix/MatrixCommonProxy.kt new file mode 100644 index 00000000..8258cc86 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/MatrixCommonProxy.kt @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix + +import heckerpowered.matrix.common.magic.resource.Mana +import heckerpowered.matrix.core.isInfiniteMana +import heckerpowered.matrix.core.mana +import heckerpowered.matrix.core.maxMana +import net.minecraft.world.entity.player.Player + +open class MatrixCommonProxy { + open fun getPlayerMana(player: Player): Mana { + return player.mana + } + + open fun getPlayerMaxMana(player: Player): Mana { + return player.maxMana + } + + open fun isInfiniteMana(player: Player): Boolean { + return player.isInfiniteMana + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ClientGlobals.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ClientGlobals.kt new file mode 100644 index 00000000..493eedc1 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ClientGlobals.kt @@ -0,0 +1,15 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.client + +import net.minecraft.client.Minecraft +import net.minecraft.client.player.LocalPlayer + +val minecraft: Minecraft + get() = Minecraft.getInstance() + +val player: LocalPlayer? + get() = minecraft.player diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt index 95f74111..a3027f15 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt @@ -10,25 +10,27 @@ import heckerpowered.matrix.client.network.MatrixClientPlayNetworking import heckerpowered.matrix.client.render.ChannelSequenceRenderer import heckerpowered.matrix.client.render.MatrixRenderSystem import heckerpowered.matrix.client.render.ScreenEffectRenderer +import heckerpowered.matrix.client.render.TargetGuideRenderer import heckerpowered.matrix.client.render.entity.DevEntityRenderer import heckerpowered.matrix.client.render.entity.EmptyRenderer import heckerpowered.matrix.client.render.entity.FinderArrowEntityRenderer import heckerpowered.matrix.client.render.entity.MagicLightningEntityRenderer -import heckerpowered.matrix.client.render.item.VortexItemRenderer +import heckerpowered.matrix.client.render.post.ShockwaveRenderer import heckerpowered.matrix.client.shader.ShaderStageStore +import heckerpowered.matrix.client.ui.element.DamageNumberHud import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase import heckerpowered.matrix.common.entity.ModEntityTypes -import heckerpowered.matrix.common.item.MagicTalismanItem +import heckerpowered.matrix.common.entity.AttractorEntity +import heckerpowered.matrix.common.entity.DevEntity +import heckerpowered.matrix.common.entity.FinderArrowEntity +import heckerpowered.matrix.common.entity.MagicLightningBolt +import heckerpowered.matrix.common.item.getMagics import heckerpowered.matrix.common.magic.core.Magic -import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.common.magic.system.Magics +import heckerpowered.matrix.core.isInfiniteMana import net.fabricmc.api.ClientModInitializer -import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry -import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRendererRegistrationCallback -import net.minecraft.client.render.entity.feature.FeatureRendererContext -import net.minecraft.client.render.entity.model.EntityModel -import net.minecraft.entity.LivingEntity import org.joml.Matrix4f import java.time.Duration @@ -68,30 +70,34 @@ class MatrixClient : ClientModInitializer { MatrixHud.onInitialize() MatrixClientPlayNetworking.onInitialize() + DamageNumberHud.onInitialize() ScreenEffectRenderer.onInitialize() + ChannelSequenceRenderer.onInitialize() + TargetGuideRenderer.onInitialize() + ShockwaveRenderer.onInitialize() MatrixKeyBindings.onInitialize() registerEntityRenderers() - - LivingEntityFeatureRendererRegistrationCallback.EVENT.register { _, entityRenderer, registrationHelper, _ -> - @Suppress("UNCHECKED_CAST") - registrationHelper.register(ChannelSequenceRenderer(entityRenderer as FeatureRendererContext>)) - } - - BuiltinItemRendererRegistry.INSTANCE.register(MagicTalismanItem, VortexItemRenderer) + onWindowInitialization() } private fun registerEntityRenderers() { - EntityRendererRegistry.register(ModEntityTypes.MAGIC_LIGHTNING_ENTITY) { context -> MagicLightningEntityRenderer(context) } - EntityRendererRegistry.register(ModEntityTypes.attractor) { context -> EmptyRenderer(context) } - EntityRendererRegistry.register(ModEntityTypes.FINDER_ARROW_ENTITY) { context -> FinderArrowEntityRenderer(context) } - EntityRendererRegistry.register(ModEntityTypes.devEntity) { context -> DevEntityRenderer(context) } + EntityRendererRegistry.register(ModEntityTypes.MAGIC_LIGHTNING_ENTITY) { context -> MagicLightningEntityRenderer(context) } + EntityRendererRegistry.register(ModEntityTypes.attractor) { context -> EmptyRenderer(context) } + EntityRendererRegistry.register(ModEntityTypes.FINDER_ARROW_ENTITY) { context -> FinderArrowEntityRenderer(context) } + EntityRendererRegistry.register(ModEntityTypes.devEntity) { context -> DevEntityRenderer(context) } } companion object { private var lastNonEmptyMagicList: List? = null + private var shaderPipelinesInitialized = false fun getPlayerMagics(): List { - val magics = MagicSystem.getMagics(player) + val player = player ?: return lastNonEmptyMagicList ?: emptyList() + val magics = if (MatrixHud.isInfiniteMana || player.isInfiniteMana) { + Magics.all.toList() + } else { + player.getMagics().toList() + } if (magics.isNotEmpty()) { this.lastNonEmptyMagicList = magics } @@ -100,8 +106,12 @@ class MatrixClient : ClientModInitializer { @JvmStatic fun onWindowInitialization() { + if (shaderPipelinesInitialized) { + return + } + shaderPipelinesInitialized = true ShaderStageStore.Default.discoverFiles() ShaderStageStore.Default.precompileAll() } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt index 37e87cf2..7b681681 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt @@ -5,14 +5,16 @@ package heckerpowered.matrix.client +import heckerpowered.matrix.MatrixCommonProxy import heckerpowered.matrix.common.magic.resource.Mana import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.server.network.ServerPlayerEntity +import heckerpowered.matrix.core.isInfiniteMana +import net.minecraft.world.entity.player.Player +import net.minecraft.server.level.ServerPlayer class MatrixClientProxy : MatrixCommonProxy() { - override fun getPlayerMana(player: PlayerEntity): Mana { - if (player is ServerPlayerEntity) { + override fun getPlayerMana(player: Player): Mana { + if (player is ServerPlayer) { return super.getPlayerMana(player) } if (minecraft.player == null || player != ::player.get()) { @@ -22,8 +24,8 @@ class MatrixClientProxy : MatrixCommonProxy() { return (MatrixHud.mana - MatrixHud.manaUsage).mana } - override fun getPlayerMaxMana(player: PlayerEntity): Mana { - if (player is ServerPlayerEntity) { + override fun getPlayerMaxMana(player: Player): Mana { + if (player is ServerPlayer) { return super.getPlayerMaxMana(player) } if (minecraft.player == null || player != ::player.get()) { @@ -33,10 +35,13 @@ class MatrixClientProxy : MatrixCommonProxy() { return MatrixHud.maxMana.mana } - override fun isInfiniteMana(player: PlayerEntity): Boolean { - if (player is ServerPlayerEntity) { + override fun isInfiniteMana(player: Player): Boolean { + if (player is ServerPlayer) { return super.isInfiniteMana(player) } - return false + if (minecraft.player != null && player == minecraft.player) { + return MatrixHud.isInfiniteMana || player.isInfiniteMana + } + return player.isInfiniteMana } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt index 420d13e6..56db132f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt @@ -5,1906 +5,1512 @@ package heckerpowered.matrix.client -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.systems.VertexSorter +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.core.AimAssist import heckerpowered.matrix.client.core.ClientOptions.aimAssistEnabled import heckerpowered.matrix.client.core.ClientOptions.aimAssistFov import heckerpowered.matrix.client.core.ClientOptions.aimAssistMaxDistance import heckerpowered.matrix.client.event.KeyEvent import heckerpowered.matrix.client.event.MouseButtonEvent -import heckerpowered.matrix.client.render.* -import heckerpowered.matrix.client.render.post.BloomEffect -import heckerpowered.matrix.client.render.shader.GaussianBlurRenderer -import heckerpowered.matrix.client.render.shader.opacityMask -import heckerpowered.matrix.client.render.state.* -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import heckerpowered.matrix.client.render.state.capabilities.CapabilityState -import heckerpowered.matrix.client.render.state.capabilities.CullFaceState -import heckerpowered.matrix.client.render.state.capabilities.DepthTestState -import heckerpowered.matrix.client.shader.* -import heckerpowered.matrix.client.shader.component.TransformFeedback -import heckerpowered.matrix.client.ui.element.* -import heckerpowered.matrix.client.ui.foundation.animation.* +import heckerpowered.matrix.client.render.PostProcessRenderer +import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.ui.foundation.animation.EasingMode +import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase +import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.common.effect.isBloodPactActive import heckerpowered.matrix.common.item.LightningChestplate1 import heckerpowered.matrix.common.item.LightningChestplate1.isBorrowedTime import heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking import heckerpowered.matrix.common.item.WizardHelmet5 -import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus +import heckerpowered.matrix.common.magic.channel.CasterContext +import heckerpowered.matrix.common.magic.channel.ChannelEntry +import heckerpowered.matrix.common.magic.channel.ChannelExecutor +import heckerpowered.matrix.common.magic.channel.ChannelQueue.Companion.getChannelQueue +import heckerpowered.matrix.common.magic.channel.ChannelQueue.Companion.getOrCreateChannelQueue +import heckerpowered.matrix.common.magic.channel.MagicInvocation import heckerpowered.matrix.common.magic.core.Magic +import heckerpowered.matrix.common.magic.core.MagicAvailableStatus +import heckerpowered.matrix.common.magic.core.MagicAvailability import heckerpowered.matrix.common.magic.core.MagicCalculationContext import heckerpowered.matrix.common.magic.core.description +import heckerpowered.matrix.common.magic.system.Magics import heckerpowered.matrix.common.network.ServerboundActivateBloodPactPayload +import heckerpowered.matrix.common.network.ServerboundBorrowedTimePayload +import heckerpowered.matrix.common.network.ServerboundOverclockPayload import heckerpowered.matrix.common.network.ServerboundUseMagicPayload import heckerpowered.matrix.common.persistent.isWizard +import heckerpowered.matrix.common.persistent.queueSize import heckerpowered.matrix.common.persistent.wizardHelmetStack -import heckerpowered.matrix.core.approximatelyEqual -import heckerpowered.matrix.core.inverseLerp -import heckerpowered.matrix.core.lerp +import heckerpowered.matrix.core.getLerpedPos +import heckerpowered.matrix.core.utility.getEntitiesNearSight import heckerpowered.matrix.core.worldToScreen +import heckerpowered.matrix.data.language.MatrixLanguage +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.client.util.InputUtil -import net.minecraft.entity.Entity -import net.minecraft.entity.EquipmentSlot -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.boss.dragon.EnderDragonPart -import net.minecraft.entity.projectile.ProjectileUtil -import net.minecraft.sound.SoundCategory -import net.minecraft.sound.SoundEvents -import net.minecraft.text.Text -import net.minecraft.util.Util -import net.minecraft.util.math.Box -import net.minecraft.util.math.ColorHelper -import net.minecraft.util.math.MathHelper -import net.minecraft.util.math.Vec3d -import net.minecraft.world.RaycastContext +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.network.chat.Component +import net.minecraft.sounds.SoundEvents +import net.minecraft.sounds.SoundSource +import net.minecraft.util.ARGB +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.boss.enderdragon.EnderDragonPart +import net.minecraft.world.entity.projectile.ProjectileUtil +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 import org.joml.Vector2f import org.lwjgl.glfw.GLFW -import org.lwjgl.opengl.GL15.glDeleteBuffers -import org.lwjgl.opengl.GL30.glDeleteVertexArrays -import org.lwjgl.opengl.GL46.* -import org.lwjgl.system.MemoryUtil +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER import java.math.BigDecimal import java.math.RoundingMode import java.time.Duration import kotlin.math.abs import kotlin.math.min -import kotlin.math.round -import kotlin.random.Random +import kotlin.math.roundToInt object MatrixHud { - var mana - get() = manaBar.mana.value - set(value) { - manaBar.mana.value = value.coerceIn(0.0..maxMana) - } + private const val USE_MAGIC_REPEAT_INTERVAL_TICKS = 5 + private const val MAGIC_HUD_TIME_SCALE = 0.01 + private const val BORROWED_TIME_SCALE = 0.15 - var maxMana - get() = manaBar.maxMana.value.coerceAtLeast(.0) - set(value) { - manaBar.maxMana.value = value - } + var mana = .0 + var maxMana = .0 + var manaUsage = .0 + var isInfiniteMana = false - var manaUsage - get() = manaBar.manaUsage.value - set(value) { - manaBar.manaUsage.value = value - } + var renderHud = true + var useBloom = false + var useBlur = false var targetedEntity: LivingEntity? = null + private var candidateTargets: List = emptyList() private var usingRayCast = false + private var manaOverclock = 1.0 + private var magicOverclock = 1.0 + private var previousMagicListVisible = false + private var magicListKeyDown = false private var cachedTargetedEntity: LivingEntity? = null + private var lastFrameNanos = System.nanoTime() - private var lastNanos = 0L - - private var selectedIndex = 1 - private var usingMagicList = mutableMapOf() - - private var previousIndex = 1 - - private val manaBar = ManaBar() - - private val easingFunction = ElasticEase() - - private val manaOverclockAnimation = AnimationClock(Duration.ofMillis(300), 1.0, 1.0) - private val magicOverclockAnimation = AnimationClock(Duration.ofMillis(300), 1.0, 1.0) - - private val magicShownAnimationClock = AnimationClock( - Duration.ofMillis( - 300 - ), -50.0, .0 - ) - private val magicShownOpacityAnimationClock = AnimationClock( - Duration.ofMillis( - 300 - ), .0, 1.0 - ) - private val magicShownAnimation = DoubleAnimation( - magicShownAnimationClock, easingFunction - ) - val magicShownOpacityAnimation = DoubleAnimation( - magicShownOpacityAnimationClock, easingFunction - ) - - private val hudBloomThreshold = SimpleDoubleAnimation(from = 1.0, to = 1.0) + val manaOverclockValue: Double + get() = manaOverclock - private val magicTimeScale = TimeController.allocateTimeController() - private val lightningTimeScale = TimeController.allocateTimeController() - - private val healthPercentageAnimation = SimpleDoubleAnimation() - private val healthAnimation = SimpleDoubleAnimation() - private val maxHealthAnimation = SimpleDoubleAnimation() - private var previousDisplayEntityNameHashCode: Int = 0 - private var displayEntityName: Text = Text.empty() - private var displayEntityNameOpacityAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150), initValue = 1.0) - private var previousCandidateEntities: Int = 0 - private var displayCandidateEntities: Int = 0 - private var displayCandidateCountOpacityAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150), initValue = 1.0) - private var candidateCountPadding = SimpleDoubleAnimation() - - private val manaOverclock = DoubleAnimation( - manaOverclockAnimation, easingFunction - ) - private val magicOverclock = DoubleAnimation( - magicOverclockAnimation, easingFunction - ) - - private val dissolveShader = DissolveShader() - - private val dissolveAnimation = SimpleDoubleAnimation(from = 1.0) - - private val magicDescriptionChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) - private var currentDescription: Text = Text.empty() - private var displayDescription: Text = Text.empty() + val magicOverclockValue: Double + get() = magicOverclock - private val descriptionYOffsetAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(300)) - - private val entityDescriptionOpacityAnimation = SimpleDoubleAnimation(initValue = 1.0) - private var previousVisibility = false - - private var aimEntity: Entity? = null - private var useAimAssist = false - private var firstShow = true - - private val grayscaleIntensityAnimation = SimpleDoubleAnimation() - private val descriptionExtraHeightAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(450)) + @JvmField + var isPressingRightMouseButton = false - private var sizeScalingAnimation = true + @JvmField + var isPressingLeftMouseButton = false @JvmField val fovAnimation = SimpleDoubleAnimation(initValue = 1.0) - private var fovZoomRatio = .0 - private val hudFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } - private val blurFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } - private val emissiveFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } - - private class MagicDisplayData { - val statusChangedAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150)) - val costChangedAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150)) - val costWidthAnimation = SimpleDoubleAnimation() - - var displayCost = 0L - var previousCost = 0L - var displayStatus = LMagicAvailableStatus.AVAILABLE - var previousStatus = LMagicAvailableStatus.AVAILABLE - } + @JvmField + val magicShownOpacityAnimation = SimpleDoubleAnimation(initValue = .0) + + private val magicShownAnimation = SimpleDoubleAnimation(initValue = -50.0) + private val manaShownAnimation = SimpleDoubleAnimation(initValue = -50.0) + private val manaOpacityAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaValueAnimation = SimpleDoubleAnimation(initValue = .0) + private val maxManaValueAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaUsageAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaCostAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaCostTooltipShownAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaCostTooltipOpacityAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaCostTooltipRedAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaCostTooltipGreenAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaCostTooltipBlueAnimation = SimpleDoubleAnimation(initValue = .0) + private val availableStatusShownAnimation = SimpleDoubleAnimation(initValue = -50.0) + private val availableStatusOpacityAnimation = SimpleDoubleAnimation(initValue = .0) + private val healthPercentageAnimation = SimpleDoubleAnimation(initValue = .0) + private val healthAnimation = SimpleDoubleAnimation(initValue = .0) + private val maxHealthAnimation = SimpleDoubleAnimation(initValue = .0) + private val entityDescriptionOpacityAnimation = SimpleDoubleAnimation(initValue = .0) + private val descriptionYOffsetAnimation = SimpleDoubleAnimation(initValue = -35.0) + private val descriptionExtraHeightAnimation = SimpleDoubleAnimation(initValue = .0, duration = Duration.ofMillis(450)) + private val magicDescriptionChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + private val displayEntityNameOpacityAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + private val displayCandidateCountOpacityAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + private val candidateCountPaddingAnimation = SimpleDoubleAnimation(initValue = .0) + private val manaOverclockAnimation = SimpleDoubleAnimation(initValue = 1.0) + private val magicOverclockAnimation = SimpleDoubleAnimation(initValue = 1.0) + private val grayscaleIntensityAnimation = SimpleDoubleAnimation(initValue = .0) + private val crosshairX = SimpleDoubleAnimation(initValue = .0) + private val crosshairY = SimpleDoubleAnimation(initValue = .0) + private val magicHudTimeScale = TimeController.allocateTimeController() + private val lightningTimeScale = TimeController.allocateTimeController() + private var selectedMagicIndex = 0 + private var crosshairTargetPosition: Vector2f? = null + private var crosshairAnimationInitialized = false + private var lastUseMagicTick = Int.MIN_VALUE + private var useMagicHoldArmed = false + private var fovZoomRatio = .0 + private var currentDescription: Component = Component.empty() + private var displayDescription: Component = Component.empty() + private var previousDisplayEntityNameKey = "" + private var displayEntityName: Component = Component.empty() + private var previousCandidateEntityCount = 0 + private var displayCandidateEntityCount = 0 + private var currentAvailableStatusKey = "available" + private var displayAvailableStatus: Component = MatrixLanguage.magicAvailable + private val availableStatusChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + private var lastManaCostTooltipState = false + private var displayManaCostTooltipState = false + private var lastManaCostTooltipDifference = 0L + private var displayManaCostTooltipDifference = 0L + private val manaCostTooltipStateChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + private val manaCostTooltipDifferenceChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + private val usingMagicList = mutableMapOf() private var cachedMagicDisplayData = mutableListOf() - private val magicDisplayData: MutableList - get() { - val magics = MatrixClient.getPlayerMagics() - if (cachedMagicDisplayData.size != magics.size) { - val newCachedMagicDisplayData = mutableListOf() - for (i in magics.indices) { - newCachedMagicDisplayData.add(MagicDisplayData()) - } - cachedMagicDisplayData = newCachedMagicDisplayData - } - return cachedMagicDisplayData - } - + private val magicColorAnimations = mutableListOf() + private val magicExtraWidthAnimations = mutableListOf() private val theWorldShader by lazy { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/the_world.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("grayscaleIntensity") { pointer -> - glUniform1f(pointer, grayscaleIntensityAnimation.animatedValue.toFloat()) - } - ) ) } - private val pointSpriteProgram by lazy { - Program( - ResourceShader("/assets/matrix/shaders/point_sprite/point_sprite.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/point_sprite/point_sprite.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(UniformProvider("time") { pointer -> - val timeSeconds = System.nanoTime() / 1_000_000_000.0 - glUniform1f(pointer, timeSeconds.toFloat()) - }), - components = arrayOf( - TransformFeedback( - arrayOf("OutPosition"), - (points.size / 2), - bufferSize = (points.size / 2).toLong() * 4 * 2 - ) - ) - ) - } + val grayscaleIntensity: Float + get() = grayscaleIntensityAnimation.animatedValue.toFloat().coerceIn(.0F, 1.0F) - init { - easingFunction.easingMode = EasingMode.OUT - easingFunction.oscillations = 0 + private class HudColorAnimation { + val red = SimpleDoubleAnimation(initValue = .0) + val green = SimpleDoubleAnimation(initValue = .0) + val blue = SimpleDoubleAnimation(initValue = .0) - magicOverclock.currentValue = 1.0 - manaOverclock.currentValue = 1.0 + fun setColor(red: Double, green: Double, blue: Double) { + this.red.value = red + this.green.value = green + this.blue.value = blue + } - entityDescriptionOpacityAnimation.start() - descriptionYOffsetAnimation.start() - grayscaleIntensityAnimation.start() - descriptionExtraHeightAnimation.start() + fun setColorWithoutAnimation(red: Double, green: Double, blue: Double) { + this.red.animatedValue = red + this.green.animatedValue = green + this.blue.animatedValue = blue + } } - private class ColorAnimation { - val redClock = AnimationClock( - Duration.ofMillis( - 300 - ), .0, 1.0 - ) - val red = DoubleAnimation( - redClock, easingFunction - ) + private class MagicDisplayData { + val statusChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + val costChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) + val costWidthAnimation = SimpleDoubleAnimation(initValue = .0) - val greenClock = AnimationClock( - Duration.ofMillis( - 300 - ), .0, 1.0 - ) - val green = DoubleAnimation( - greenClock, easingFunction - ) + var displayCost = 0L + var previousCost = Long.MIN_VALUE + var displayStatus: Component = MatrixLanguage.magicAvailable + var previousStatusKey = "" + } - val blueClock = AnimationClock( - Duration.ofMillis( - 300 - ), .0, 1.0 - ) - val blue = DoubleAnimation( - blueClock, easingFunction - ) + private data class MagicStatusDisplay( + val key: String, + val text: Component, + val available: Boolean, + val targetMissing: Boolean, + ) - fun setColor( - red: Double, - green: Double, - blue: Double, - ) { - this.red.currentValue = red - this.green.currentValue = green - this.blue.currentValue = blue + val selectedMagic: Magic + get() { + val magics = currentMagicList() + selectedMagicIndex = selectedMagicIndex.coerceIn(0, (magics.size - 1).coerceAtLeast(0)) + return magics.getOrNull(selectedMagicIndex) ?: Magics.all.first() } - fun setColorWithoutAnimation( - red: Double, - green: Double, - blue: Double, - ) { - redClock.from = red - redClock.to = red - this.red.currentValue = red - - greenClock.from = green - greenClock.to = green - this.green.currentValue = green - - blueClock.from = blue - blueClock.to = blue - this.blue.currentValue = blue + fun onInitialize() { + AimAssist.autoApplyRotation = false + HudElementRegistry.addLast(Matrix.identifier("matrix_hud")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) + } + ClientTickEvents.END_CLIENT_TICK.register { + handleKeyBindings() } } - private val magicColorAnimations = mutableListOf() - private val magicExtraWidthAnimations = mutableListOf() - - private var candidateAimAssistEntities = emptyList() - - @JvmStatic - fun onDoAttack() { - if (!shouldRenderHud() || shouldSlowTime()) { - useAimAssist = false + private fun handleKeyBindings() { + val player = minecraft.player + if (player == null || minecraft.level == null) { + forceCloseMagicList(instant = true) return } - useAimAssist = !useAimAssist - if (!useAimAssist) { - aimEntity = null - } - } - private fun processKeyInput() { - if (MatrixKeyBindings.useMagic.wasPressed()) { - useCurrentMagic() - } - while (MatrixKeyBindings.useMagic.wasPressed()) { - useCurrentMagic() + if (minecraft.gui.screen() != null && magicListKeyDown) { + forceCloseMagicList(instant = true) + return } - while (MatrixKeyBindings.nextMagic.wasPressed()) { + val hudActive = shouldRenderMagicList() + updateMagicListVisibility(hudActive) + + while (MatrixKeyBindings.nextMagic.consumeClick()) { nextMagic() } - - while (MatrixKeyBindings.previousMagic.wasPressed()) { + while (MatrixKeyBindings.previousMagic.consumeClick()) { previousMagic() } + var useMagicPressedWhileHudActive = false + while (MatrixKeyBindings.useMagic.consumeClick()) { + if (hudActive) { + useMagicPressedWhileHudActive = true + } + } + + if (!MatrixKeyBindings.useMagic.isDown) { + useMagicHoldArmed = false + } + if (useMagicPressedWhileHudActive) { + useMagicHoldArmed = true + lastUseMagicTick = player.tickCount - USE_MAGIC_REPEAT_INTERVAL_TICKS + } - while (MatrixKeyBindings.overclockMagic.wasPressed()) { - val difference = if (player.isSneaking) { - -0.5 + if (hudActive && MatrixKeyBindings.useMagic.isDown && useMagicHoldArmed) { + val currentTick = player.tickCount + if (currentTick - lastUseMagicTick >= USE_MAGIC_REPEAT_INTERVAL_TICKS && useSelectedMagic()) { + lastUseMagicTick = currentTick + } + } else { + lastUseMagicTick = Int.MIN_VALUE + if (!hudActive) { + useMagicHoldArmed = false + } + } + while (MatrixKeyBindings.overclockMagic.consumeClick()) { + if (minecraft.player?.isShiftKeyDown == true) { + underclockMagic() } else { - 0.5 + overclockMagic() } - val newOverclock = (magicOverclock.currentValue + difference).coerceIn( - 1.0..10.0 - ) - magicOverclock.currentValue = newOverclock - ClientPlayNetworking.send(OverclockPayload(manaOverclock.currentValue, magicOverclock.currentValue)) } - - while (MatrixKeyBindings.overclockMana.wasPressed()) { - val difference = if (player.isSneaking) { - -0.5 + while (MatrixKeyBindings.overclockMana.consumeClick()) { + if (minecraft.player?.isShiftKeyDown == true) { + underclockMana() } else { - 0.5 + overclockMana() } - val newOverclock = (manaOverclock.currentValue + difference).coerceIn( - 1.0..10.0 - ) - manaOverclock.currentValue = newOverclock - ClientPlayNetworking.send( - OverclockPayload( - manaOverclock.currentValue, magicOverclock.currentValue - ) - ) } } - fun onInitialize() { - HudRenderCallback.EVENT.register(this::onHudRender) - SystemCrashBar.onInitialize() - StatusHud.onInitialize() - DamageNumberHud.onInitialize() + private fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + if (!hasHudContext() || !renderHud) { + forceCloseMagicList(instant = true) + return + } + if (minecraft.gui.screen() != null) { + forceCloseMagicList(instant = true) + return + } + syncMagicListKeyStateFromWindow() + val hudActive = shouldRenderMagicList() + updateMagicListVisibility(hudActive) + if (!hudActive) { + useMagicHoldArmed = false + lastUseMagicTick = Int.MIN_VALUE + } + + val tickDelta = tickCounter.getGameTimeDeltaPartialTick(false) + updateTargeting(tickDelta, drawContext.guiWidth(), drawContext.guiHeight(), hudActive) + if (hudActive) { + handleKeyBindings() + } + + updateTimeScale(hudActive) + updateTheWorldPostEffect() + checkMagicAvailableStatus() + performChannelMagicAnimation() + + val alpha = magicShownOpacityAnimation.animatedValue + if (alpha <= 0.001) { + magicExtraWidthAnimations.forEach { it.animatedValue = .0 } + lastFrameNanos = System.nanoTime() + return + } + + renderManaCostTooltip(drawContext) + renderLeftPart(drawContext) + renderRightPart(drawContext) + renderLegacyManaBar(drawContext) + renderMagicAvailableStatus(drawContext, hudActive) + + if (hudActive) { + renderOverclock(drawContext) + } + lastFrameNanos = System.nanoTime() } @JvmStatic - fun overclockMana() { - val newOverclock = (manaOverclock.currentValue + 0.5).coerceIn( - 1.0..10.0 - ) - manaOverclock.currentValue = newOverclock - ClientPlayNetworking.send( - OverclockPayload( - manaOverclock.currentValue, magicOverclock.currentValue - ) - ) + fun onRemoteManaUpdate() { + manaUsage = manaUsage.coerceAtMost(mana) } @JvmStatic - fun underclockMana() { - val newOverclock = (manaOverclock.currentValue - 0.5).coerceIn( - 1.0..10.0 - ) - manaOverclock.currentValue = newOverclock - ClientPlayNetworking.send( - OverclockPayload( - manaOverclock.currentValue, magicOverclock.currentValue - ) - ) + fun shouldRenderHud(): Boolean { + return shouldRenderMagicList() } - @JvmStatic - fun overclockMagic() { - val newOverclock = (magicOverclock.currentValue + 0.5).coerceIn( - 1.0..10.0 - ) - magicOverclock.currentValue = newOverclock - ClientPlayNetworking.send( - OverclockPayload( - manaOverclock.currentValue, magicOverclock.currentValue - ) - ) + fun currentMagicList(): List { + return MatrixClient.getPlayerMagics() + } + + fun shouldSlowTime(): Boolean { + val server = minecraft.singleplayerServer ?: return false + return minecraft.isLocalServer && !server.isPublished } @JvmStatic - fun underclockMagic() { - val newOverclock = (magicOverclock.currentValue - 0.5).coerceIn( - 1.0..10.0 - ) - magicOverclock.currentValue = newOverclock - ClientPlayNetworking.send( - OverclockPayload( - manaOverclock.currentValue, magicOverclock.currentValue - ) - ) + fun onDoAttack() { + if (isPressingRightMouseButton && shouldRenderMagicList()) { + useSelectedMagic() + } } @JvmStatic fun nextMagic() { - previousIndex = selectedIndex - ++selectedIndex - if (selectedIndex > MatrixClient.getPlayerMagics().size) { - selectedIndex = 1 - } - onSelectionChanged() + val size = currentMagicList().size + if (size > 0) selectedMagicIndex = (selectedMagicIndex + 1).floorMod(size) } @JvmStatic fun previousMagic() { - previousIndex = selectedIndex - --selectedIndex - if (selectedIndex < 1) { - selectedIndex = MatrixClient.getPlayerMagics().size - } - onSelectionChanged() + val size = currentMagicList().size + if (size > 0) selectedMagicIndex = (selectedMagicIndex - 1).floorMod(size) } + @JvmStatic + fun nextZoomLevel() { + fovZoomRatio = (fovZoomRatio + 0.2).coerceAtMost(0.95) + fovAnimation.value = 1.0 - fovZoomRatio + } - private fun onSelectionChanged() { - if (selectedIndex - 1 !in MatrixClient.getPlayerMagics().indices) { - return - } + @JvmStatic + fun previousZoomLevel() { + fovZoomRatio = (fovZoomRatio - 0.2).coerceAtLeast(.0) + fovAnimation.value = 1.0 - fovZoomRatio + } - val magic = selectedMagic - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - manaBar.manaCost.value = magic.getCost(calculationContext).toDouble() + @JvmStatic + fun overclockMana() { + manaOverclock = (manaOverclock + 0.5).coerceIn(1.0, 10.0) + syncOverclock() } - val selectedMagic: Magic - get() { - var index = selectedIndex - 1 - val magics = MatrixClient.getPlayerMagics() - if (index !in magics.indices) { - index = 0 - } + @JvmStatic + fun underclockMana() { + manaOverclock = (manaOverclock - 0.5).coerceIn(1.0, 10.0) + syncOverclock() + } + + @JvmStatic + fun overclockMagic() { + magicOverclock = (magicOverclock + 0.5).coerceIn(1.0, 10.0) + syncOverclock() + } + + @JvmStatic + fun underclockMagic() { + magicOverclock = (magicOverclock - 0.5).coerceIn(1.0, 10.0) + syncOverclock() + } - return magics[index] + @JvmStatic + fun translateCrosshairPosition(x: Float, y: Float): Vector2f { + val targetPosition = crosshairTargetPosition + if (targetPosition == null || !aimAssistEnabled) { + if (!crosshairAnimationInitialized) { + crosshairX.animatedValue = x.toDouble() + crosshairY.animatedValue = y.toDouble() + } else { + crosshairX.value = x.toDouble() + crosshairY.value = y.toDouble() + } + return Vector2f(crosshairX.animatedValue.toFloat(), crosshairY.animatedValue.toFloat()) } - private fun useCurrentMagic() { - if (!shouldRenderHud()) { - return + if (!crosshairAnimationInitialized) { + crosshairX.animatedValue = x.toDouble() + crosshairY.animatedValue = y.toDouble() + crosshairAnimationInitialized = true } - useMagicIndexed(selectedIndex - 1) + crosshairX.value = targetPosition.x.toDouble() + crosshairY.value = targetPosition.y.toDouble() + return Vector2f(crosshairX.animatedValue.toFloat(), crosshairY.animatedValue.toFloat()) } - private fun useMagicIndexed(index: Int) { - val magic = MatrixClient.getPlayerMagics()[index] - val target = this.targetedEntity ?: return - val calculationContext = MagicCalculationContext.fromEntity(player, target) - if (magic.availableStatus(calculationContext) != LMagicAvailableStatus.AVAILABLE) { - return + @JvmStatic + fun onKey(window: Long, key: Int, scancode: Int, action: Int, mods: Int): Boolean { + if (window != minecraft.window.handle() || minecraft.player == null) { + return false } - magicColorAnimations[index].setColorWithoutAnimation(.0, 255.0, .0) + val screenOpen = minecraft.gui.screen() != null + if (key == GLFW.GLFW_KEY_TAB) { + if (screenOpen) { + magicListKeyDown = false + return false + } + + val pressed = action != GLFW.GLFW_RELEASE + if (pressed != magicListKeyDown) { + magicListKeyDown = pressed + } + return true + } - // Reset use magic animation - usingMagicList[index + 1] = 0.0 + if (!screenOpen && key == GLFW.GLFW_KEY_E && action != GLFW.GLFW_RELEASE) { + val player = minecraft.player ?: return false + val tabPressed = magicListKeyDown || + GLFW.glfwGetKey(minecraft.window.handle(), GLFW.GLFW_KEY_TAB) == GLFW.GLFW_PRESS + if (tabPressed && player.getItemBySlot(EquipmentSlot.CHEST).item is LightningChestplate1) { + ClientPlayNetworking.send(ServerboundBorrowedTimePayload) + return true + } - val cost = magic.getCost(calculationContext) - val mana = mana - manaUsage - if (player.isBloodPactActive && mana < cost) { - minecraft.world!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1.0f, 1f) - minecraft.world!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENTITY_WARDEN_HEARTBEAT, SoundCategory.PLAYERS, 1.0f, 1f) - } else { - minecraft.world!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1.0f, 1f) + if (shouldRenderHud()) { + ClientPlayNetworking.send(ServerboundActivateBloodPactPayload) + return true + } } - channelMagic(magic, target) + if (!KeyEvent.EVENT.invoker().onKey(key, scancode, action, mods)) { + return true + } + return false } - private fun channelMagic(magic: Magic, target: LivingEntity) { - ClientPlayNetworking.send(ServerboundUseMagicPayload(magic.definition.uuid, target.id)) - } + @JvmStatic + fun onMouseButton(window: Long, button: Int, action: Int, mods: Int): Boolean { + if (window != minecraft.window.handle()) { + return false + } - private fun checkVisibilityChanges() { - val shouldRenderHud = shouldRenderHud() - if (shouldRenderHud != previousVisibility) { - onHudVisibilityChanged(shouldRenderHud) + if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { + isPressingRightMouseButton = action != GLFW.GLFW_RELEASE + if (shouldRenderHud()) { + if (action == GLFW.GLFW_PRESS) { + fovZoomRatio = (fovZoomRatio + 0.2).coerceAtMost(0.95) + fovAnimation.value = 1.0 - fovZoomRatio + return true + } + if (action == GLFW.GLFW_RELEASE) { + fovZoomRatio = .0 + fovAnimation.value = 1.0 + return true + } + } else if (action == GLFW.GLFW_RELEASE) { + fovZoomRatio = .0 + fovAnimation.value = 1.0 + } } - previousVisibility = shouldRenderHud + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + isPressingLeftMouseButton = action != GLFW.GLFW_RELEASE + } + if (!MouseButtonEvent.EVENT.invoker().onMouseButton(button, action, mods)) { + return true + } + return false } - private fun warp() { - if (TimeController.minTimeScale != 1.0 || player.isPhaseWalking) { - grayscaleIntensityAnimation.value = 1.0 + private fun useSelectedMagic(): Boolean { + if (!shouldRenderMagicList()) { + return false + } + val usedMagicIndex = selectedMagicIndex + val magic = selectedMagicOrNull() ?: return false + val target = bestUsableTarget(magic) ?: return false + val player = minecraft.player ?: return false + val queue = target.getOrCreateChannelQueue(player) + val calculationContext = MagicCalculationContext( + caster = CasterContext.fromEntity(player), + target = target, + queue = queue, + ) + if (!magic.availableStatus(calculationContext).isAvailable) { + return false + } + val cost = runCatching { magic.getCost(calculationContext) }.getOrDefault(magic.getNormalCost()) + val channelTime = runCatching { magic.getChannelTime(calculationContext) }.getOrDefault(magic.getNormalChannelTime()) + val availableMana = mana - manaUsage + val level = minecraft.level + if (player.isBloodPactActive && availableMana < cost) { + level?.playSound(player, player.x, player.y, player.z, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0F, 1.0F) + level?.playSound(player, player.x, player.y, player.z, SoundEvents.WARDEN_HEARTBEAT, SoundSource.PLAYERS, 1.0F, 1.0F) } else { - grayscaleIntensityAnimation.value = .0 + level?.playSound(player, player.x, player.y, player.z, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0F, 1.0F) } + val predictedEntry = ChannelEntry(magic, cost, channelTime).also { + it.clientPrediction = true + } + queue.enqueue(predictedEntry) + magic.channel(MagicInvocation.fromEntity(player, target)) + ChannelExecutor.performChannelAnimation(predictedEntry, target, channelTime) + ClientPlayNetworking.send(ServerboundUseMagicPayload(magic.definition.uuid, target.id)) + magicColorAnimations.getOrNull(usedMagicIndex)?.setColorWithoutAnimation(.0, 255.0, .0) + usingMagicList[usedMagicIndex] = .0 + return true + } - if (!shouldSlowTime()) { - return + private fun updateTimeScale(active: Boolean) { + val canSlowTime = shouldSlowTime() + magicHudTimeScale.value = if (active && canSlowTime) { + MAGIC_HUD_TIME_SCALE + } else { + 1.0 } - val hasLightningEffect = player.isBorrowedTime - TimeController.playerStandaloneRenderTick = hasLightningEffect && !shouldRenderHud() && !minecraft.isPaused - if (hasLightningEffect) { - lightningTimeScale.value = 0.15 + val hasBorrowedTime = minecraft.player?.isBorrowedTime == true + lightningTimeScale.value = if (canSlowTime && hasBorrowedTime) { + BORROWED_TIME_SCALE } else { - lightningTimeScale.value = 1.0 + 1.0 } + TimeController.playerStandaloneRenderTick = canSlowTime && hasBorrowedTime && !active && !minecraft.isPaused TimeController.onRenderTick() - PostProcessRenderer.postProcessShaders.add(theWorldShader) } - private fun checkMagicAvailableStatus() { - val magics = MatrixClient.getPlayerMagics() - fillColorAnimationList(magics) - - magics.forEachIndexed { index, magic -> - if (index == selectedIndex - 1) { - val color = magicColorAnimations[index] - // when green = 255, magic is used, perform animation - // when green = 128, animation is in progress - if (color.green.currentValue == 255.0 || color.green.currentValue == 128.0) { - color.setColor( - .0, 128.0, .0 - ) - } else { - color.setColorWithoutAnimation( - .0, 128.0, .0 - ) - } - - return@forEachIndexed - } - - val status = getMagicAvailableStatus( - magic - ) - when (status) { - LMagicAvailableStatus.TARGET_MISSING -> magicColorAnimations[index].setColor( - .0, .0, .0 - ) - - LMagicAvailableStatus.AVAILABLE -> magicColorAnimations[index].setColor( - .0, .0, .0 - ) - - else -> { - magicColorAnimations[index].setColor(128.0, 0.0, 0.0) - } - } - } + private fun resetTimeScale() { + magicHudTimeScale.animatedValue = 1.0 + lightningTimeScale.animatedValue = 1.0 + TimeController.playerStandaloneRenderTick = false + TimeController.onRenderTick() + grayscaleIntensityAnimation.animatedValue = .0 + PostProcessRenderer.postProcessShaders.remove(theWorldShader) } - private fun fillColorAnimationList( - magics: List, - ) { - if (magicColorAnimations.size >= magics.size) { - return + private fun updateTheWorldPostEffect() { + val player = minecraft.player + val targetIntensity = when { + player?.isPhaseWalking == true -> 1.0 + shouldSlowTime() -> magicShownOpacityAnimation.animatedValue.coerceIn(.0, 1.0) + else -> .0 } + grayscaleIntensityAnimation.animatedValue = targetIntensity - for (i in magicColorAnimations.size..magics.size) { - magicColorAnimations.add( - ColorAnimation() - ) + if (targetIntensity > 0.001) { + PostProcessRenderer.postProcessShaders.add(theWorldShader) + } else { + PostProcessRenderer.postProcessShaders.remove(theWorldShader) } } - private fun fillExtraWidthAnimationList( - magics: List, - ) { - if (magicExtraWidthAnimations.size >= magics.size) { + private fun syncMagicListKeyStateFromWindow() { + if (!magicListKeyDown) { return } - - for (i in magicExtraWidthAnimations.size..magics.size) { - val animationClock = AnimationClock( - Duration.ofMillis( - 300 - ), 0.0, 1.0 - ) - val animation = DoubleAnimation( - animationClock, easingFunction - ) - magicExtraWidthAnimations.add( - PackedAnimation( - animationClock, animation - ) - ) + val tabDown = GLFW.glfwGetKey(minecraft.window.handle(), GLFW.GLFW_KEY_TAB) == GLFW.GLFW_PRESS + if (!tabDown) { + magicListKeyDown = false } } - private fun getMagicAvailableStatus(magic: Magic): LMagicAvailableStatus { - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - return magic.availableStatus(calculationContext) + private fun updateMagicListVisibility(visible: Boolean) { + if (visible != previousMagicListVisible) { + onHudVisibilityChanged(visible) + previousMagicListVisible = visible + } } - private fun renderMagicAvailableStatus( - drawContext: DrawContext, - renderer: LegacyMatrixUIRenderer, - ) { - val status = getMagicAvailableStatus(selectedMagic) - if (status == LMagicAvailableStatus.AVAILABLE || status == LMagicAvailableStatus.TARGET_MISSING || !shouldRenderHud()) { - AvailableStatusTooltip.hide() + private fun forceCloseMagicList(instant: Boolean) { + magicListKeyDown = false + previousMagicListVisible = false + if (instant) { + magicShownOpacityAnimation.animatedValue = .0 + magicShownAnimation.animatedValue = -50.0 + manaOpacityAnimation.animatedValue = .0 + manaShownAnimation.animatedValue = -50.0 + manaCostTooltipOpacityAnimation.animatedValue = .0 + manaCostTooltipShownAnimation.animatedValue = .0 + availableStatusOpacityAnimation.animatedValue = .0 + availableStatusShownAnimation.animatedValue = -50.0 + entityDescriptionOpacityAnimation.animatedValue = .0 + descriptionYOffsetAnimation.animatedValue = -35.0 } else { - AvailableStatusTooltip.show() + onHudHide() } - - AvailableStatusTooltip.render(drawContext, renderer, status) + resetTimeScale() } - private fun updateAimAssist( - updateRotation: Boolean, - tickCounter: RenderTickCounter, - ) { - targetedEntity?.apply { - if (aimEntity == null) { - AimAssist.resetAnimation() - aimEntity = targetedEntity - } + private fun onHudVisibilityChanged(visible: Boolean) { + if (visible) { + onHudShown() + } else { + onHudHide() } + } - if (!updateRotation) { - return - } - - aimEntity?.apply { - val tickDelta = tickCounter.getTickDelta( - true - ) - val x = lerp( - tickDelta.toDouble(), prevX, x - ) - val y = lerp( - tickDelta.toDouble(), prevY, y - ) - val z = lerp( - tickDelta.toDouble(), prevZ, z - ) - AimAssist.lookAt( - Vec3d( - x, y - 0.5, z - ), tickDelta.toDouble() - ) - AimAssist.applyRotation() - } - } - - private val isHudVisible - get() = magicShownOpacityAnimation.animatedValue != .0 - - private val isHudInvisible - get() = magicShownOpacityAnimation.animatedValue == .0 - - var useBloom = false - var renderHud = false - var useBlur = false - - private fun renderOtherHuds(drawContext: DrawContext, tickCounter: RenderTickCounter) { - renderWitherArmorHud(drawContext, tickCounter) - } - - private fun onBeginHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - renderOtherHuds(drawContext, tickCounter) - - if (!isHudInvisible) { - useBlur = true - renderHud = true - - useBloom = !hudBloomThreshold.animatedValue.approximatelyEqual(1.0) && - !magicShownOpacityAnimation.animatedValue.approximatelyEqual(.0) - } - - val bloodPact = player.isBloodPactActive - hudBloomThreshold.value = if (bloodPact) { - .0 - } else { - 1.0 - } - } - - private fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - StateIsolation.isolate( - FramebufferState(hudFramebuffer), ViewportState(hudFramebuffer), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { - onBeginHudRender(drawContext, tickCounter) - renderHud(drawContext, tickCounter) - onEndHudRender(drawContext, tickCounter) - } - } - - private fun renderCandidateEntities(drawContext: DrawContext, tickCounter: RenderTickCounter) { - if (!shouldRenderHud()) { - return - } - val tickDelta = tickCounter.getTickDelta(true) - - val tessellator = Tessellator.getInstance() - val buffer = tessellator.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR) - - val modelViewStack = RenderSystem.getModelViewStack() - modelViewStack.pushMatrix() - modelViewStack.set(viewMatrix) - RenderSystem.applyModelViewMatrix() - RenderSystem.backupProjectionMatrix() - RenderSystem.setProjectionMatrix(projectionMatrix, VertexSorter.BY_DISTANCE) - - var from = player.getLerpedPos(tickDelta).add(.0, player.boundingBox.lengthY / 2, .0)// Vector2d(crosshairX.animatedValue + 7.5, crosshairY.animatedValue + 7.5) - val targetedEntity = this.targetedEntity - if (targetedEntity != null) { - val to = targetedEntity.getLerpedPos(tickDelta).add(.0, targetedEntity.boundingBox.lengthY / 2, .0) - val color = ColorHelper.Argb.getArgb(255, 25, 255, 25) - buffer.vertex(from.x.toFloat(), from.y.toFloat(), from.z.toFloat()) - .color(color) - buffer.vertex(to.x.toFloat(), to.y.toFloat(), to.z.toFloat()) - .color(color) - from = to - } - for (candidateEntity in candidateAimAssistEntities) { - val targetPosition = candidateEntity.getLerpedPos(tickDelta).add(.0, candidateEntity.boundingBox.lengthY / 2, .0) - - val color = ColorHelper.Argb.getArgb(255, 255, 25, 25) - buffer.vertex(from.x.toFloat(), from.y.toFloat(), from.z.toFloat()) - .color(color) - buffer.vertex(targetPosition.x.toFloat(), targetPosition.y.toFloat(), targetPosition.z.toFloat()) - .color(color) - from = targetPosition - } - - StateIsolation.isolate( - LineWidthState(1.0F), - BlendState(false), - BlendFuncSeparateState(), - DepthTestState(false), - CullFaceState(false), - ShaderProgramState(GameRenderer::getPositionColorProgram), - CapabilityState(GL_MULTISAMPLE, true) - ) { - val mul = 8.0F - RenderSystem.setShaderColor(mul, mul, mul, 1.0F) - buffer.endNullable()?.let { - BufferRenderer.drawWithGlobalProgram(it) - } - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - } - - RenderSystem.restoreProjectionMatrix() - modelViewStack.popMatrix() - RenderSystem.applyModelViewMatrix() + private fun onHudShown() { + magicShownAnimation.value = .0 + magicShownOpacityAnimation.value = 1.0 + manaShownAnimation.value = .0 + manaOpacityAnimation.value = 1.0 + entityDescriptionOpacityAnimation.value = if (targetedEntity != null) 1.0 else .0 + descriptionYOffsetAnimation.value = if (targetedEntity != null) .0 else -35.0 + AimAssist.resetAnimation() } - private fun renderWitherArmorHud(drawContext: DrawContext, tickCounter: RenderTickCounter) { - StatusHud.onHudRender(drawContext, tickCounter) + private fun onHudHide() { + magicShownAnimation.value = -50.0 + magicShownOpacityAnimation.value = .0 + manaShownAnimation.value = -50.0 + manaOpacityAnimation.value = .0 + manaCostTooltipOpacityAnimation.value = .0 + manaCostTooltipShownAnimation.value = .0 + availableStatusOpacityAnimation.value = .0 + availableStatusShownAnimation.value = -50.0 + entityDescriptionOpacityAnimation.value = .0 + descriptionYOffsetAnimation.value = -35.0 + fovAnimation.value = 1.0 } - private fun renderHud(drawContext: DrawContext, tickCounter: RenderTickCounter) { - if (selectedIndex - 1 !in MatrixClient.getPlayerMagics().indices || - previousIndex - 1 !in MatrixClient.getPlayerMagics().indices - ) { - selectedIndex = 1 - previousIndex = 1 - } - - val renderer = LegacyMatrixUIRenderer(drawContext.vertexConsumers) - renderCandidateEntities(drawContext, tickCounter) - checkVisibilityChanges() - warp() - processKeyInput() - checkMagicAvailableStatus() - - performChannelMagicAnimation() - if (!shouldRenderHud()) { - fovZoomRatio = .0 + private fun updateTargeting(tickDelta: Float, viewportWidth: Int, viewportHeight: Int, hudActive: Boolean) { + val player = minecraft.player + if (player == null || minecraft.level == null || !hudActive) { + candidateTargets = emptyList() targetedEntity = null - } - fovAnimation.value = 1.0 - fovZoomRatio - lastNanos = Util.getMeasuringTimeNano() - - // magicShownAnimationClock.let { - // it.from = magicShownAnimation.animatedValue - // it.to = .0 - // } - - // magicShownOpacityAnimationClock.let { - // it.from = magicShownOpacityAnimation.animatedValue - // it.to = 1.0 - // } - if (magicShownOpacityAnimation.animatedValue == .0) { - for (animation in magicExtraWidthAnimations) { - animation.animation.currentValue = .0 - } - + crosshairTargetPosition = null + usingRayCast = false return } - ManaCostTooltip.render(drawContext, tickCounter) - renderLeftPart(drawContext, tickCounter) - renderRightPart(drawContext, tickCounter) - renderManaBar(drawContext, tickCounter) - renderMagicAvailableStatus(drawContext, renderer) - - if (!shouldRenderHud()) { - return - } - selectTargetEntity(tickCounter) - renderOverclock(drawContext, tickCounter) - - updateAimAssist(false, tickCounter) - } - - val points = FloatArray(1000 * 2) { - if (it % 2 == 0) { - Random.nextFloat() * 3f - 1f - 3F + val previousTarget = targetedEntity + val magic = selectedMagicOrNull() + val directTarget = getDirectTargetEntity(tickDelta, magic) + val candidates = if (aimAssistEnabled && magic != null) { + getAssistTargetEntities(tickDelta, magic) } else { - 1f - Random.nextFloat() * 0.2f + emptyList() } - } - - private fun onEndHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - if (!renderHud) { - return + candidateTargets = candidates + usingRayCast = directTarget != null && directTarget !== minecraft.crosshairPickEntity.asLivingTarget() + targetedEntity = when { + magic != null && directTarget != null && canChannelMagicOn(directTarget, magic) -> directTarget + magic != null -> candidates.firstOrNull() + else -> directTarget ?: candidates.firstOrNull() } - if (useBlur) { - val strength = magicShownOpacityAnimation.animatedValue.toFloat() - GaussianBlurRenderer.gaussianKernel = GaussianBlurRenderer.generateSymmetricGaussianKernel(strength, maxSigma = 8F) - BlurRenderer.renderGaussianBlur(minecraft.framebuffer) - - dropHudShadow() - - StateIsolation.isolate( - FramebufferState(minecraft.framebuffer), ViewportState(minecraft.framebuffer), - BlendState(true), BlendFuncState(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), - ) { - renderHudBlur() - } - } else { - StateIsolation.isolate( - FramebufferState(blurFramebuffer), ViewportState(blurFramebuffer), - BlendState(true), BlendFuncState(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), - ) { - PostProcessRenderer.copyFramebuffer(hudFramebuffer, blurFramebuffer, false) - PostProcessRenderer.copyFramebuffer(hudFramebuffer, minecraft.framebuffer, false) + if (targetedEntity != previousTarget) { + if (targetedEntity == null) { + entityDescriptionOpacityAnimation.value = .0 + descriptionYOffsetAnimation.value = -35.0 + } else { + entityDescriptionOpacityAnimation.value = 1.0 + descriptionYOffsetAnimation.value = .0 } } - - BloomEffect.brightnessPassFramebuffer = blurFramebuffer - BloomEffect.brightnessThreshold = 1F - - StateIsolation.isolate(BlendState(true), BlendFuncState(GL_ONE, GL_ONE)) { - BloomEffect.renderBloom() - PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.framebuffer, false) + if (targetedEntity != null) { + cachedTargetedEntity = targetedEntity } - hudFramebuffer.clear(true) - blurFramebuffer.clear(true) - - renderHud = false - useBlur = false - useBloom = false - } - - private fun dropHudShadow() { - GaussianBlurRenderer.gaussianKernel = GaussianBlurRenderer.generateSymmetricGaussianKernel(1.0F, maxSigma = 20F) - BlurRenderer.renderGaussianBlur(hudFramebuffer, blurFramebuffer) - - StateIsolation.isolate( - FramebufferState(blurFramebuffer), - ViewportState(blurFramebuffer), - BlendState(true), - BlendFuncState(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), - ) { - // Render the blurred hud background to blurFramebuffer - hudFramebuffer opacityMask BlurRenderer.blurFramebuffer - - // Render half-transparent hud on the blurred hud background - hudFramebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, false) + val target = targetedEntity + crosshairTargetPosition = if (aimAssistEnabled && target != null) { + val targetPosition = target.getLerpedPos(tickDelta).add(.0, target.boundingBox.ysize * 0.5, .0) + targetPosition.toGuiScreenPosition(tickDelta, viewportWidth, viewportHeight) + } else { + null } } - private fun renderHudBlur() { - val strength = 1.0F - magicShownOpacityAnimation.animatedValue.toFloat() - if (strength == .0F) { - blurFramebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, false) - return + private fun getDirectTargetEntity(tickDelta: Float, magic: Magic?): LivingEntity? { + val player = minecraft.player ?: return null + val vanillaTarget = minecraft.crosshairPickEntity.asLivingTarget() + if (magic == null || player.wizardHelmetStack.item !is WizardHelmet5) { + return vanillaTarget } - GaussianBlurRenderer.gaussianKernel = GaussianBlurRenderer.generateSymmetricGaussianKernel(strength, maxSigma = 20F) - BlurRenderer.renderGaussianBlurFullResolution(blurFramebuffer) - BlurRenderer.blurFramebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, false) + return getRayCastTargetEntity(tickDelta, magic)?.asLivingTarget() ?: vanillaTarget } - private fun renderPoints() { - val result = IntArray(1) - glGenVertexArrays(result) - - val vertexArray = result[0] - val vertexBuffer = glGenBuffers() - - glBindVertexArray(vertexArray) - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer) - - val buffer = MemoryUtil.memAllocFloat(points.size).put(points).flip() - glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW) - MemoryUtil.memFree(buffer) - glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * 4, 0L) - glEnableVertexAttribArray(0) - - pointSpriteProgram.enableShader() - glBindVertexArray(vertexArray) - glEnable(GL_PROGRAM_POINT_SIZE) - glDrawArrays(GL_POINTS, 0, points.size / 2) - pointSpriteProgram.disableShader() - - glBindVertexArray(0) - glBindBuffer(GL_ARRAY_BUFFER, 0) - glDisableVertexAttribArray(0) - glDisable(GL_PROGRAM_POINT_SIZE) - - glDeleteBuffers(vertexBuffer) - glDeleteVertexArrays(vertexArray) - - glBindFramebuffer(GL_FRAMEBUFFER, 0) - glDisable(GL_BLEND) - } - - private fun performChannelMagicAnimation() { - val delta = Util.getMeasuringTimeNano() - lastNanos - for (magic in usingMagicList) { - magic.setValue( - magic.value + delta / 2000000 - ) // 2000000 - } - } + private fun getAssistTargetEntities(tickDelta: Float, magic: Magic): List { + val player = minecraft.player ?: return emptyList() + val entities = minecraft.cameraEntity?.getEntitiesNearSight( + aimAssistMaxDistance, + aimAssistFov, + tickDelta, + ) ?: return emptyList() - @JvmStatic - fun shouldRenderHud(): Boolean { - if (minecraft.player == null) { - return false - } - if (MatrixClient.getPlayerMagics().isEmpty() || !player.isWizard) { - return false - } - return MinecraftClient.getInstance().options.playerListKey.isPressed + return entities + .mapNotNull { it as? LivingEntity } + .filter { it !== player && it.isAlive && !it.isSpectator } + .filter { canChannelMagicOn(it, magic) } + .toList() } - private val isPressingTab - get() = MinecraftClient.getInstance().options.playerListKey.isPressed + private fun getRayCastTargetEntity(tickDelta: Float, magic: Magic): Entity? { + val player = minecraft.player ?: return null + val cameraEntity = minecraft.cameraEntity ?: return null + val range = aimAssistMaxDistance - @JvmField - var isPressingRightMouseButton = false + val location = minecraft.gameRenderer.mainCamera().position() + val rotation = cameraEntity.getViewVector(tickDelta).normalize() + val min = location.add(rotation) + val max = location.add(rotation.scale(range)) + val box = AABB(min, max) - @JvmField - var isPressingLeftMouseButton = false + val basePredicate = { entity: Entity -> + val target = entity.asLivingTarget() + entity !== cameraEntity && + !entity.isSpectator && + target != null && + target.isAlive && + canChannelMagicOn(target, magic) + } - fun shouldSlowTime(): Boolean { - val minecraft = MinecraftClient.getInstance() - val server = minecraft.server - return minecraft.isIntegratedServerRunning && (server != null && !server.isRemote) + return ProjectileUtil.getEntityHitResult(cameraEntity, min, max, box, basePredicate, range)?.entity } - private fun onHudVisibilityChanged(visibility: Boolean) { - manaBar.onHudVisibilityChanged(visibility) - ManaCostTooltip.onHudVisibilityChanged(visibility) - if (visibility) { - onHudShown() - } else { - onHudHide() - } - } + private fun renderLegacyManaBar(drawContext: GuiGraphicsExtractor) { + val width = drawContext.guiWidth() + val player = minecraft.player + val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) + val currentMagicCost = selectedMagicOrNull()?.let { runCatching { it.getCost(calculationContext) }.getOrDefault(it.getNormalCost()) } ?: 0L - private fun onHudHide() { - if (shouldSlowTime()) { - magicTimeScale.value = 1.0 - } + manaValueAnimation.value = mana.coerceAtLeast(.0) + maxManaValueAnimation.value = maxMana.coerceAtLeast(.0) + manaUsageAnimation.value = manaUsage.coerceAtLeast(.0) + manaCostAnimation.value = currentMagicCost.toDouble() - magicShownAnimationClock.let { - it.from = magicShownAnimation.animatedValue - it.to = -50.0 + val opacity = manaOpacityAnimation.animatedValue + if (opacity <= 0.001) { + return } - magicShownOpacityAnimationClock.let { - it.from = magicShownOpacityAnimation.animatedValue - it.to = .0 + val maxManaValue = maxManaValueAnimation.animatedValue.coerceAtLeast(.0) + val visibleMana = manaValueAnimation.animatedValue.coerceAtLeast(.0) + val usage = manaUsageAnimation.animatedValue.coerceAtLeast(.0) + val manaPercentage = if (visibleMana.isInfinite() || maxManaValue <= .0) { + if (visibleMana.isInfinite()) 1.0 else .0 + } else { + (visibleMana / maxManaValue).coerceIn(.0, 1.0) } - dissolveAnimation.value = 1.0 - dissolveAnimation.duration = Duration.ofMillis(300) - dissolveAnimation.start() + val left = 50 + val right = width - 50 + val top = (10.0 + manaShownAnimation.animatedValue).roundToInt() + val bottom = (25.0 + manaShownAnimation.animatedValue).roundToInt() + val fillRight = lerp(manaPercentage, left.toDouble(), right.toDouble()).roundToInt() - magicShownAnimationClock.start() - magicShownOpacityAnimationClock.start() - ManaCostTooltip.hide() - - fovAnimation.value = 1.0 - } - - private fun onHudShown() { - // println(glGenProgramPipelines()) - if (shouldSlowTime()) { - magicTimeScale.value = 0.01 - } + drawContext.fill(left, top, fillRight, bottom, color((opacity * 64).roundToInt(), 25, 128, 255)) - magicShownAnimationClock.let { - it.from = magicShownAnimation.animatedValue - it.to = .0 - } + if (maxManaValue > .0) { + val usageWidth = usage / maxManaValue * (right - left) + val usageLeft = (fillRight - usageWidth).roundToInt().coerceAtLeast(left) + drawContext.fill(usageLeft, top, fillRight, bottom, color((opacity * 128).roundToInt(), 255, 25, 25)) - magicShownOpacityAnimationClock.let { - it.from = magicShownOpacityAnimation.animatedValue - it.to = 1.0 + val costWidth = manaCostAnimation.animatedValue / maxManaValue * (right - left) + val costLeft = (usageLeft - costWidth).roundToInt().coerceAtLeast(left) + drawContext.fill(costLeft, bottom, usageLeft, bottom + 3, color((opacity * 128).roundToInt(), 128, 25, 25)) } - dissolveAnimation.value = .0 - dissolveAnimation.duration = Duration.ofMillis(1000) - dissolveAnimation.startTime = Duration.ofMillis(0) - dissolveAnimation.start() + val currentMana = ((visibleMana * 10).toLong() - (usage * 10).toLong()) / 10.0 + val maxManaText = (maxManaValue * 10).toLong() / 10.0 + val manaText = "${MatrixLanguage.mana.string} = ${formatDecimal(currentMana)}/${formatDecimal(maxManaText)}" + drawContext.text( + minecraft.font, + manaText, + 55, + (12.5 + manaShownAnimation.animatedValue).roundToInt(), + color((opacity * 255).roundToInt(), 255, 255, 255), + ) + } - magicShownAnimationClock.start() - magicShownOpacityAnimationClock.start() + fun targetGuideChain(): List { + val result = mutableListOf() + val seen = mutableSetOf() - ManaCostTooltip.show() - AimAssist.resetAnimation() - if (firstShow) { - firstShow = false - selectTargetEntity(RenderTickCounter.ZERO) - if (targetedEntity == null) { - descriptionYOffsetAnimation.animatedValue = -35.0 + fun addTarget(entity: LivingEntity?) { + if (entity == null || !entity.isAlive || !seen.add(entity.id)) { + return } + result.add(entity) } - } - private fun renderManaBar( - drawContext: DrawContext, - tickCounter: RenderTickCounter, - ) { - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - val magicCost = selectedMagic.getCost(calculationContext).toDouble() - manaBar.manaCost.value = magicCost - - val renderer = LegacyMatrixUIRenderer(drawContext.vertexConsumers) - manaBar.render(drawContext, renderer) + addTarget(targetedEntity) + candidateTargets.forEach(::addTarget) + return result } - private fun renderLeftPart( - drawContext: DrawContext, - tickCounter: RenderTickCounter, - ) { - val magics = MatrixClient.getPlayerMagics() - val indentList = generateIndentList(magics.size) - fillExtraWidthAnimationList( - magics - ) - repeat( - magics.size - ) { - renderMagic(drawContext, tickCounter, it + 1, magics[it], indentList) + private fun renderLeftPart(drawContext: GuiGraphicsExtractor) { + val magics = currentMagicList() + if (magics.isEmpty()) { + return } - } - private fun restrictedSizedString( - string: String, - width: Double, - ): String { - val textRenderer = MinecraftClient.getInstance().textRenderer - var length = 0 - var index = 0 - for (character in string) { - length += textRenderer.getWidth( - character.toString() - ) - if (length > width) { - return string.take(index) - } - ++index - } + fillColorAnimationList(magics) + fillExtraWidthAnimationList(magics) + ensureMagicDisplayData(magics) - return string + val indentList = generateIndentList(magics.size) + magics.forEachIndexed { index, magic -> + renderMagic(drawContext, index, magic, indentList) + } } private fun renderMagic( - drawContext: DrawContext, - tickCounter: RenderTickCounter, + drawContext: GuiGraphicsExtractor, index: Int, magic: Magic, indentList: List, ) { - val displayData = magicDisplayData[index - 1] - val xIndent = indentList[index - 1].toInt() - - val animatedColor = magicColorAnimations.getOrNull( - index - 1 - ) - val color = ColorHelper.Argb.getArgb( - (magicShownOpacityAnimation.animatedValue * 127.5).toInt(), animatedColor?.red?.animatedValue?.toInt() ?: 0, animatedColor?.green?.animatedValue?.toInt() ?: 0, animatedColor?.blue?.animatedValue?.toInt() ?: 0 + val displayData = magicDisplayData[index] + val xIndent = indentList[index].roundToInt() + val animatedColor = magicColorAnimations.getOrNull(index) + val alpha = magicShownOpacityAnimation.animatedValue + val backgroundColor = color( + (alpha * 127.5).roundToInt(), + animatedColor?.red?.animatedValue?.roundToInt() ?: 0, + animatedColor?.green?.animatedValue?.roundToInt() ?: 0, + animatedColor?.blue?.animatedValue?.roundToInt() ?: 0, ) - val height = 20.0 + val rowHeight = 20.0 val margin = 5.0 + val startY = (index + 1) * (rowHeight + margin) + drawContext.guiHeight() / 2.0 - (indentList.size + 1) * (rowHeight + margin) / 2.0 + val top = startY.roundToInt() + val bottom = (startY + rowHeight).roundToInt() - val startY = (index * (height + margin) + drawContext.scaledWindowHeight / 2 - (indentList.size + 1) * (height + margin) / 2).toInt() - val endY = (startY + height).toInt() + val status = getMagicStatusDisplay(magic, targetMissingAsAvailable = true) + val calculationContext = MagicCalculationContext.fromEntity(minecraft.player, targetedEntity) + val normalCost = runCatching { magic.getNormalCost() }.getOrDefault(magic.definition.baseCost.toDouble().toLong()) + val cost = runCatching { magic.getCost(calculationContext) }.getOrDefault(normalCost) - val status = getMagicAvailableStatus( - magic - ).let { - if (it == LMagicAvailableStatus.TARGET_MISSING) { - LMagicAvailableStatus.AVAILABLE - } else { - it - } - } - - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - val normalCost = magic.getNormalCost() - val cost = magic.getCost(calculationContext) if (displayData.previousCost != cost) { - displayData.costChangedAnimation.value = .0 displayData.previousCost = cost - } - if (displayData.costChangedAnimation.animatedValue == .0) { displayData.displayCost = cost + displayData.costChangedAnimation.animatedValue = .0 displayData.costChangedAnimation.value = 1.0 } - if (displayData.previousStatus != status) { - displayData.statusChangedAnimation.value = .0 - displayData.previousStatus = status - } - if (displayData.statusChangedAnimation.animatedValue == .0) { - displayData.displayStatus = status + if (displayData.previousStatusKey != status.key) { + displayData.previousStatusKey = status.key + displayData.displayStatus = status.text + displayData.statusChangedAnimation.animatedValue = .0 displayData.statusChangedAnimation.value = 1.0 } - val costString = - if (displayData.displayCost > normalCost) { - "§c↑§r" + displayData.displayCost.toString() - } else if (displayData.displayCost < normalCost) { - "§a↓§r" + displayData.displayCost.toString() - } else { - displayData.displayCost.toString() - } - val statusString = displayData.displayStatus.description - val textRenderer = MinecraftClient.getInstance().textRenderer - displayData.costWidthAnimation.value = textRenderer.getWidth(costString).toDouble() + val costString = when { + displayData.displayCost > normalCost -> "§c↑§r${displayData.displayCost}" + displayData.displayCost < normalCost -> "§a↓§r${displayData.displayCost}" + else -> displayData.displayCost.toString() + } - val magicNameWidth = textRenderer.getWidth(magic.definition.name) + val magicNameWidth = minecraft.font.width(magic.definition.name) + displayData.costWidthAnimation.value = minecraft.font.width(costString).toDouble() val costStringWidth = displayData.costWidthAnimation.animatedValue - val statusStringWidth = textRenderer.getWidth(status.description) - val extraWidth = magicNameWidth + costStringWidth + statusStringWidth + 30 /* padding */ - val extraWidthAnimation = magicExtraWidthAnimations[index - 1].animation - extraWidthAnimation.currentValue = extraWidth - - drawContext.enableScissor( - xIndent + 50 + magicShownAnimation.animatedValue.toInt(), startY, xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt(), endY - ) - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - - val blurBackgroundStartX = xIndent + 50 + magicShownAnimation.animatedValue.toInt() - val blurBackgroundEndX = xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt() - - val builder = Tessellator.getInstance() - var buffer = builder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR) - buffer.vertex(transformationMatrix, blurBackgroundEndX.toFloat(), endY.toFloat(), 0f).color(color).texture(1.0F, 1.0F) - buffer.vertex(transformationMatrix, blurBackgroundEndX.toFloat(), startY.toFloat(), 0f).color(color).texture(1.0F, .0F) - buffer.vertex(transformationMatrix, blurBackgroundStartX.toFloat(), startY.toFloat(), 0f).color(color).texture(.0F, .0F) - buffer.vertex(transformationMatrix, blurBackgroundStartX.toFloat(), endY.toFloat(), 0f).color(color).texture(.0F, 1.0F) - - StateIsolation.isolate( - BlendState(true), - ShaderProgramState(GameRenderer::getPositionColorProgram) - ) { - BufferRenderer.drawWithGlobalProgram(buffer.end()) + val statusStringWidth = minecraft.font.width(displayData.displayStatus) + val extraWidth = magicNameWidth + costStringWidth + statusStringWidth + 30.0 + val extraWidthAnimation = magicExtraWidthAnimations[index] + extraWidthAnimation.value = extraWidth + + val offsetX = magicShownAnimation.animatedValue.roundToInt() + val left = xIndent + 50 + offsetX + val right = xIndent + 50 + extraWidthAnimation.animatedValue.roundToInt() + offsetX + + drawContext.enableScissor(left, top, right, bottom) + drawContext.fill(left, top, right, bottom, backgroundColor) + + val foregroundColor = color((alpha * 255).roundToInt(), 255, 255, 255) + if (alpha > 0.016) { + drawContext.text(minecraft.font, magic.definition.name, xIndent + 55 + offsetX, top + 5, foregroundColor) + } + + val costAlpha = min(alpha, displayData.costChangedAnimation.animatedValue) + if (costAlpha > 0.016) { + drawContext.text( + minecraft.font, + costString, + xIndent + 65 + magicNameWidth + offsetX, + top + 5, + color((costAlpha * 255).roundToInt(), 255, 255, 255), + ) } - // dissolveShader.disableShader() - - // drawContext.fill(xIndent + 50 + magicShownAnimation.animatedValue.toInt(), startY, xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt(), endY, 0, color) - val alpha = magicShownOpacityAnimation.animatedValue * 255 - val foregroundColor = ColorHelper.Argb.getArgb(alpha.toInt(), 255, 255, 255) - if (alpha > 4) { - val multiplier = 1.0F - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) - drawContext.drawText(textRenderer, magic.definition.name, xIndent + 55 + magicShownAnimation.animatedValue.toInt(), startY + 5, foregroundColor, false) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) + val statusAlpha = min(alpha, displayData.statusChangedAnimation.animatedValue) + if (statusAlpha > 0.016) { + drawContext.text( + minecraft.font, + displayData.displayStatus, + xIndent + 75 + magicNameWidth + costStringWidth.roundToInt() + offsetX, + top + 5, + color((statusAlpha * 255).roundToInt(), 255, 255, 255), + ) } + drawContext.disableScissor() - val costAlpha = min(alpha, displayData.costChangedAnimation.animatedValue * 255) - // println((displayData.costChangedAnimation.animatedValue * 255).toInt()) - if (costAlpha > 4) { - val multiplier = 1.0F - val costForegroundColor = ColorHelper.Argb.getArgb(costAlpha.toInt(), 255, 255, 255) - RenderSystem.setShaderColor(1.0F, multiplier, 1.0F, 1.0F) - drawContext.drawText(textRenderer, Text.literal(costString), xIndent + 65 + magicNameWidth + magicShownAnimation.animatedValue.toInt(), startY + 5, costForegroundColor, false) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) + val useAnimation = usingMagicList[index] ?: return + val maxX = xIndent + 55 + extraWidthAnimation.animatedValue + offsetX + val startX = xIndent + useAnimation + offsetX + val endX = startX + rowHeight + if (startX > maxX) { + usingMagicList.remove(index) + return } - val statusAlpha = min(alpha, displayData.statusChangedAnimation.animatedValue * 255) - if (statusAlpha > 4) { - val statusForegroundColor = ColorHelper.Argb.getArgb(statusAlpha.toInt(), 255, 255, 255) - drawContext.drawText(textRenderer, statusString, xIndent + 75 + magicNameWidth + costStringWidth.toInt() + magicShownAnimation.animatedValue.toInt(), startY + 5, statusForegroundColor, false) - } + val animationProgress = ((startX - xIndent - 50.0) / extraWidth).coerceIn(.0, 1.0) + drawContext.enableScissor(left, top, right, bottom) + drawSlantedBand( + drawContext, + startX, + top, + rowHeight, + rowHeight, + rowHeight, + color((alpha * 255 * (1.0 - animationProgress)).roundToInt(), 0, 255, 0), + ) + drawSlantedBand( + drawContext, + startX, + top, + rowHeight, + rowHeight, + rowHeight, + color((alpha * 128).roundToInt(), 25, 192, 25), + ) + drawSlantedBand( + drawContext, + startX + 10.0, + top, + rowHeight, + rowHeight, + rowHeight, + color((alpha * 255).roundToInt(), 25, 255, 25), + ) + drawSlantedBand( + drawContext, + startX + 20.0, + top, + rowHeight, + rowHeight, + rowHeight, + color((alpha * 128).roundToInt(), 25, 192, 25), + ) drawContext.disableScissor() + } - if (usingMagicList.containsKey( - index - ) - ) { - val deltaTime = usingMagicList[index]!! - - val maxX = xIndent + 55 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt() - - val startX = (xIndent + deltaTime) + magicShownAnimation.animatedValue.toInt() - val endX = startX + height - - if (startX > maxX) { - usingMagicList.remove( - index - ) - return - } + private fun renderRightPart(drawContext: GuiGraphicsExtractor) { + val alpha = magicShownOpacityAnimation.animatedValue + val width = drawContext.guiWidth() + val height = drawContext.guiHeight() + val offsetX = magicShownAnimation.animatedValue + val offsetY = descriptionExtraHeightAnimation.animatedValue + val left = (width - 200 - offsetX).roundToInt() + val right = (width - 25 - offsetX).roundToInt() + val top = (height / 2.0 - 100.0 - offsetY / 2.0).roundToInt() + val bottom = (height / 2.0 + 100.0 + offsetY / 2.0).roundToInt() - val animationProgress = (startX - xIndent - 50) / extraWidth - val progressColor = Color( - 25, 192, 25, (magicShownOpacityAnimation.animatedValue * 128).toInt() - ) - val brightProgressColor = Color( - 25, 255, 25, (magicShownOpacityAnimation.animatedValue * 255).toInt().coerceAtMost( - 255 - ) - ) - val transparentColor = Color( - 0, 0, 0, 0 - ) + drawContext.fill(left, top, right, bottom, color((alpha * 127.5).roundToInt(), 255, 255, 255)) - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - - // We're drawing in triangle strip mode, the first 3 vertices form the first triangle. - // Each added vertex forms a new triangle with the first vertex and the last vertex. - // - // We need to draw a parallelogram, we split the parallelogram into two triangles to render - // in this mode, first we draw the left triangle by the following order: - // 1. lower left corner (startX, endY) - // 2. lower right corner (endX, endY) - // 3. upper right corner (endX, startY) - // Then we draw the right triangle, in this mode we only need to draw a new vertex that will - // form a new triangle with the first two vertices, so we only need to draw the upper right - // of the right triangle (endX + width, startY) - drawContext.enableScissor( - xIndent + 50 + magicShownAnimation.animatedValue.toInt(), startY, xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt(), endY - ) + val target = cachedTargetedEntity + val descriptionAlpha = min(alpha, entityDescriptionOpacityAnimation.animatedValue) + if (target != null) { + renderTargetDescription(drawContext, target, descriptionAlpha, offsetX, offsetY) + } - val halfTransparentColor = Color(0, 255, 0, (magicShownOpacityAnimation.animatedValue * 255 * (1.0 - animationProgress)).toInt()) - buffer = tessellator.begin(VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR) - buffer.vertex( - transformationMatrix, startX.toFloat(), endY.toFloat(), 0f - ).color( - transparentColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), endY.toFloat(), 0f - ).color( - halfTransparentColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), startY.toFloat(), 0f - ).color( - transparentColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + height).toFloat(), startY.toFloat(), 0f - ).color( - halfTransparentColor.toInt() - ) - BufferRenderer.drawWithGlobalProgram(buffer.end()) + if (alpha <= 0.016) { + return + } - val multiplier = 4.0F - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, (0.7F - animationProgress).toFloat()) - buffer = tessellator.begin( - VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR - ) - buffer.vertex( - transformationMatrix, startX.toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + height).toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - BufferRenderer.drawWithGlobalProgram( - buffer.end() - ) + val selectedMagic = selectedMagicOrNull() ?: return + if (selectedMagic.definition.description != currentDescription) { + currentDescription = selectedMagic.definition.description + displayDescription = currentDescription + magicDescriptionChangedAnimation.animatedValue = .0 + magicDescriptionChangedAnimation.value = 1.0 + } - buffer = tessellator.begin( - VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR - ) - buffer.vertex( - transformationMatrix, (startX + 20).toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 20).toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 20).toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 20 + height).toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - BufferRenderer.drawWithGlobalProgram( - buffer.end() - ) + val lines = minecraft.font.split(currentDescription, 150) + val extraHeight = minecraft.font.lineHeight * lines.size - 180.0 + descriptionExtraHeightAnimation.value = extraHeight.coerceAtLeast(.0) - buffer = tessellator.begin( - VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR - ) - buffer.vertex( - transformationMatrix, (startX + 10).toFloat(), endY.toFloat(), 0f - ).color( - brightProgressColor.toInt() + drawContext.enableScissor(left, top, right, bottom) + val descriptionY = (height / 2.0 - 55.0 + descriptionYOffsetAnimation.animatedValue - descriptionExtraHeightAnimation.animatedValue / 2.0).roundToInt() + val textAlpha = min(alpha, magicDescriptionChangedAnimation.animatedValue) + if (textAlpha > 0.016) { + drawContext.textWithWordWrap( + minecraft.font, + displayDescription, + width - 190 - offsetX.roundToInt(), + descriptionY, + 150, + color((textAlpha * 255).roundToInt(), 255, 255, 255), ) - buffer.vertex( - transformationMatrix, (endX + 10).toFloat(), endY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 10).toFloat(), startY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 10 + height).toFloat(), startY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - - RenderSystem.enableBlend() - BufferRenderer.drawWithGlobalProgram(buffer.end()) - RenderSystem.defaultBlendFunc() - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - - // val renderer = MatrixUIRenderer(drawContext.vertexConsumers) - // renderer.renderRectangle( - // Rectangle( - // Point(startX, startY.toDouble()), - // Point(endX, endY.toDouble()) - // ), - // Color(0, 0, 128, magicShownOpacityAnimation.animatedValue.toInt()) - // ) - drawContext.disableScissor() } + drawContext.disableScissor() } - private fun renderOverclock( - drawContext: DrawContext, - tickCounter: RenderTickCounter, + private fun renderTargetDescription( + drawContext: GuiGraphicsExtractor, + target: LivingEntity, + descriptionAlpha: Double, + offsetX: Double, + offsetY: Double, ) { - val renderer = LegacyMatrixUIRenderer( - drawContext.vertexConsumers - ) - val manaOverclockMinPoint = Point( - renderer.scaledWindowWidth - 5.0, renderer.scaledWindowHeight.toDouble() - 25.0 - ) - val manaOverclockMaxPoint = Point( - renderer.scaledWindowWidth - 10.0, MathHelper.lerp( - manaOverclock.animatedValue / 10, renderer.scaledWindowHeight.toDouble() - 25.0, 25.0 - ) - ) - - val magicOverclockMinPoint = Point( - renderer.scaledWindowWidth - 15.0, renderer.scaledWindowHeight.toDouble() - 25.0 - ) + if (descriptionAlpha <= 0.016) { + return + } - val magicOverclockMaxPoint = Point( - renderer.scaledWindowWidth - 20.0, MathHelper.lerp( - magicOverclock.animatedValue / 10, renderer.scaledWindowHeight.toDouble() - 25.0, 25.0 + val width = drawContext.guiWidth() + val height = drawContext.guiHeight() + val health = target.health.toDouble() + val maxHealth = target.maxHealth.toDouble() + if (health.isFinite()) { + healthAnimation.value = health + } + if (maxHealth.isFinite()) { + maxHealthAnimation.value = maxHealth + } + healthPercentageAnimation.value = if (maxHealth > .0) (health / maxHealth).coerceIn(.0, 1.0) else .0 + + val percentage = healthPercentageAnimation.animatedValue + val barLeft = width - 190 - offsetX.roundToInt() + val barRight = (width - lerp(percentage, 190.0, 35.0) - offsetX).roundToInt() + val barTop = (height / 2.0 - 80.0 - offsetY / 2.0).roundToInt() + val barBottom = (height / 2.0 - 75.0 - offsetY / 2.0).roundToInt() + val red = (lerp(percentage, 255.0, 25.0)).roundToInt() + val green = (lerp(percentage, 25.0, 255.0)).roundToInt() + drawContext.fill(barLeft.coerceAtMost(barRight), barTop, barRight, barBottom, color((descriptionAlpha * 255).roundToInt(), red, green, 25)) + + val textColor = color((descriptionAlpha * 255).roundToInt(), 255, 255, 255) + val entityNameKey = target.displayName.string + if (entityNameKey != previousDisplayEntityNameKey) { + previousDisplayEntityNameKey = entityNameKey + displayEntityName = target.displayName + displayEntityNameOpacityAnimation.animatedValue = .0 + displayEntityNameOpacityAnimation.value = 1.0 + } + + val nameAlpha = min(descriptionAlpha, displayEntityNameOpacityAnimation.animatedValue) + if (nameAlpha > 0.016) { + drawContext.text( + minecraft.font, + displayEntityName, + barLeft, + (height / 2.0 - 90.0 - offsetY / 2.0).roundToInt(), + color((nameAlpha * 255).roundToInt(), 255, 255, 255), ) - ) + } - val magicOverclockColor = Color( - MathHelper.lerp( - magicOverclock.animatedValue / 10.0, 0.0, 255.0 - ).toInt(), MathHelper.lerp( - magicOverclock.animatedValue / 10.0, 255.0, 0.0 - ).toInt(), 0, 128 - ) + if (candidateTargets.size != previousCandidateEntityCount) { + previousCandidateEntityCount = candidateTargets.size + displayCandidateEntityCount = candidateTargets.size + displayCandidateCountOpacityAnimation.animatedValue = .0 + displayCandidateCountOpacityAnimation.value = 1.0 + } - val manaOverclockColor = Color( - MathHelper.lerp( - manaOverclock.animatedValue / 10.0, 0.0, 255.0 - ).toInt(), MathHelper.lerp( - manaOverclock.animatedValue / 10.0, 255.0, 0.0 - ).toInt(), 0, 128 - ) + val candidateAlpha = min(descriptionAlpha, displayCandidateCountOpacityAnimation.animatedValue) + if (candidateAlpha > 0.016) { + candidateCountPaddingAnimation.value = (minecraft.font.width(displayEntityName) + minecraft.font.width(" ")).toDouble() + drawContext.text( + minecraft.font, + "+$displayCandidateEntityCount", + (barLeft + candidateCountPaddingAnimation.animatedValue).roundToInt(), + (height / 2.0 - 90.0 - offsetY / 2.0).roundToInt(), + color((candidateAlpha * 255).roundToInt(), 255, 255, 255), + ) + } - renderer.renderRectangle( - Rectangle( - manaOverclockMinPoint, manaOverclockMaxPoint - ), manaOverclockColor - ) - renderer.renderRectangle( - Rectangle( - magicOverclockMinPoint, magicOverclockMaxPoint - ), magicOverclockColor + val healthText = "${formatDecimal(healthAnimation.animatedValue, scale = 2)}/${formatDecimal(maxHealthAnimation.animatedValue, scale = 2)}" + drawContext.text( + minecraft.font, + healthText, + barLeft, + (height / 2.0 - 70.0 - offsetY / 2.0).roundToInt(), + textColor, ) } - private fun selectTargetEntity(tickCounter: RenderTickCounter) { - var targetedEntity = getTargetedEntity(tickCounter.getTickDelta(true)) - if (targetedEntity is EnderDragonPart) { - targetedEntity = targetedEntity.owner - } - if (targetedEntity != this.targetedEntity) { - if (targetedEntity == null) { - entityDescriptionOpacityAnimation.value = .0 - descriptionYOffsetAnimation.value = -35.0 + private fun renderManaCostTooltip(drawContext: GuiGraphicsExtractor) { + val magic = selectedMagicOrNull() ?: return + val calculationContext = MagicCalculationContext.fromEntity(minecraft.player, targetedEntity) + val normalCost = runCatching { magic.getNormalCost() }.getOrDefault(magic.definition.baseCost.toDouble().toLong()) + val cost = runCatching { magic.getCost(calculationContext) }.getOrDefault(normalCost) + + if (cost == normalCost || magicShownOpacityAnimation.animatedValue <= 0.001) { + manaCostTooltipShownAnimation.value = .0 + manaCostTooltipOpacityAnimation.value = .0 + } else { + manaCostTooltipShownAnimation.value = 70.0 + manaCostTooltipOpacityAnimation.value = 1.0 + if (cost > normalCost) { + manaCostTooltipRedAnimation.value = .5 + manaCostTooltipGreenAnimation.value = .0 + manaCostTooltipBlueAnimation.value = .0 } else { - entityDescriptionOpacityAnimation.value = 1.0 - descriptionYOffsetAnimation.value = .0 + manaCostTooltipRedAnimation.value = .0 + manaCostTooltipGreenAnimation.value = .5 + manaCostTooltipBlueAnimation.value = .0 } } - if (targetedEntity is LivingEntity) { - cachedTargetedEntity = targetedEntity - } - this.targetedEntity = targetedEntity as? LivingEntity? - } - - private fun renderRightPart(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val backgroundColor = ColorHelper.Argb.getArgb((magicShownOpacityAnimation.animatedValue * 127.5).toInt(), 255, 255, 255) - val alpha = (magicShownOpacityAnimation.animatedValue * 255).coerceIn(.0..255.0).toInt() - - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR) - val offsetX = magicShownAnimation.animatedValue.toFloat() - val offsetY = descriptionExtraHeightAnimation.animatedValue.toFloat() - - val windowWidth = drawContext.scaledWindowWidth - val windowHeight = drawContext.scaledWindowHeight - - val leftX = windowWidth - 200 - offsetX - val rightX = windowWidth - 25 - offsetX - val topY = windowHeight / 2 - 100F - offsetY / 2F - val bottomY = windowHeight / 2 + 100F + offsetY / 2F - val width = rightX - leftX - val height = bottomY - topY - - buffer.vertex(rightX, topY, 0F).texture(0F, 0F).color(backgroundColor) - buffer.vertex(leftX, topY, 0F).texture(1F, 0F).color(backgroundColor) - buffer.vertex(leftX, bottomY, 0F).texture(1F, 1F).color(backgroundColor) - buffer.vertex(rightX, bottomY, 0F).texture(0F, 1F).color(backgroundColor) - - dissolveShader.dissolveFactor = dissolveAnimation.animatedValue.toFloat() - dissolveShader.resolutionX = width - dissolveShader.resolutionY = height - dissolveShader.enableShader() - - StateIsolation.isolate(BlendState(true)) { - BufferRenderer.draw(buffer.end()) + val opacity = manaCostTooltipOpacityAnimation.animatedValue + if (opacity <= 0.001) { + return } - dissolveShader.disableShader() - dissolveShader.resolutionX = 1.0F - dissolveShader.resolutionY = 1.0F - - val descriptionAlpha = min(magicShownOpacityAnimation.animatedValue * 255, entityDescriptionOpacityAnimation.animatedValue * 255).toInt() - val cachedTargetedEntity = this.cachedTargetedEntity - - val textRenderer = MinecraftClient.getInstance().textRenderer - if (cachedTargetedEntity != null) { - val red = ColorHelper.Argb.getArgb(descriptionAlpha, 255, 25, 25) - val green = ColorHelper.Argb.getArgb(descriptionAlpha, 25, 255, 25) + val left = drawContext.guiWidth() / 2 - 125 + val top = (drawContext.guiHeight() - manaCostTooltipShownAnimation.animatedValue).roundToInt() + val right = drawContext.guiWidth() / 2 + 125 + val bottom = top + 15 + drawContext.fill( + left, + top, + right, + bottom, + color( + (opacity * 128).roundToInt(), + (manaCostTooltipRedAnimation.animatedValue * 255).roundToInt(), + (manaCostTooltipGreenAnimation.animatedValue * 255).roundToInt(), + (manaCostTooltipBlueAnimation.animatedValue * 255).roundToInt(), + ), + ) - val health = cachedTargetedEntity.health.toDouble() - val maxHealth = cachedTargetedEntity.maxHealth.toDouble() + val difference = abs(normalCost - cost) + if (difference != lastManaCostTooltipDifference) { + lastManaCostTooltipDifference = difference + displayManaCostTooltipDifference = difference + manaCostTooltipDifferenceChangedAnimation.animatedValue = .0 + manaCostTooltipDifferenceChangedAnimation.value = 1.0 + } + val state = cost > normalCost + if (state != lastManaCostTooltipState) { + lastManaCostTooltipState = state + displayManaCostTooltipState = state + manaCostTooltipStateChangedAnimation.animatedValue = .0 + manaCostTooltipStateChangedAnimation.value = 1.0 + } + + val stateAlpha = min(opacity, manaCostTooltipStateChangedAnimation.animatedValue) + if (stateAlpha > 0.016) { + drawContext.text( + minecraft.font, + if (displayManaCostTooltipState) MatrixLanguage.manaCostIncreased else MatrixLanguage.manaCostReduced, + left + 5, + top + 3, + color((stateAlpha * 255).roundToInt(), 255, 255, 255), + ) + } + val differenceAlpha = min(opacity, manaCostTooltipDifferenceChangedAnimation.animatedValue) + if (differenceAlpha > 0.016) { + val differenceText = displayManaCostTooltipDifference.toString() + drawContext.text( + minecraft.font, + differenceText, + right - 5 - minecraft.font.width(differenceText), + top + 3, + color((differenceAlpha * 255).roundToInt(), 255, 255, 255), + ) + } + } - if (health.isFinite()) { - healthAnimation.value = health - } - if (maxHealth.isFinite()) { - maxHealthAnimation.value = maxHealth - } - healthPercentageAnimation.value = (health / maxHealth).coerceIn(.0..1.0) + private fun renderMagicAvailableStatus(drawContext: GuiGraphicsExtractor, hudActive: Boolean) { + val magic = selectedMagicOrNull() ?: return + val status = getMagicStatusDisplay(magic) + if (!hudActive || status.available || status.targetMissing) { + availableStatusShownAnimation.value = -50.0 + availableStatusOpacityAnimation.value = .0 + } else { + availableStatusShownAnimation.value = .0 + availableStatusOpacityAnimation.value = 1.0 + } - val percentage = healthPercentageAnimation.animatedValue - val lerpedColor = ColorHelper.Argb.lerp(percentage.toFloat(), red, green) + if (status.key != currentAvailableStatusKey && !status.available) { + currentAvailableStatusKey = status.key + displayAvailableStatus = status.text + availableStatusChangedAnimation.animatedValue = .0 + availableStatusChangedAnimation.value = 1.0 + } - val sizeReduced = if (sizeScalingAnimation) { - 10 - (entityDescriptionOpacityAnimation.animatedValue * 10).toInt() - } else { - 0 - } + val opacity = availableStatusOpacityAnimation.animatedValue + if (opacity <= 0.001) { + return + } - val progressBarX = MathHelper.lerp(percentage.toFloat(), 190, 35) - val x1 = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() + sizeReduced - val x2 = drawContext.scaledWindowWidth - progressBarX - magicShownAnimation.animatedValue.toInt() - sizeReduced - - val multiplier = lerp(1.0 - percentage, 1.0, 5.0).toFloat() - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) - drawContext.fill( - x1.coerceAtMost(x2), - drawContext.scaledWindowHeight / 2 - 80 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - sizeReduced, - x2, - drawContext.scaledWindowHeight / 2 - 75 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - sizeReduced, - lerpedColor + val left = drawContext.guiWidth() / 2 - 125 + val top = (30.0 + availableStatusShownAnimation.animatedValue).roundToInt() + val right = drawContext.guiWidth() / 2 + 125 + val bottom = (45.0 + availableStatusShownAnimation.animatedValue).roundToInt() + drawContext.fill(left, top, right, bottom, color((opacity * 128).roundToInt(), 128, 0, 0)) + + val textAlpha = min(opacity, availableStatusChangedAnimation.animatedValue) + if (textAlpha > 0.016) { + drawContext.text( + minecraft.font, + displayAvailableStatus, + left + 5, + top + 3, + color((textAlpha * 255).roundToInt(), 255, 255, 255), ) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - - val fontSizeReduced = if (sizeScalingAnimation) { - entityDescriptionOpacityAnimation.animatedValue.toFloat() - } else { - 1F - } - val descriptionForegroundColor = ColorHelper.Argb.getArgb(descriptionAlpha, 255, 255, 255) - if (descriptionAlpha > 3) { - val currentHealth = BigDecimal.valueOf(healthAnimation.animatedValue) - .setScale(2, RoundingMode.HALF_UP) - .toPlainString() - val maxHealth = BigDecimal.valueOf(maxHealthAnimation.animatedValue) - .setScale(2, RoundingMode.HALF_UP) - .toPlainString() - val healthText = StringBuilder() - .append(currentHealth) - .append("/") - .append(maxHealth) - .toString() - - val textX = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() - val textY = drawContext.scaledWindowHeight / 2 - 70 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - - val textWidth = textRenderer.getWidth(healthText) - val textCenterX = textX + textWidth / 2.0 - val textCenterY = textY.toDouble() - 15 - - drawContext.matrices.push() - - drawContext.matrices.translate(textCenterX, textCenterY, 0.0) - drawContext.matrices.scale(fontSizeReduced, fontSizeReduced, fontSizeReduced) - drawContext.matrices.translate(-textCenterX, -textCenterY, 0.0) - - drawContext.drawText( - textRenderer, - healthText, - textX, - textY, - descriptionForegroundColor, - false - ) - drawContext.matrices.pop() - } - - val hashCode = cachedTargetedEntity.name.hashCode() - if (hashCode != previousDisplayEntityNameHashCode) { - displayEntityNameOpacityAnimation.value = .0 - previousDisplayEntityNameHashCode = hashCode - } - if (displayEntityNameOpacityAnimation.animatedValue == .0) { - displayEntityNameOpacityAnimation.value = 1.0 - displayEntityName = cachedTargetedEntity.name - } - val entityNameAlpha = min(descriptionAlpha, (displayEntityNameOpacityAnimation.animatedValue * 255).toInt()) - val entityNameForegroundColor = ColorHelper.Argb.getArgb(entityNameAlpha, 255, 255, 255) - if (entityNameAlpha > 3) { - val textX = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() - val textY = drawContext.scaledWindowHeight / 2 - 90 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - - val textWidth = textRenderer.getWidth(displayEntityName) - val textCenterX = textX + textWidth / 2.0 - val textCenterY = textY + textRenderer.fontHeight / 2.0 + } + } - drawContext.matrices.push() + private fun renderOverclock(drawContext: GuiGraphicsExtractor) { + val alpha = magicShownOpacityAnimation.animatedValue + if (alpha <= 0.001) { + return + } + manaOverclockAnimation.value = manaOverclock + magicOverclockAnimation.value = magicOverclock - drawContext.matrices.translate(textCenterX, textCenterY, 0.0) - drawContext.matrices.scale(fontSizeReduced, fontSizeReduced, fontSizeReduced) - drawContext.matrices.translate(-textCenterX, -textCenterY, 0.0) + val width = drawContext.guiWidth() + val height = drawContext.guiHeight() + val manaTop = lerp((manaOverclockAnimation.animatedValue / 10.0).coerceIn(.0, 1.0), height - 25.0, 25.0).roundToInt() + val magicTop = lerp((magicOverclockAnimation.animatedValue / 10.0).coerceIn(.0, 1.0), height - 25.0, 25.0).roundToInt() + val manaColor = overclockColor(manaOverclockAnimation.animatedValue, alpha) + val magicColor = overclockColor(magicOverclockAnimation.animatedValue, alpha) - drawContext.drawText(textRenderer, displayEntityName, textX, textY, entityNameForegroundColor, true) + drawContext.fill(width - 10, manaTop, width - 5, height - 25, manaColor) + drawContext.fill(width - 20, magicTop, width - 15, height - 25, magicColor) + } - drawContext.matrices.pop() - } + private fun checkMagicAvailableStatus() { + val magics = currentMagicList() + fillColorAnimationList(magics) - if (candidateAimAssistEntities.size != previousCandidateEntities) { - displayCandidateCountOpacityAnimation.value = .0 - previousCandidateEntities = candidateAimAssistEntities.size - } else if (displayCandidateCountOpacityAnimation.animatedValue == .0) { - displayCandidateCountOpacityAnimation.value = 1.0 - displayCandidateEntities = candidateAimAssistEntities.size + magics.forEachIndexed { index, magic -> + val color = magicColorAnimations[index] + if (index == selectedMagicIndex) { + if (color.green.value == 255.0 || color.green.value == 128.0) { + color.setColor(.0, 128.0, .0) + } else { + color.setColorWithoutAnimation(.0, 128.0, .0) + } + return@forEachIndexed } - val candidateCountAlpha = min(descriptionAlpha, (displayCandidateCountOpacityAnimation.animatedValue * 255).toInt()) - val candidateCountColor = ColorHelper.Argb.getArgb(candidateCountAlpha, 255, 255, 255) - if (candidateCountAlpha > 3) { - candidateCountPadding.value = (textRenderer.getWidth(displayEntityName) + textRenderer.getWidth(" ")).toDouble() - val padding = candidateCountPadding.animatedValue - val textX = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() + padding - val textY = drawContext.scaledWindowHeight / 2 - 90 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - - val text = "+$displayCandidateEntities" - val textWidth = textRenderer.getWidth(text) - val textCenterX = textX + textWidth / 2.0 - val textCenterY = textY + textRenderer.fontHeight / 2.0 - - drawContext.matrices.push() - - drawContext.matrices.translate(textCenterX, textCenterY, 0.0) - drawContext.matrices.scale(fontSizeReduced, fontSizeReduced, fontSizeReduced) - drawContext.matrices.translate(-textCenterX, -textCenterY, 0.0) - - drawContext.drawText(textRenderer, text, round(textX).toInt(), textY, candidateCountColor, true) - - drawContext.matrices.pop() + val status = getMagicStatusDisplay(magic) + if (status.available || status.targetMissing) { + color.setColor(.0, .0, .0) + } else { + color.setColor(128.0, .0, .0) } } + } - if (alpha <= 3) { - return - } - - drawContext.enableScissor( - drawContext.scaledWindowWidth - 200 - magicShownAnimation.animatedValue.toInt(), - drawContext.scaledWindowHeight / 2 - 100 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt(), - drawContext.scaledWindowWidth - 25 - magicShownAnimation.animatedValue.toInt(), - drawContext.scaledWindowHeight / 2 + 100 + (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - ) - val currentMagic = MatrixClient.getPlayerMagics()[selectedIndex - 1] - - if (currentMagic.definition.description != currentDescription) { - currentDescription = currentMagic.definition.description - magicDescriptionChangedAnimation.value = .0 - } - if (magicDescriptionChangedAnimation.animatedValue == .0) { - magicDescriptionChangedAnimation.value = 1.0 - displayDescription = currentDescription + private fun performChannelMagicAnimation() { + val now = System.nanoTime() + val delta = now - lastFrameNanos + usingMagicList.keys.toList().forEach { index -> + usingMagicList[index] = (usingMagicList[index] ?: .0) + delta / 2_000_000.0 } + } - val descriptionY = drawContext.scaledWindowHeight / 2 - 55 + descriptionYOffsetAnimation.animatedValue.toInt() - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() // + magicSwitchAnimation.animatedValue - - val lines = textRenderer.wrapLines(currentDescription, 150) - val extraHeight = textRenderer.fontHeight * lines.size - 180.0 - descriptionExtraHeightAnimation.value = extraHeight.coerceAtLeast(.0) + private val magicDisplayData: MutableList + get() = cachedMagicDisplayData - val magicDescriptionAlpha = (min(magicShownOpacityAnimation.animatedValue, magicDescriptionChangedAnimation.animatedValue) * 255).toInt() - if (magicDescriptionAlpha > 3) { - drawContext.drawTextWrapped(textRenderer, displayDescription, drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt(), descriptionY, 150, ColorHelper.Argb.getArgb(magicDescriptionAlpha, 255, 255, 255)) + private fun ensureMagicDisplayData(magics: List) { + if (cachedMagicDisplayData.size == magics.size) { + return } - drawContext.disableScissor() + cachedMagicDisplayData = MutableList(magics.size) { MagicDisplayData() } } - private fun getTargetedEntity(tickDelta: Float): Entity? { - val candidateEntities = getAssistTargetEntity(tickDelta)//.filter { entity -> - // val rotationVector = player.getRotationVec(tickDelta) - // val from = player.getCameraPosVec(tickDelta) - // val to = player.getCameraPosVec(tickDelta).add(rotationVector.multiply(aimAssistMaxDistance)) - // val blockHit = player.world.raycast(RaycastContext(from, to, RaycastContext.ShapeType.VISUAL, RaycastContext.FluidHandling.ANY, player)) - // val blockHitDistance = player.squaredDistanceTo(blockHit.pos) - // blockHitDistance >= entity.squaredDistanceTo(player) - //} - candidateAimAssistEntities = candidateEntities - - val rayCastTarget = getRayCastTargetEntity(tickDelta) - if (rayCastTarget != null) { - usingRayCast = true - return rayCastTarget + private fun fillColorAnimationList(magics: List) { + while (magicColorAnimations.size < magics.size) { + magicColorAnimations.add(HudColorAnimation()) } - usingRayCast = false - return candidateEntities.firstOrNull() } - private fun getAssistTargetEntity(tickDelta: Float): List { - val entities = minecraft.cameraEntity?.getEntitiesNearSight( - aimAssistMaxDistance, - aimAssistFov, - tickDelta - ) // TODO: Sort by distance - if (entities == null) { - return emptyList() + private fun fillExtraWidthAnimationList(magics: List) { + while (magicExtraWidthAnimations.size < magics.size) { + magicExtraWidthAnimations.add(SimpleDoubleAnimation(initValue = .0)) } - - return entities - .filter { it is LivingEntity && !it.isSpectator && it.isAlive } - .map { it as LivingEntity } - .filter { - val calculationContext = MagicCalculationContext.fromEntity(player, it) - selectedMagic.availableStatus(calculationContext) == LMagicAvailableStatus.AVAILABLE - } } - private fun getRayCastTargetEntity(tickDelta: Float): Entity? { - val range = 10000.0 - - val minecraftClient = MinecraftClient.getInstance()!! - val camera = minecraftClient.cameraEntity!! - - val location = camera.getCameraPosVec(tickDelta) - val rotation = camera.getRotationVec(tickDelta) - val min = location.add(rotation) - val max = location.add(rotation.multiply(range)) - val box = Box(min, max) - - // Wrap Dancer: Select entities through walls - if (player.wizardHelmetStack.item is WizardHelmet5) { - val result = ProjectileUtil.raycast(camera, min, max, box, { entity -> - if (entity.isSpectator) { - return@raycast false - } - true - }, range) - return result?.entity + private fun getMagicStatusDisplay( + magic: Magic, + targetMissingAsAvailable: Boolean = false, + ): MagicStatusDisplay { + val status = getMagicAvailability(magic).firstOrNull() + if (status == null) { + return MagicStatusDisplay("available", MatrixLanguage.magicAvailable, available = true, targetMissing = false) } - val blockHit = player.world.raycast(RaycastContext(min, max, RaycastContext.ShapeType.VISUAL, RaycastContext.FluidHandling.ANY, player)) - val blockHitDistance = player.squaredDistanceTo(blockHit.pos) - val result = ProjectileUtil.raycast(camera, min, max, box, { entity -> - if (entity.isSpectator) { - return@raycast false - } - - blockHitDistance > entity.squaredDistanceTo(player) - }, range) + val targetMissing = status.identifier.path == MagicAvailableStatus.TargetMissing.identifier.path + if (targetMissingAsAvailable && targetMissing) { + return MagicStatusDisplay("available", MatrixLanguage.magicAvailable, available = true, targetMissing = true) + } - return result?.entity + return MagicStatusDisplay( + key = status.identifier.toString(), + text = legacyStatusText(status), + available = false, + targetMissing = targetMissing, + ) } - private val crosshairX = SimpleDoubleAnimation() - private val crosshairY = SimpleDoubleAnimation() + private fun getMagicAvailability(magic: Magic): MagicAvailability { + val context = MagicCalculationContext.fromEntity(minecraft.player, targetedEntity) + return runCatching { magic.availableStatus(context) } + .getOrDefault(MagicAvailability(MagicAvailableStatus.Unavailable)) + } - @JvmStatic - fun translateCrosshairPosition(x: Float, y: Float): Vector2f { - if (!aimAssistEnabled) { - return Vector2f(x, y) + private fun legacyStatusText(status: MagicAvailableStatus): Component { + return when (status.identifier.path) { + MagicAvailableStatus.InsufficientMana.identifier.path -> MatrixLanguage.magicAvailableManaNotEnough + MagicAvailableStatus.TargetImmune.identifier.path -> MatrixLanguage.magicTargetImmune + MagicAvailableStatus.Unavailable.identifier.path -> MatrixLanguage.magicUnavailable + MagicAvailableStatus.ChannelQueueFull.identifier.path -> MatrixLanguage.magicChannelQueueFull + MagicAvailableStatus.ChannelQueueLocked.identifier.path -> MatrixLanguage.magicChannelQueueLocked + MagicAvailableStatus.TargetMissing.identifier.path -> MatrixLanguage.magicTargetMissing + "sculk_catalyst_is_already_active" -> MatrixLanguage.magicSculkCatalystIsAlreadyActive + else -> status.description } + } - if (crosshairX.from == .0) { - crosshairX.from = x.toDouble() + private fun generateIndentList(size: Int): List { + if (size <= 0) { + return emptyList() } - if (crosshairY.from == .0) { - crosshairY.from = y.toDouble() + val ease = ElasticEase().also { + it.oscillations = 0 + it.springiness = 1.0 + it.easingMode = EasingMode.OUT } - val targetedEntity = targetedEntity - if (targetedEntity == null) { - crosshairX.value = x.toDouble() - crosshairY.value = y.toDouble() - } else { - val tickDelta = minecraft.renderTickCounter.getTickDelta(true) - val lerpedPosition = targetedEntity.getLerpedPos(tickDelta).add( - .0, - targetedEntity.boundingBox.lengthY / 2, - .0 - ) - val screenPosition = worldToScreen(lerpedPosition) - if (screenPosition != null) { - crosshairX.value = screenPosition.x - crosshairY.value = screenPosition.y - } + val center = size / 2.0 + return List(size) { index -> + val distance = abs(center - index) + val current = 1.0 - ease.transform(1.0 - (distance / center).coerceIn(.0, 1.0)) + current * 50.0 - 25.0 } - - return Vector2f(crosshairX.animatedValue.toFloat(), crosshairY.animatedValue.toFloat()) } - private fun generateIndentList(size: Int): List { - val result = mutableListOf() - - val ease = ElasticEase() - ease.apply { - oscillations = 0 - springiness = 1.0 - easingMode = EasingMode.OUT + private fun drawSlantedBand( + drawContext: GuiGraphicsExtractor, + startX: Double, + top: Int, + width: Double, + height: Double, + slant: Double, + color: Int, + ) { + val rows = height.roundToInt().coerceAtLeast(1) + for (row in 0 until rows) { + val t = row / rows.toDouble() + val left = startX + slant * (1.0 - t) + val right = left + width + drawContext.fill(left.roundToInt(), top + row, right.roundToInt().coerceAtLeast(left.roundToInt() + 1), top + row + 1, color) } + } - // var current = 0 - val center = size / 2.0 - for (i in 0 until size) { - val distance = abs(center - i) - val current = 1 - ease.transform(1 - distance.inverseLerp(.00..center)) - - result.add(current * 50 - 25) + private fun overclockColor(value: Double, alpha: Double): Int { + val ratio = (value / 10.0).coerceIn(.0, 1.0) + return color( + (alpha * 128).roundToInt(), + lerp(ratio, .0, 255.0).roundToInt(), + lerp(ratio, 255.0, .0).roundToInt(), + 0, + ) + } - // if (size % 2 == 0 && i == size / 2 - 1) { - // continue - // } -// - // if (i >= size / 2) { - // current += 5 - // } else { - // current -= 5 - // } + private fun formatDecimal(value: Double, scale: Int = 1): String { + if (!value.isFinite()) { + return "∞" } + return BigDecimal.valueOf(value) + .setScale(scale, RoundingMode.HALF_UP) + .toPlainString() + } - return result + private fun lerp(delta: Double, from: Double, to: Double): Double { + return from + (to - from) * delta } - fun onRemoteManaUpdate() { - manaBar.onRemoteManaUpdate() + private fun selectedMagicOrNull(): Magic? { + val magics = currentMagicList() + selectedMagicIndex = selectedMagicIndex.coerceIn(0, (magics.size - 1).coerceAtLeast(0)) + return magics.getOrNull(selectedMagicIndex) } - @JvmStatic - fun onKey(window: Long, key: Int, scancode: Int, action: Int, mods: Int): Boolean { - if (window != minecraft.window.handle) { - return false + private fun bestUsableTarget(magic: Magic): LivingEntity? { + val target = targetedEntity + if (target != null && canChannelMagicOn(target, magic)) { + return target } + return candidateTargets.firstOrNull { canChannelMagicOn(it, magic) } + } - if (isPressingTab && InputUtil.isKeyPressed(minecraft.window.handle, GLFW.GLFW_KEY_E) && - player.getEquippedStack(EquipmentSlot.CHEST).item is LightningChestplate1 - ) { - ClientPlayNetworking.send(BorrowedTimePayload()) - return true + private fun canChannelMagicOn(target: LivingEntity?, magic: Magic): Boolean { + val player = minecraft.player ?: return false + target ?: return false + val queue = target.getChannelQueue(player) + if (queue?.isLocked == true) { + return false } - - if (InputUtil.isKeyPressed(minecraft.window.handle, GLFW.GLFW_KEY_E) && shouldRenderHud()) { - ClientPlayNetworking.send(ServerboundActivateBloodPactPayload()) - return true + if (queue?.isChanneling == true && queue.queuedMagicCount >= player.queueSize) { + return false } - if (!KeyEvent.EVENT.invoker().onKey(key, scancode, action, mods)) { - return true - } - return false + val context = MagicCalculationContext( + caster = CasterContext.fromEntity(player), + target = target, + queue = queue, + ) + return magic.availableStatus(context).isAvailable } - private var debug = false - - @JvmStatic - fun onMouseButton(window: Long, button: Int, action: Int, mods: Int): Boolean { - if (window != minecraft.window.handle) { - return false - } + private fun Vec3.toGuiScreenPosition( + tickDelta: Float, + viewportWidth: Int, + viewportHeight: Int, + centered: Boolean = false, + ): Vector2f? { + val screenPosition = worldToScreen( + this, + viewportWidth = viewportWidth, + viewportHeight = viewportHeight, + ) ?: return null + + val halfSize = if (centered) 0.0 else 7.5 + val maxX = viewportWidth - if (centered) 0.0 else 15.0 + val maxY = viewportHeight - if (centered) 0.0 else 15.0 + return Vector2f( + (screenPosition.x - halfSize).coerceIn(0.0, maxX).toFloat(), + (screenPosition.y - halfSize).coerceIn(0.0, maxY).toFloat(), + ) + } - if (shouldRenderHud() && button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { - if (action == GLFW.GLFW_PRESS) { - debug = true + private fun LivingEntity.guidePosition(tickDelta: Float): Vec3 { + return getLerpedPos(tickDelta).add(.0, boundingBox.ysize * 0.5, .0) + } - fovZoomRatio += 0.2 - isPressingRightMouseButton = true - return true - } else if (action == GLFW.GLFW_RELEASE) { - fovZoomRatio = .0 - isPressingRightMouseButton = false - return true - } + private fun Entity?.asLivingTarget(): LivingEntity? { + return when (this) { + is LivingEntity -> this + is EnderDragonPart -> parentMob + else -> null } + } - if (!MouseButtonEvent.EVENT.invoker().onMouseButton(button, action, mods)) { - return true - } - return false + private fun shouldRenderMagicList(): Boolean { + val player = minecraft.player ?: return false + return player.isWizard && + minecraft.gui.screen() == null && + currentMagicList().isNotEmpty() && + magicListKeyDown } - @JvmStatic - fun nextZoomLevel() { - fovZoomRatio = (fovZoomRatio + 0.2).coerceAtMost(0.95) + private fun hasHudContext(): Boolean { + val player = minecraft.player ?: return false + return player.isWizard && currentMagicList().isNotEmpty() } - @JvmStatic - fun previousZoomLevel() { - fovZoomRatio = (fovZoomRatio - 0.2).coerceAtLeast(.0) + private fun Int.floorMod(modulo: Int): Int { + return ((this % modulo) + modulo) % modulo } -} \ No newline at end of file + + private fun syncOverclock() { + if (minecraft.player == null || minecraft.connection == null) { + return + } + ClientPlayNetworking.send(ServerboundOverclockPayload(manaOverclock, magicOverclock)) + } + +} + +private fun color(alpha: Int, red: Int, green: Int, blue: Int): Int { + return ARGB.color(alpha.coerceIn(0, 255), red.coerceIn(0, 255), green.coerceIn(0, 255), blue.coerceIn(0, 255)) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt index 2d9221c8..607d5aaf 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt @@ -5,56 +5,61 @@ package heckerpowered.matrix.client -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper -import net.minecraft.client.option.KeyBinding -import net.minecraft.client.util.InputUtil +import com.mojang.blaze3d.platform.InputConstants +import heckerpowered.matrix.Matrix +import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper +import net.minecraft.client.KeyMapping import org.lwjgl.glfw.GLFW object MatrixKeyBindings { - val useMagic: KeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( + private val category = KeyMapping.Category.register(Matrix.identifier("key_category")) + + val useMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( "key.matrix.use_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_F, - "key.categories.matrix" + category ) ) - val nextMagic: KeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( + val nextMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( "key.matrix.next_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_DOWN, - "key.categories.matrix" + category ) ) - val previousMagic: KeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( + val previousMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( "key.matrix.previous_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UP, - "key.categories.matrix" + category ) ) - val overclockMagic = KeyBinding( - "key.matrix.overclock_magic", - InputUtil.Type.KEYSYM, - GLFW.GLFW_KEY_N, - "key.categories.matrix" + val overclockMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( + "key.matrix.overclock_magic", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_N, + category + ) ) - val overclockMana = KeyBinding( - "key.matrix.overclock_mana", - InputUtil.Type.KEYSYM, - GLFW.GLFW_KEY_M, - "key.categories.matrix" + val overclockMana: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( + "key.matrix.overclock_mana", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_M, + category + ) ) fun onInitialize() { - // KeyBindingHelper.registerKeyBinding(useMagic) - // KeyBindingHelper.registerKeyBinding(nextMagic) - // KeyBindingHelper.registerKeyBinding(previousMagic) + // Key mappings are registered during property initialization. } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt b/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt index 890bc01c..b920cc50 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt @@ -7,17 +7,18 @@ package heckerpowered.matrix.client import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.common.network.ServerboundWarpPayload -import it.unimi.dsi.fastutil.floats.FloatUnaryOperator import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking -import net.minecraft.client.MinecraftClient -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.util.Util import kotlin.time.Duration import kotlin.time.Duration.Companion.nanoseconds object TimeController { + private const val WARP_HEARTBEAT_NANOS = 500_000_000L + private const val STANDALONE_TICK_MILLIS = 50.0F + private val timeControllers = mutableSetOf() - private var previousMinScale = .0 + private var previousMinScale = 1.0 + private var clientTimeScale = 1.0 + private var lastWarpSyncNanos = 0L private var lastFrameTime = Duration.ZERO var deltaTime = Duration.ZERO @@ -32,12 +33,58 @@ object TimeController { return controller } + class StandaloneRenderTickCounter { + private var deltaTicks = .0F + private var deltaTickResidual = .0F + private var pausedDeltaTickResidual = .0F + private var lastMillis = 0L + private var paused = false + private var frozen = false + + fun beginRenderTick(timeMillis: Long, tick: Boolean): Int { + if (!tick) { + return 0 + } + if (lastMillis == 0L) { + lastMillis = timeMillis + return 0 + } + + val elapsedMillis = (timeMillis - lastMillis).coerceAtLeast(0L) + lastMillis = timeMillis + deltaTicks = elapsedMillis / STANDALONE_TICK_MILLIS + deltaTickResidual += deltaTicks + val ticks = deltaTickResidual.toInt() + deltaTickResidual -= ticks.toFloat() + return ticks + } + + fun tick(paused: Boolean) { + if (paused && !this.paused) { + pausedDeltaTickResidual = deltaTickResidual + } else if (!paused && this.paused) { + deltaTickResidual = pausedDeltaTickResidual + } + this.paused = paused + } + + fun setTickFrozen(frozen: Boolean) { + this.frozen = frozen + } + + fun getTickDelta(tick: Boolean): Float { + if (!tick && frozen) { + return 1.0F + } + return if (paused) pausedDeltaTickResidual else deltaTickResidual + } + } + @JvmField - var standaloneRenderTickCounter: RenderTickCounter.Dynamic = - RenderTickCounter.Dynamic(20.0f, 0L, FloatUnaryOperator.identity()) + var standaloneRenderTickCounter = StandaloneRenderTickCounter() val isTimeScaled: Boolean - get() = MinecraftClient.getInstance().renderTickCounter.tickTime - 50.0F > 0.001F + get() = clientTimeScale < 0.999 || previousMinScale != 1.0 @JvmStatic var playerImmuneTimeScale: Boolean = false @@ -51,16 +98,37 @@ object TimeController { private var previousPlayerStandaloneTickState = false private fun setTimeScale(timeScale: Double) { - MinecraftClient.getInstance().renderTickCounter.tickTime = (50.0 / timeScale).toFloat() + if (minecraft.connection == null) { + return + } ClientPlayNetworking.send(ServerboundWarpPayload(timeScale, playerStandaloneRenderTick)) + lastWarpSyncNanos = System.nanoTime() } private fun setClientTimeScale(timeScale: Double) { - MinecraftClient.getInstance().renderTickCounter.tickTime = (50.0 / timeScale).toFloat() + clientTimeScale = timeScale.coerceIn(0.01, 1.0) } fun setPlayerStandaloneTimeScale(timeScale: Double) { - MinecraftClient.getInstance().renderTickCounter.tickTime = (50.0 / timeScale).toFloat() + setClientTimeScale(timeScale) + } + + @JvmStatic + fun getClientGameTimeScale(): Float { + return clientTimeScale.coerceIn(0.01, 1.0).toFloat() + } + + @JvmStatic + fun shouldScaleClientGameTime(): Boolean { + return getClientGameTimeScale() < 0.999F + } + + @JvmStatic + fun scaleClientGameDelta(delta: Float): Float { + if (clientTimeScale >= 0.999) { + return delta + } + return (delta * clientTimeScale.toFloat()).coerceAtLeast(0.0F) } @JvmStatic @@ -69,24 +137,24 @@ object TimeController { deltaTime = System.nanoTime().nanoseconds - lastFrameTime } lastFrameTime = System.nanoTime().nanoseconds - val ticks = standaloneRenderTickCounter.beginRenderTick(Util.getMeasuringTimeMs(), tick) - if (minecraft.world == null || minecraft.player == null) { + val standaloneTicks = standaloneRenderTickCounter.beginRenderTick(timeMillis, tick) + val level = minecraft.level ?: return + val player = minecraft.player ?: return + if (!playerStandaloneRenderTick || minecraft.isPaused || standaloneTicks <= 0) { return } - if (!playerStandaloneRenderTick) { - return - } - for (i in 0..= WARP_HEARTBEAT_NANOS + if (minScale != previousMinScale || previousPlayerStandaloneTickState != playerStandaloneRenderTick || shouldRefreshWarp) { setTimeScale(minScale) } @@ -98,4 +166,4 @@ object TimeController { val minTimeScale get() = timeControllers.minOf { it.value } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/core/AimAssist.kt b/common/src/main/kotlin/heckerpowered/matrix/client/core/AimAssist.kt index e0856bf7..61a1b104 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/core/AimAssist.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/core/AimAssist.kt @@ -10,8 +10,8 @@ import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.core.lerp import heckerpowered.matrix.core.toDegrees import heckerpowered.matrix.core.wrapDegrees -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.util.math.Vec3d +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.minecraft.world.phys.Vec3 import java.time.Duration import kotlin.math.atan2 import kotlin.math.sqrt @@ -35,7 +35,7 @@ object AimAssist { var autoUnlock = true init { - HudRenderCallback.EVENT.register { drawContext, tickCounter -> + ClientTickEvents.END_CLIENT_TICK.register { if (autoApplyRotation && isAiming) { applyRotation() } @@ -47,22 +47,25 @@ object AimAssist { @JvmStatic fun onMouseUpdate(timeDelta: Double): Boolean { - lockedPitch.from = player.getPitch(timeDelta.toFloat()).toDouble() - lockedYaw.from = player.getYaw(timeDelta.toFloat()).toDouble() + val player = player ?: return false + lockedPitch.from = player.getXRot(timeDelta.toFloat()).toDouble() + lockedYaw.from = player.getYRot(timeDelta.toFloat()).toDouble() return isMouseLocked && isAiming } fun applyRotation() { - player.pitch = lockedPitch.animatedValue.toFloat() - player.yaw = lockedYaw.animatedValue.toFloat() + val player = player ?: return + player.setXRot(lockedPitch.animatedValue.toFloat()) + player.setYRot(lockedYaw.animatedValue.toFloat()) } - fun lookAt(position: Vec3d, tickDelta: Double) { - val x = lerp(tickDelta, player.prevX, player.x) - val y = lerp(tickDelta, player.prevY, player.y) - val z = lerp(tickDelta, player.prevZ, player.z) + fun lookAt(position: Vec3, tickDelta: Double) { + val player = player ?: return + val x = lerp(tickDelta, player.xo, player.x) + val y = lerp(tickDelta, player.yo, player.y) + val z = lerp(tickDelta, player.zo, player.z) - val playerPosition = Vec3d(x, y, z) + val playerPosition = Vec3(x, y, z) val direction = position.subtract(playerPosition) val distance2D = sqrt(direction.x * direction.x + direction.z * direction.z) @@ -74,12 +77,13 @@ object AimAssist { lockedPitch.value = wrapDegrees(pitch) } - fun rotationDifference(position: Vec3d, tickDelta: Double): Double { - val x = lerp(tickDelta, player.prevX, player.x) - val y = lerp(tickDelta, player.prevY, player.y) - val z = lerp(tickDelta, player.prevZ, player.z) + fun rotationDifference(position: Vec3, tickDelta: Double): Double { + val player = player ?: return 0.0 + val x = lerp(tickDelta, player.xo, player.x) + val y = lerp(tickDelta, player.yo, player.y) + val z = lerp(tickDelta, player.zo, player.z) - val playerPosition = Vec3d(x, y, z) + val playerPosition = Vec3(x, y, z) val direction = position.subtract(playerPosition) val distance2D = sqrt(direction.x * direction.x + direction.z * direction.z) @@ -87,8 +91,8 @@ object AimAssist { val pitch = -toDegrees(atan2(direction.y, distance2D)) val yaw = toDegrees(atan2(direction.z, direction.x)) - 90 - val pitchDifference = wrapDegrees(pitch) - wrapDegrees(player.pitch.toDouble()) - val yawDifference = wrapDegrees(yaw) - wrapDegrees(player.yaw.toDouble()) + val pitchDifference = wrapDegrees(pitch - player.xRot.toDouble()) + val yawDifference = wrapDegrees(yaw - player.yRot.toDouble()) return sqrt(pitchDifference * pitchDifference + yawDifference * yawDifference) } @@ -96,4 +100,4 @@ object AimAssist { lockedPitch.start() lockedYaw.start() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt b/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt index 5c4f8fd9..e8d44cb9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt @@ -7,21 +7,22 @@ package heckerpowered.matrix.client.gameplay import heckerpowered.matrix.client.TimeController import heckerpowered.matrix.client.player -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.entity.Entity +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.minecraft.world.entity.Entity object ImminentDanger { private val timeController = TimeController.allocateTimeController() var trackedEntity: Entity? = null init { - HudRenderCallback.EVENT.register { drawContext, tickCounter -> + ClientTickEvents.END_CLIENT_TICK.register { + val player = player ?: return@register val trackedEntity = this.trackedEntity - if (trackedEntity != null && trackedEntity.isAlive && trackedEntity.squaredDistanceTo(player) < 9) { + if (trackedEntity != null && trackedEntity.isAlive && trackedEntity.distanceToSqr(player) < 9) { timeController.value = 0.05 } else { timeController.value = 1.0 } } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt b/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt index 8ac40922..125dc561 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt @@ -10,15 +10,14 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking object MatrixClientPlayNetworking { fun onInitialize() { - ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncManaPayload.id, ClientboundSyncManaPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundSystemCrashPayload.id, ClientboundSystemCrashPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundChannelMagicPayload.id, ClientboundChannelMagicPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundBorrowedTimePayload.id, ClientboundBorrowedTimePayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncHealthPayload.id, ClientboundSyncHealthPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundWitherArmorTriggerPayload.id, ClientboundWitherArmorTriggerPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ImminentDangerPayload.id, ImminentDangerPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundTeleportPayload.type, ClientboundTeleportPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundExplosionPayload.id, ClientboundExplosionPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundDamageNumberPayload.id, ClientboundDamageNumberPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncManaPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundSystemCrashPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundChannelMagicPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundBorrowedTimePayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncHealthPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundWitherArmorTriggerPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundTeleportPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundExplosionPayload.type) { payload, context -> payload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundDamageNumberPayload.type) { payload, context -> payload.handle(context) } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt index bcd36db4..66a3bd68 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt @@ -9,12 +9,15 @@ import heckerpowered.matrix.client.ui.foundation.animation.AnimationClock import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase +import heckerpowered.matrix.common.magic.channel.ChannelEntry import heckerpowered.matrix.common.magic.core.Magic -import net.minecraft.entity.LivingEntity +import net.minecraft.world.entity.LivingEntity import java.time.Duration +import kotlin.math.max class ChannelAnimation( val magic: Magic, + val sourceEntry: ChannelEntry? = null, ) { companion object { private val easingFunction = ElasticEase().also { @@ -29,16 +32,51 @@ class ChannelAnimation( var opacityAnimation = DoubleAnimation(opacityAnimationClock, easingFunction) var channelTime = 0L - var currentChannelTime = 0L + var currentChannelTime = .0 var initialProgressOffset = 0F + private var completionAnimationStarted = false init { shownAnimationClock.start() opacityAnimationClock.start() } - fun tick(entity: LivingEntity) { - if (currentChannelTime++ == channelTime) { + fun tick(entity: LivingEntity, tickAmount: Double = 1.0) { + sourceEntry?.let { + currentChannelTime = max(currentChannelTime, it.currentChannelTime.toDouble()) + } + + if (completionAnimationStarted) { + currentChannelTime = max(currentChannelTime, channelTime + 1.0) + return + } + + currentChannelTime += tickAmount.coerceAtLeast(.0) + if (currentChannelTime >= channelTime) { + currentChannelTime = channelTime + 1.0 + completionAnimationStarted = true + opacityAnimationClock.from = opacityAnimation.animatedValue + opacityAnimationClock.to = 0.0 + opacityAnimationClock.start() + + ChannelSequenceRenderer.offsetAnimationMap[entity]?.let { + it.xOffsetAnimationClock.from = .0 + it.xOffsetAnimationClock.to = -24.0 + it.xOffsetAnimationClock.start() + } + } + } + + fun syncProgress(entity: LivingEntity, currentTime: Double) { + if (completionAnimationStarted) { + currentChannelTime = max(currentChannelTime, channelTime + 1.0) + return + } + + currentChannelTime = currentTime.coerceAtLeast(.0) + if (currentChannelTime >= channelTime) { + currentChannelTime = channelTime + 1.0 + completionAnimationStarted = true opacityAnimationClock.from = opacityAnimation.animatedValue opacityAnimationClock.to = 0.0 opacityAnimationClock.start() @@ -50,4 +88,4 @@ class ChannelAnimation( } } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt index ed78484f..b700fb5a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt @@ -5,320 +5,149 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.render.effect.SculkCatalystEffectRenderer -import heckerpowered.matrix.client.render.post.CollapseEffectRenderer +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.ui.foundation.animation.AnimationClock import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase import heckerpowered.matrix.common.magic.spell.SculkCatalystMagic -import heckerpowered.matrix.core.worldToScreen -import heckerpowered.matrix.extension.MatrixLivingEntity -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.client.render.entity.feature.FeatureRenderer -import net.minecraft.client.render.entity.feature.FeatureRendererContext -import net.minecraft.client.render.entity.model.EntityModel -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.entity.EntityAttachmentType -import net.minecraft.util.math.MathHelper +import heckerpowered.matrix.core.getLerpedPos +import heckerpowered.matrix.core.toDegrees +import heckerpowered.matrix.core.wrapDegrees +import heckerpowered.matrix.client.render.effect.SculkCatalystEffectRenderer +import heckerpowered.matrix.client.render.post.CollapseEffectRenderer +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.DeltaTracker +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiGraphicsExtractor import net.minecraft.world.entity.LivingEntity -import org.joml.Matrix4f +import org.joml.Vector2f import java.time.Duration -import java.util.* +import java.util.WeakHashMap +import kotlin.math.abs +import kotlin.math.atan2 +import kotlin.math.sqrt +import kotlin.math.tan + +object ChannelSequenceRenderer { + private val easingFunction = ElasticEase().also { + it.easingMode = EasingMode.OUT + it.oscillations = 0 + } -class ChannelSequenceRenderer( - context: FeatureRendererContext>, -) : FeatureRenderer>(context) { + class OffsetAnimation { + val xOffsetAnimationClock = AnimationClock(Duration.ofMillis(300), .0, -24.0) + var xOffsetAnimation = DoubleAnimation(xOffsetAnimationClock, easingFunction) + } - private val disabled = false + val channelSequenceAnimationMap = WeakHashMap>() + val offsetAnimationMap = WeakHashMap() - companion object { - private val easingFunction = ElasticEase().also { - it.easingMode = EasingMode.OUT - it.oscillations = 0 + fun onInitialize() { + ClientTickEvents.END_CLIENT_TICK.register { + channelSequenceAnimationMap.keys.toList().forEach(::onEntityTick) } - - class OffsetAnimation { - val xOffsetAnimationClock = AnimationClock(Duration.ofMillis(300), .0, -24.0) - var xOffsetAnimation = DoubleAnimation(xOffsetAnimationClock, easingFunction) + HudElementRegistry.addLast(Matrix.identifier("channel_sequence")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) } + } - val channelSequenceAnimationMap = WeakHashMap>() - val offsetAnimationMap = WeakHashMap() - - init { - EntityTickCallback.EVENT.register(::onEntityTick) - // HudRenderCallback.EVENT.register(::onHudRender) - // ClientTickEvents.START_WORLD_TICK.register { world -> - // for (entry in channelSequenceAnimationMap) { - // if (entry.key.world != world) { - // continue - // } - // for (channelAnimation in entry.value) { - // if (channelAnimation.currentChannelTime <= channelAnimation.channelTime) { - // channelAnimation.tick(entry.key) - // break - // } - // } - // } - - // for (entry in channelSequenceAnimationMap.entries) { - // if (entry.key.world != world) { - // continue - // } - // val entity = entry.key - // val list = entry.value - // val iterator = list.iterator() - // while (iterator.hasNext()) { - // val channelAnimation = iterator.next() - // if (channelAnimation.currentChannelTime > channelAnimation.channelTime && channelAnimation.opacityAnimation.animatedValue == 0.0) { - // offsetAnimationMap[entity]?.let { - // it.xOffsetAnimationClock.from = .0 - // it.xOffsetAnimationClock.to = .0 - // } - // iterator.remove() - // } - // } - // } - // } + private fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + for ((entity, animation) in channelSequenceAnimationMap) { + renderEntityChannelSequence(drawContext, tickCounter, entity, animation) } + } - private fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - for (entry in channelSequenceAnimationMap) { - val entity = entry.key - val animation = entry.value - renderEntityChannelSequence(drawContext, tickCounter, entity, animation) + private fun renderEntityChannelSequence( + drawContext: GuiGraphicsExtractor, + tickCounter: DeltaTracker, + entity: LivingEntity, + animation: List, + ) { + val tickDelta = tickCounter.getGameTimeDeltaPartialTick(false) + val lerpedPosition = entity.getLerpedPos(tickDelta).add(.0, entity.boundingBox.ysize + 0.25, .0) + val entityScreenPosition = lerpedPosition.toScreenPosition(tickDelta, drawContext.guiWidth(), drawContext.guiHeight()) ?: return + + animation.forEachIndexed { index, channelAnimation -> + val alpha = channelAnimation.opacityAnimation.animatedValue + val backgroundColor = Color(128, 0, 0, (128 * alpha).toInt()).toInt() + val progressColor = Color(255, 0, 0, (255 * alpha).toInt()).toInt() + val animatedX = offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: .0 + + val isChanneling = index == 0 || animation[index - 1].currentChannelTime >= animation[index - 1].channelTime + val currentChannelTime = if (isChanneling) channelAnimation.currentChannelTime else .0 + val channelDuration = channelAnimation.channelTime.toDouble().coerceAtLeast(1.0) + val channelProgress = ( + currentChannelTime / + channelDuration + ).coerceAtMost(1.0) + + val minX = (entityScreenPosition.x - 8.0 + index * 24 + animatedX).toInt() + val maxX = (entityScreenPosition.x + 8.0 + index * 24 + animatedX).toInt() + val topY = (entityScreenPosition.y + channelAnimation.shownAnimation.animatedValue).toInt() + val bottomY = (entityScreenPosition.y + 16.0 + channelAnimation.shownAnimation.animatedValue).toInt() + val progressY = (entityScreenPosition.y + (1 - channelProgress).coerceIn(.0, 1.0) * 16.0 + channelAnimation.shownAnimation.animatedValue).toInt() + + drawContext.fill(minX, topY, maxX, progressY, backgroundColor) + drawContext.fill(minX, progressY, maxX, bottomY, progressColor) + + if (channelAnimation.magic == SculkCatalystMagic && channelAnimation.currentChannelTime < channelAnimation.channelTime) { + SculkCatalystEffectRenderer.entity = entity + CollapseEffectRenderer.dissolveFactor.value = channelProgress / 4.0 } } + } - private fun renderRectangle( - buffer: BufferBuilder, - positionMatrix: Matrix4f, - rectangle: Rectangle, - color: Color, - z: Float = 0F, - ) { - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) + private fun net.minecraft.world.phys.Vec3.toScreenPosition(tickDelta: Float, viewportWidth: Int, viewportHeight: Int): Vector2f? { + val minecraft = Minecraft.getInstance() + val player = minecraft.player ?: return null + val eyePosition = player.getEyePosition(tickDelta) + val direction = subtract(eyePosition) + val distance2D = sqrt(direction.x * direction.x + direction.z * direction.z) + if (distance2D <= 0.0001 && abs(direction.y) <= 0.0001) { + return null } - private fun renderEntityChannelSequence(drawContext: DrawContext, tickCounter: RenderTickCounter, entity: LivingEntity, animation: List) { - val tickDelta = tickCounter.getTickDelta(false) - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - val buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) - - val lerpedPosition = entity.getLerpedPos(tickDelta).add( - .0, - entity.boundingBox.lengthY, - .0 - ) - val entityScreenPosition = worldToScreen(lerpedPosition) ?: return + val pitch = -toDegrees(atan2(direction.y, distance2D)) + val yaw = toDegrees(atan2(direction.z, direction.x)) - 90.0 + val yawDifference = wrapDegrees(yaw - player.getYRot(tickDelta).toDouble()) + val pitchDifference = wrapDegrees(pitch - player.getXRot(tickDelta).toDouble()) - animation.forEachIndexed { index, channelAnimation -> - val color = Color(128, 0, 0, (128 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val progressColor = Color(255, 0, 0, (255 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val animatedX = if (channelAnimation.opacityAnimation.animatedValue != 1.0 && channelAnimation.opacityAnimationClock.to == 0.0) { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } else { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } - - val isChanneling = if (index == 0) { - true - } else { - animation[index - 1].let { it.currentChannelTime >= it.channelTime } - } - val partialProgress = if (isChanneling) { - tickDelta - } else { - .0f - } - val channelProgress = ((channelAnimation.currentChannelTime + partialProgress - channelAnimation.initialProgressOffset) / channelAnimation.channelTime.toDouble()).coerceAtMost(1.0) - - val progressRectangle = Rectangle( - Point( - entityScreenPosition.x + -8.0 + index * 24 + animatedX, - entityScreenPosition.y + 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - entityScreenPosition.x + 8.0 + index * 24 + animatedX, - entityScreenPosition.y + (1 - channelProgress) * 16.0 + channelAnimation.shownAnimation.animatedValue - ) - ) - val rectangle = Rectangle( - Point( - entityScreenPosition.x + -8.0 + index * 24 + animatedX, - entityScreenPosition.y + (1 - channelProgress).coerceIn(.0..1.0) * 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - entityScreenPosition.x + 8.0 + index * 24 + animatedX, - entityScreenPosition.y + .0 + channelAnimation.shownAnimation.animatedValue - ) - ) - renderRectangle(buffer, transformationMatrix, rectangle, color, 0F) - renderRectangle(buffer, transformationMatrix, progressRectangle, progressColor, 0F) - } + val verticalFov = minecraft.options.fov().get().toDouble().coerceIn(30.0, 110.0) + val aspectRatio = viewportWidth.toDouble() / viewportHeight.toDouble().coerceAtLeast(1.0) + val horizontalFov = toDegrees(2.0 * atan2(tan(java.lang.Math.toRadians(verticalFov) / 2.0) * aspectRatio, 1.0)) - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) + val x = viewportWidth / 2.0 + + tan(java.lang.Math.toRadians(yawDifference)) / tan(java.lang.Math.toRadians(horizontalFov) / 2.0) * viewportWidth / 2.0 + val y = viewportHeight / 2.0 + + tan(java.lang.Math.toRadians(pitchDifference)) / tan(java.lang.Math.toRadians(verticalFov) / 2.0) * viewportHeight / 2.0 - buffer.endNullable()?.let { BufferRenderer.draw(it) } - - RenderSystem.disableBlend() - } - - private fun onEntityTick(entity: LivingEntity) { - if (!entity.world.isClient) { - return - } - val channelAnimation = channelSequenceAnimationMap[entity] ?: return - val removed = channelAnimation.removeIf { it.currentChannelTime > it.channelTime && it.opacityAnimation.animatedValue == 0.0 } - if (removed) { - offsetAnimationMap[entity]?.xOffsetAnimationClock?.apply { - from = .0 - to = .0 - } - } - channelAnimation - .firstOrNull { it.currentChannelTime <= it.channelTime } - ?.tick(entity) - } + return Vector2f( + x.coerceIn(0.0, viewportWidth.toDouble()).toFloat(), + y.coerceIn(0.0, viewportHeight.toDouble()).toFloat(), + ) } - override fun render( - matrices: MatrixStack, - vertexConsumers: VertexConsumerProvider, - light: Int, - entity: LivingEntity, - limbAngle: Float, - limbDistance: Float, - tickDelta: Float, - animationProgress: Float, - headYaw: Float, - headPitch: Float, - ) { - if (entity !is MatrixLivingEntity || disabled) { + private fun onEntityTick(entity: LivingEntity) { + if (!entity.level().isClientSide) { return } - - val channelAnimations = channelSequenceAnimationMap[entity] ?: return - - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - - val minecraftClient = MinecraftClient.getInstance() - val camera = minecraftClient.gameRenderer.camera - val entityRenderer = minecraftClient.entityRenderDispatcher.getRenderer(entity) - val positionOffset = entityRenderer.getPositionOffset(entity, tickDelta) - - val entityPartialX = MathHelper.lerp(tickDelta.toDouble(), entity.lastRenderX, entity.x) - val entityPartialY = MathHelper.lerp(tickDelta.toDouble(), entity.lastRenderY, entity.y) - val entityPartialZ = MathHelper.lerp(tickDelta.toDouble(), entity.lastRenderZ, entity.z) - - val entityRelativeX = entityPartialX - camera.pos.x - val entityRelativeY = entityPartialY - camera.pos.y - val entityRelativeZ = entityPartialZ - camera.pos.z - - val offsetX = entityRelativeX + positionOffset.x - val offsetY = entityRelativeY + positionOffset.y - val offsetZ = entityRelativeZ + positionOffset.z - - val matrixStack = MatrixStack() - matrixStack.push() - matrixStack.translate(offsetX, offsetY, offsetZ) - - val position = entity.attachments.getPointNullable(EntityAttachmentType.NAME_TAG, 0, entity.getYaw(tickDelta))!! - - matrixStack.push() - matrixStack.translate(position.x, position.y + 0.5, position.z) - matrixStack.multiply(minecraftClient.entityRenderDispatcher.rotation) - matrixStack.scale(0.025f, -0.025f, 0.025f) - - val positionMatrix = matrixStack.peek().positionMatrix - - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - RenderSystem.enableBlend() - val layer = RenderLayer.getGui() - val buffer = vertexConsumers.getBuffer(layer) - - channelAnimations.forEachIndexed { index, channelAnimation -> - val color = Color(128, 0, 0, (128 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val progressColor = Color(255, 0, 0, (255 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val animatedX = if (channelAnimation.opacityAnimation.animatedValue != 1.0 && channelAnimation.opacityAnimationClock.to == 0.0) { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } else { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } - - val isChanneling = if (index == 0) { - true - } else { - channelAnimations[index - 1].let { it.currentChannelTime >= it.channelTime } - } - val partialProgress = if (isChanneling) { - tickDelta - } else { - .0f - } - val channelProgress = ((channelAnimation.currentChannelTime + partialProgress - channelAnimation.initialProgressOffset) / channelAnimation.channelTime.toDouble()).coerceAtMost(1.0) - val progressRectangle = Rectangle( - Point( - -8.0 + index * 24 + animatedX, 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - 8.0 + index * 24 + animatedX, (1 - channelProgress) * 16.0 + channelAnimation.shownAnimation.animatedValue - ) - ) - val rectangle = Rectangle( - Point( - -8.0 + index * 24 + animatedX, (1 - channelProgress).coerceIn(.0..1.0) * 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - 8.0 + index * 24 + animatedX, .0 + channelAnimation.shownAnimation.animatedValue - ) - ) - renderRectangle( - buffer, positionMatrix, rectangle, color, light, if (isChanneling) { - 0.01f - } else { - -0.01f - } - ) - renderRectangle( - buffer, positionMatrix, progressRectangle, progressColor, light, if (isChanneling) { - 0f - } else { - -0.01f - } - ) - if (channelAnimations[index].magic == SculkCatalystMagic && - channelAnimations[index].currentChannelTime < channelAnimations[index].channelTime - ) { - SculkCatalystEffectRenderer.entity = entity - CollapseEffectRenderer.dissolveFactor.value = channelProgress / 4.0 + val channelAnimation = channelSequenceAnimationMap[entity] ?: return + val removed = channelAnimation.removeIf { it.currentChannelTime > it.channelTime && it.opacityAnimation.animatedValue == 0.0 } + if (removed) { + offsetAnimationMap[entity]?.xOffsetAnimationClock?.apply { + from = .0 + to = .0 } } - - RenderSystem.disableBlend() - matrixStack.pop() - matrixStack.pop() - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - } - - private fun renderRectangle( - buffer: VertexConsumer, - positionMatrix: Matrix4f?, - rectangle: Rectangle, - color: Color, - light: Int, - z: Float = 0.01f, - ) { - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) + if (channelAnimation.isEmpty()) { + channelSequenceAnimationMap.remove(entity) + offsetAnimationMap.remove(entity) + return + } + channelAnimation + .firstOrNull { it.currentChannelTime <= it.channelTime } + ?.tick(entity) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt index 609de58d..16426bc3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt @@ -5,25 +5,19 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager - object FramebufferCapture { - private var previousFramebuffer: Int = 0 + private var capturing = false val captureFramebuffer = PostProcessRenderer.createManagedFramebuffer() fun beginCapture() { - if (previousFramebuffer != 0) { + if (capturing) { throw IllegalStateException("Cannot begin capture while another capture is in progress") } - previousFramebuffer = GlStateManager.getBoundFramebuffer() - captureFramebuffer.beginWrite(false) + capturing = true } fun endCapture() { - captureFramebuffer.endWrite() - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) - previousFramebuffer = 0 + capturing = false } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt index 387682e8..e7a8e6c5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt @@ -5,18 +5,12 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.systems.RenderSystem -import net.minecraft.client.MinecraftClient -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.text.Text -import kotlin.math.max -import kotlin.math.min +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.network.chat.Component @Deprecated("Deprecated") -class MatrixHUDRenderer(val drawContext: DrawContext, val tickCounter: RenderTickCounter) { +class MatrixHUDRenderer(val drawContext: GuiGraphicsExtractor, val tickCounter: DeltaTracker) { fun enableScissor(rectangle: Rectangle) { drawContext.enableScissor( rectangle.min.x.toInt(), @@ -31,65 +25,21 @@ class MatrixHUDRenderer(val drawContext: DrawContext, val tickCounter: RenderTic } fun renderRectangle(rectangle: Rectangle, color: Color) { - drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - - tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) + drawContext.fill( + rectangle.min.x.toInt(), + rectangle.min.y.toInt(), + rectangle.max.x.toInt(), + rectangle.max.y.toInt(), + color.toInt() + ) } } @Deprecated("Deprecated") -class LegacyMatrixUIRenderer(private val vertexConsumers: VertexConsumerProvider.Immediate) { - private val minecraft = MinecraftClient.getInstance() - private val matrixStack = MatrixStack() - private val textRenderer = minecraft.textRenderer - - val scaledWindowWidth: Int - get() = minecraft.window.scaledWidth - - val scaledWindowHeight: Int - get() = minecraft.window.scaledHeight - - private fun renderOnLayer(layer: RenderLayer, rectangle: Rectangle, color: Color) { - val maxX = max(rectangle.min.x, rectangle.max.x) - val maxY = max(rectangle.min.y, rectangle.max.y) - - val minX = min(rectangle.min.x, rectangle.max.x) - val minY = min(rectangle.min.y, rectangle.max.y) - - val vertexConsumer = vertexConsumers.getBuffer(layer) - val matrix = matrixStack.peek().positionMatrix - vertexConsumer.vertex(matrix, maxX.toFloat(), maxY.toFloat(), 0f).color(color.toInt()) - vertexConsumer.vertex(matrix, maxX.toFloat(), minY.toFloat(), 0f).color(color.toInt()) - vertexConsumer.vertex(matrix, minX.toFloat(), minY.toFloat(), 0f).color(color.toInt()) - vertexConsumer.vertex(matrix, minX.toFloat(), maxY.toFloat(), 0f).color(color.toInt()) +class LegacyMatrixUIRenderer(private val vertexConsumers: Any? = null) { + val scaledWindowWidth: Int get() = 0 + val scaledWindowHeight: Int get() = 0 - render() - } - - private fun render() { - RenderSystem.disableDepthTest() - vertexConsumers.draw() - RenderSystem.enableDepthTest() - } - - fun renderRectangle(rectangle: Rectangle, color: Color) { - renderOnLayer(RenderLayer.getGui(), rectangle, color) - } - - fun render(text: Text, point: Point, color: Color, shadow: Boolean = false) { - textRenderer.draw( - text, - point.x.toFloat(), - point.y.toFloat(), - color.toInt(), - shadow, - matrixStack.peek().positionMatrix, - vertexConsumers, - TextRenderer.TextLayerType.NORMAL, - 0, - 0xF000F0 - ) - render() - } -} \ No newline at end of file + fun renderRectangle(rectangle: Rectangle, color: Color) = Unit + fun render(text: Component, point: Point, color: Color, shadow: Boolean = false) = Unit +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixPostUniforms.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixPostUniforms.kt new file mode 100644 index 00000000..2615fccd --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixPostUniforms.kt @@ -0,0 +1,243 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.client.render + +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.buffers.GpuBufferSlice +import com.mojang.blaze3d.systems.CommandEncoder +import com.mojang.blaze3d.systems.RenderSystem +import heckerpowered.matrix.client.MatrixHud +import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.projectionMatrix +import heckerpowered.matrix.client.render.post.BloomEffect +import heckerpowered.matrix.client.render.post.CollapseEffectRenderer +import heckerpowered.matrix.client.render.post.ScaleSampling +import heckerpowered.matrix.client.render.post.ShockwaveRenderer +import heckerpowered.matrix.client.render.post.ToneMapping +import heckerpowered.matrix.client.render.shader.GaussianBlurRenderer +import heckerpowered.matrix.client.render.shader.RadialBlurRenderer +import heckerpowered.matrix.client.render.shader.TentShader +import heckerpowered.matrix.client.render.shader.hud.ProgressRingRenderer +import heckerpowered.matrix.client.render.shader.sdf.DropShadowRenderer +import heckerpowered.matrix.client.render.shader.sdf.SignedDistanceField +import heckerpowered.matrix.client.viewMatrix +import net.minecraft.client.gl.Framebuffer +import org.joml.Matrix4f +import org.joml.Vector4f +import java.nio.ByteBuffer +import java.nio.ByteOrder + +object MatrixPostUniforms { + const val BLOCK_NAME = "MatrixPostUniforms" + private const val BUFFER_SIZE = 256L + + var colorFilterColor = Vector4f(1.0F, 1.0F, 1.0F, 1.0F) + var edgeHighlightThreshold = 1.0F + var edgeHighlightColor = Vector4f(0.7F, 0.1F, 0.1F, 1.0F) + + private val buffers = mutableMapOf() + + fun prepare( + pass: MatrixShaderPipelines.PostProcessPass, + input: Framebuffer, + output: Framebuffer, + encoder: CommandEncoder, + ): Map { + if (pass.uniformBlocks.isEmpty()) { + return emptyMap() + } + + val result = linkedMapOf() + for (uniformBlock in pass.uniformBlocks) { + val data = ByteBuffer.allocateDirect(BUFFER_SIZE.toInt()).order(ByteOrder.nativeOrder()) + write(uniformBlock, pass.fragmentShader, input, output, data) + data.position(0) + data.limit(BUFFER_SIZE.toInt()) + + val buffer = buffers.getOrPut(uniformBlock) { + RenderSystem.getDevice().createBuffer( + { "Matrix post uniform $uniformBlock" }, + GpuBuffer.USAGE_UNIFORM or GpuBuffer.USAGE_COPY_DST, + BUFFER_SIZE, + ) + } + val slice = buffer.slice(0, BUFFER_SIZE) + encoder.writeToBuffer(slice, data) + result[uniformBlock] = slice + } + return result + } + + private fun write(block: String, fragmentShader: String, input: Framebuffer, output: Framebuffer, data: ByteBuffer) { + if (block != BLOCK_NAME) { + return + } + + when (fragmentShader) { + "post/hud/progress_ring" -> { + ProgressRingRenderer.center.also { center -> + data.putVec4(0, ProgressRingRenderer.progress, ProgressRingRenderer.radius, ProgressRingRenderer.thickness, .0F) + data.putVec4(1, center.x, center.y, .0F, .0F) + ProgressRingRenderer.color.also { color -> data.putVec4(2, color.x, color.y, color.z, color.w) } + } + } + + "post/tone_mapping/aces_filmic" -> { + data.putVec4(0, ToneMapping.exposureLinear, ToneMapping.exposureEv, .0F, .0F) + } + + "post/bloom/bloom_brightness_pass" -> { + data.putVec4(0, BloomEffect.brightnessThreshold, BloomEffect.bloomIntensity, .0F, .0F) + } + + "post/blur/radial_blur" -> { + data.putVec4(0, RadialBlurRenderer.strength, RadialBlurRenderer.samples.toFloat(), .0F, .0F) + } + + "post/blur/tent" -> { + data.putVec4(0, PostProcessRenderer.levelOfDetail + TentShader.levelOfDetail, .0F, .0F, .0F) + } + + "post/blur/kawase_blur" -> { + data.putVec4(0, 1.0F, 1.0F, .0F, .0F) + } + + "post/blur/gaussian_blur" -> { + val kernel = GaussianBlurRenderer.gaussianKernel + val kernelSize = (kernel.size - 1).coerceIn(0, 48) + data.putVec4(0, GaussianBlurRenderer.direction.x, GaussianBlurRenderer.direction.y, kernelSize.toFloat(), .0F) + if (kernel.isEmpty()) { + data.putFloat(16, 1.0F) + } else { + for (index in 0..kernelSize) { + data.putFloat(16 + index * 4, kernel[index]) + } + } + } + + "post/bloom/bloom_lower_sampling_pass" -> { + data.putVec4(0, 1.0F, .0F, .0F, .0F) + } + + "post/bloom/bloom_super_sampling_pass" -> { + data.putVec4(0, 15.0F, .0F, .0F, .0F) + } + + "post/lower_sampling/lod" -> { + data.putVec4(0, ScaleSampling.levelOfDetail, .0F, .0F, .0F) + } + + "post/lower_sampling/hybrid_lod" -> { + data.putVec4(0, ScaleSampling.levelOfDetail, ScaleSampling.levelOfDetail + 1.0F, 0.5F, .0F) + } + + "post/sampling/bilinear" -> { + data.putVec4( + 0, + input.textureWidth.toFloat(), + input.textureHeight.toFloat(), + output.textureWidth.toFloat(), + output.textureHeight.toFloat(), + ) + } + + "post/sdf/jump_flooding" -> { + data.putVec4(0, SignedDistanceField.stepSize, .0F, .0F, .0F) + } + + "post/sdf/drop_shadow" -> { + DropShadowRenderer.shadowOffset.also { offset -> + data.putVec4(0, offset.x, offset.y, DropShadowRenderer.shadowSize, .0F) + } + DropShadowRenderer.shadowColor.also { color -> + data.putVec4(1, color.x, color.y, color.z, color.w) + } + } + + "post/color/colorful" -> { + data.putVec4(0, 1.0F, 1.0F, 1.0F, .0F) + } + + "post/color_filter" -> { + colorFilterColor.also { color -> + data.putVec4(0, color.x, color.y, color.z, color.w) + } + } + + "post/color_fusion" -> { + data.putVec4(0, colorMultiplier.x, colorMultiplier.y, colorMultiplier.z, colorMultiplier.w) + } + + "post/edge_highlight" -> { + data.putVec4(0, edgeHighlightThreshold, .0F, .0F, .0F) + edgeHighlightColor.also { color -> + data.putVec4(1, color.x, color.y, color.z, color.w) + } + } + + "post/ghost" -> { + data.putVec4(0, 1.0F, .0F, .0F, .0F) + } + + "post/the_world" -> { + data.putVec4(0, MatrixHud.grayscaleIntensity, .0F, .0F, .0F) + } + + "post/shockwave" -> { + data.putMatrix4f(0, projectionMatrix.invert(Matrix4f())) + data.putMatrix4f(64, viewMatrix.invert(Matrix4f())) + ShockwaveRenderer.wavePosition.also { position -> + data.putVec4(8, position.x, position.y, position.z, ShockwaveRenderer.waveRadius.animatedValue.toFloat()) + } + ShockwaveRenderer.waveColor.also { color -> + data.putVec4(9, color.x, color.y, color.z, color.w) + } + data.putVec4(10, ShockwaveRenderer.waveSize.animatedValue.toFloat(), .0F, .0F, .0F) + } + + "post/collapse" -> { + data.putMatrix4f(0, projectionMatrix.invert(Matrix4f())) + data.putMatrix4f(64, viewMatrix.invert(Matrix4f())) + val playerPosition = minecraft.player?.position() + data.putVec4( + 8, + playerPosition?.x?.toFloat() ?: .0F, + playerPosition?.y?.toFloat() ?: .0F, + playerPosition?.z?.toFloat() ?: .0F, + CollapseEffectRenderer.dissolveFactor.animatedValue.toFloat(), + ) + data.putVec4(9, input.textureWidth.toFloat(), input.textureHeight.toFloat(), .0F, .0F) + } + } + } + + private fun ByteBuffer.putMatrix4f(offset: Int, matrix: Matrix4f) { + putFloat(offset, matrix.m00()) + putFloat(offset + 4, matrix.m01()) + putFloat(offset + 8, matrix.m02()) + putFloat(offset + 12, matrix.m03()) + putFloat(offset + 16, matrix.m10()) + putFloat(offset + 20, matrix.m11()) + putFloat(offset + 24, matrix.m12()) + putFloat(offset + 28, matrix.m13()) + putFloat(offset + 32, matrix.m20()) + putFloat(offset + 36, matrix.m21()) + putFloat(offset + 40, matrix.m22()) + putFloat(offset + 44, matrix.m23()) + putFloat(offset + 48, matrix.m30()) + putFloat(offset + 52, matrix.m31()) + putFloat(offset + 56, matrix.m32()) + putFloat(offset + 60, matrix.m33()) + } + + private fun ByteBuffer.putVec4(index: Int, x: Float, y: Float, z: Float, w: Float) { + val offset = index * 16 + putFloat(offset, x) + putFloat(offset + 4, y) + putFloat(offset + 8, z) + putFloat(offset + 12, w) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt index 6feeb58e..645b21bd 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt @@ -5,58 +5,37 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.render.OpenGLExtensions.getErrorName -import heckerpowered.matrix.core.math.Vector3fExtensions.unaryMinus -import net.minecraft.client.render.Camera +import net.minecraft.client.Camera import org.joml.Matrix4f import org.joml.Matrix4fc import org.joml.Quaternionf -import org.lwjgl.opengl.GL46.* object MatrixRenderSystem { var projectionMatrix = Matrix4f() var viewMatrix = Matrix4f() var viewProjectionMatrix = Matrix4f() - var inverseProjectionMatrix = Matrix4f() var inverseViewMatrix = Matrix4f() var inverseViewProjectionMatrix = Matrix4f() @JvmStatic - fun setupMatrix(camera: Camera, projectionMatrix: Matrix4fc) { - this.projectionMatrix = Matrix4f(projectionMatrix) - - val rotation = camera.rotation.conjugate(Quaternionf()) - val translation = -camera.pos.toVector3f() - - viewMatrix.identity() - .rotate(rotation) - .translate(translation) - - viewProjectionMatrix.identity().mul(projectionMatrix).mul(viewMatrix) - projectionMatrix.invert(inverseProjectionMatrix) - inverseViewMatrix.identity() - .translate(camera.pos.toVector3f()) - .rotate(camera.rotation) - viewProjectionMatrix.invert(inverseViewProjectionMatrix) + fun setupMatrix(camera: Any?, projectionMatrix: Matrix4fc) { + this.projectionMatrix.set(projectionMatrix) + viewMatrix.setView(camera) + viewProjectionMatrix.set(projectionMatrix).mul(viewMatrix) + inverseViewMatrix.set(viewMatrix).invert() + inverseViewProjectionMatrix.set(viewProjectionMatrix).invert() } - fun assertOnRenderThread() { - RenderSystem.assertOnRenderThread() - } - - fun createShader(type: Int): Int { - assertOnRenderThread() - val shader = glCreateShader(type) - if (shader != 0) { - return shader + private fun Matrix4f.setView(camera: Any?) { + identity() + if (camera !is Camera) { + return } - val error = glGetError() - if (error == GL_INVALID_ENUM) { - error("GL_INVALID_ENUM: shaderType $type is not an accepted value.") - } - val errorName = getErrorName(error) - error("$errorName: shaderType: $type") + rotate(camera.rotation().conjugate(Quaternionf())) + val position = camera.position() + translate(-position.x.toFloat(), -position.y.toFloat(), -position.z.toFloat()) } -} \ No newline at end of file + + fun createShader(shaderType: Int): Int = 0 +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixShaderPipelines.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixShaderPipelines.kt new file mode 100644 index 00000000..96d6b354 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixShaderPipelines.kt @@ -0,0 +1,252 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.client.render + +import com.mojang.blaze3d.pipeline.BindGroupLayout +import com.mojang.blaze3d.pipeline.CompiledRenderPipeline +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.ColorTargetState +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.DefaultVertexFormat +import com.mojang.blaze3d.vertex.VertexFormat +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.core.resource.ClasspathResourceProvider +import heckerpowered.matrix.core.resourceToString +import net.minecraft.client.renderer.BindGroupLayouts +import net.minecraft.client.renderer.RenderPipelines +import net.minecraft.resources.Identifier + +/** + * Vulkan/OpenGL compatible shader pipeline bridge for Matrix post effects. + * + * Minecraft 26.2 compiles shaders through RenderPipeline/GpuDevice instead of + * exposing backend-specific OpenGL program ids. This object only owns pipeline + * descriptions and precompilation; actual post-process drawing must submit these + * pipelines through a RenderPass. + */ +object MatrixShaderPipelines { + data class PostProcessPass( + val fragmentShader: String, + val pipeline: RenderPipeline, + val samplers: List, + val uniformBlocks: List, + ) { + fun supportsSingleInput(): Boolean { + return samplers.isEmpty() || samplers.all(SINGLE_INPUT_SAMPLERS::contains) + } + } + + private val postProcessPipelines = linkedMapOf() + private val compiledPipelines = linkedMapOf() + private var pointSpritePipeline: RenderPipeline? = null + + private val fallbackPostFragments = listOf( + "post/dissolve/dissolve", + "post/dissolve/texture_dissolve", + "post/aura", + "post/blend_screen", + "post/blur/gaussian_blur", + "post/blur/kawase_blur", + "post/blur/radial_blur", + "post/blur/tent", + "post/bloom/bloom_brightness_pass", + "post/bloom/bloom_lower_sampling_pass", + "post/bloom/bloom_super_sampling_pass", + "post/circle", + "post/collapse", + "post/color/colorful", + "post/color_filter", + "post/color_fusion", + "post/edge_highlight", + "post/ghost", + "post/grain/background_grain", + "post/hud/progress_ring", + "post/lower_sampling/hybrid_lod", + "post/lower_sampling/lod", + "post/opacity_blend", + "post/opacity_mask", + "post/refraction/refraction", + "post/sampling/bilinear", + "post/sdf/drop_shadow", + "post/sdf/jump_flooding", + "post/sdf/sdf_eval", + "post/sdf/seed_gen", + "post/shockwave", + "post/the_world", + "post/tone_mapping/aces_filmic", + "post/velocity_map/velocity_map", + "post/the_world", + "post/vortex/vortex", + "post/vortex/inverse_vortex", + ) + + fun postProcessPipeline(fragmentShader: String): RenderPipeline { + return postProcessPass(fragmentShader).pipeline + } + + fun postProcessPass(fragmentShader: String): PostProcessPass { + val normalizedFragment = normalizeShaderId(fragmentShader) + return postProcessPipelines.getOrPut(normalizedFragment) { + val samplers = parseSamplerNames(normalizedFragment) + val uniformBlocks = parseUniformBlockNames(normalizedFragment) + val builder = RenderPipeline.builder() + .withLocation(Matrix.identifier("pipeline/${normalizedFragment.replace('/', '_')}")) + .withVertexShader(Matrix.identifier("core/screenquad_frag_tex_coord")) + .withFragmentShader(Matrix.identifier(normalizedFragment)) + .withVertexFormat(DefaultVertexFormat.EMPTY, VertexFormat.Mode.TRIANGLES) + if (samplers.isNotEmpty()) { + builder.withBindGroupLayout(bindGroupLayout(samplers, uniformBlocks)) + } else if (uniformBlocks.isNotEmpty()) { + builder.withBindGroupLayout(bindGroupLayout(samplers, uniformBlocks)) + } + + PostProcessPass(normalizedFragment, RenderPipelines.register(builder.build()), samplers, uniformBlocks) + } + } + + fun precompileKnownPostPipelines() { + val postFragments = discoverPostFragments() + val compiledPostPipelines = postFragments.count(::precompilePostPipeline) + val compiledPointSprite = precompilePointSpritePipeline() + Matrix.LOGGER.info( + "Matrix shader pipelines precompiled: {}/{} post effects, point sprite={}", + compiledPostPipelines, + postFragments.size, + compiledPointSprite, + ) + } + + fun precompilePostPipeline(fragmentShader: String): Boolean { + val normalizedFragment = normalizeShaderId(fragmentShader) + val pipeline = postProcessPipeline(normalizedFragment) + val device = RenderSystem.tryGetDevice() ?: return false + val result = runCatching { + val compiled = device.precompilePipeline(pipeline) + compiledPipelines[normalizedFragment] = compiled + compiled.isValid + } + result.exceptionOrNull()?.let { + Matrix.LOGGER.warn("Matrix post shader pipeline failed to precompile: {}", normalizedFragment, it) + } + val valid = result.getOrDefault(false) + if (!valid && result.exceptionOrNull() == null) { + Matrix.LOGGER.warn("Matrix post shader pipeline is invalid after precompile: {}", normalizedFragment) + } + return valid + } + + fun isPostPipelineCompiled(fragmentShader: String): Boolean { + return compiledPipelines[normalizeShaderId(fragmentShader)]?.isValid == true + } + + fun isSingleInputPostPipelineCompiled(fragmentShader: String): Boolean { + val normalizedFragment = normalizeShaderId(fragmentShader) + return postProcessPass(normalizedFragment).supportsSingleInput() && isPostPipelineCompiled(normalizedFragment) + } + + fun singleInputSamplerNames(fragmentShader: String): List { + return postProcessPass(fragmentShader).samplers.filter(SINGLE_INPUT_SAMPLERS::contains) + } + + fun pointSpritePipeline(): RenderPipeline { + return pointSpritePipeline ?: RenderPipelines.register( + RenderPipeline.builder() + .withLocation(Matrix.identifier("pipeline/point_sprite")) + .withVertexShader(Matrix.identifier("point_sprite/point_sprite")) + .withFragmentShader(Matrix.identifier("point_sprite/point_sprite")) + .withVertexFormat(DefaultVertexFormat.POSITION, VertexFormat.Mode.POINTS) + .withCull(false) + .withColorTargetState(ColorTargetState(BlendFunction.ADDITIVE)) + .build() + ).also { + pointSpritePipeline = it + } + } + + fun precompilePointSpritePipeline(): Boolean { + val pipeline = pointSpritePipeline() + val device = RenderSystem.tryGetDevice() ?: return false + val result = runCatching { + val compiled = device.precompilePipeline(pipeline) + compiledPipelines["point_sprite/point_sprite"] = compiled + compiled.isValid + } + result.exceptionOrNull()?.let { + Matrix.LOGGER.warn("Matrix point sprite pipeline failed to precompile", it) + } + val valid = result.getOrDefault(false) + if (!valid && result.exceptionOrNull() == null) { + Matrix.LOGGER.warn("Matrix point sprite pipeline is invalid after precompile") + } + return valid + } + + private fun normalizeShaderId(path: String): String { + return path + .removePrefix("/") + .removePrefix("assets/matrix/shaders/") + .removeSuffix(".fsh") + .removeSuffix(".frag") + .removeSuffix(".vsh") + } + + private fun discoverPostFragments(): List { + val discovered = runCatching { + ClasspathResourceProvider.Default + .listRecursively("assets/matrix/shaders/post") + .asSequence() + .filter { it.endsWith(".fsh") || it.endsWith(".frag") } + .map(::normalizeShaderId) + .toList() + }.getOrDefault(emptyList()) + return (fallbackPostFragments + discovered).distinct() + } + + private fun parseSamplerNames(fragmentShader: String): List { + val source = shaderSource(fragmentShader) ?: return emptyList() + return SAMPLER_REGEX.findAll(source) + .map { it.groupValues[1] } + .distinct() + .toList() + } + + private fun parseUniformBlockNames(fragmentShader: String): List { + val source = shaderSource(fragmentShader) ?: return emptyList() + return UNIFORM_BLOCK_REGEX.findAll(source) + .map { it.groupValues[1] } + .distinct() + .toList() + } + + private fun shaderSource(fragmentShader: String): String? { + val normalized = normalizeShaderId(fragmentShader) + return runCatching { resourceToString("/assets/matrix/shaders/$normalized.fsh") } + .recoverCatching { resourceToString("/assets/matrix/shaders/$normalized.frag") } + .getOrNull() + } + + private fun bindGroupLayout(samplers: List, uniformBlocks: List): BindGroupLayout { + val builder = BindGroupLayout.builder() + for (sampler in samplers) { + builder.withSampler(sampler) + } + for (uniformBlock in uniformBlocks) { + builder.withUniform(uniformBlock, com.mojang.blaze3d.shaders.UniformType.UNIFORM_BUFFER) + } + return builder.build() + } + + private val SAMPLER_REGEX = Regex("""uniform\s+sampler\w+\s+([A-Za-z_][A-Za-z0-9_]*)""") + private val UNIFORM_BLOCK_REGEX = Regex("""layout\s*\(\s*std140\s*\)\s*uniform\s+([A-Za-z_][A-Za-z0-9_]*)""") + + private val SINGLE_INPUT_SAMPLERS = setOf( + "InSampler", + "framebuffer", + "colorAttachment", + "hdrScene", + ) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt index f7f9e822..d0618dfc 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt @@ -6,20 +6,12 @@ package heckerpowered.matrix.client.render import net.minecraft.client.gl.SimpleFramebuffer -import org.lwjgl.opengl.GL46.* class MipmapsFramebuffer(width: Int, height: Int, useDepth: Boolean = false, getError: Boolean = true) : SimpleFramebuffer(width, height, useDepth, getError) { - init { - glGenerateMipmap(fbo) - } - var levelOfDetail: Int = 0 set(value) { field = value - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorAttachment, value) - viewportWidth = textureWidth shr value viewportHeight = textureHeight shr value - glViewport(0, 0, viewportWidth, viewportHeight) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/OpenGLExtensions.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/OpenGLExtensions.kt index 33428da6..cbb66214 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/OpenGLExtensions.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/OpenGLExtensions.kt @@ -5,188 +5,15 @@ package heckerpowered.matrix.client.render -import heckerpowered.matrix.client.minecraft -import org.lwjgl.glfw.GLFW.* -import org.lwjgl.opengl.GL -import org.lwjgl.opengl.GL20.glGetActiveUniform -import org.lwjgl.opengl.GL31.glGetActiveUniformBlockiv -import org.lwjgl.opengl.GL31.glGetActiveUniformsiv -import org.lwjgl.opengl.GL46.* -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryUtil - object OpenGLExtensions { - @JvmStatic - fun clearGLError() { - glGetError() - } - - @JvmStatic - fun checkGLError(handler: (Int) -> Unit) { - val error = glGetError() - if (error != GL_NO_ERROR) { - handler(error) - } - } - - @JvmStatic - fun getErrorName(error: Int) = when (error) { - GL_NO_ERROR -> "GL_NO_ERROR" - GL_INVALID_ENUM -> "GL_INVALID_ENUM" - GL_INVALID_VALUE -> "GL_INVALID_VALUE" - GL_INVALID_OPERATION -> "GL_INVALID_OPERATION" - GL_INVALID_FRAMEBUFFER_OPERATION -> "GL_INVALID_FRAMEBUFFER_OPERATION" - GL_OUT_OF_MEMORY -> "GL_OUT_OF_MEMORY" - GL_STACK_UNDERFLOW -> "GL_STACK_UNDERFLOW" - GL_STACK_OVERFLOW -> "GL_STACK_OVERFLOW" - else -> "Unknown error $error" - } - - @JvmStatic - fun getErrorDescription(error: Int) = when (error) { - GL_NO_ERROR -> "No error has been recorded." - GL_INVALID_ENUM -> "An unacceptable value is specified for an enumerated argument. The offering command is ignored and has no other side effect." - GL_INVALID_VALUE -> "A numeric argument is out of range. The offering command is ignored and has no other side effect." - GL_INVALID_OPERATION -> "The specified operation is not allowed in the current state. The offering command is ignored and has no other side effect." - GL_INVALID_FRAMEBUFFER_OPERATION -> "The framebuffer object is not complete. The offering command is ignored and has no side effect." - GL_OUT_OF_MEMORY -> "There is no enough memory left to execute the command. The state of the GL is undefined." - GL_STACK_UNDERFLOW -> "An attempt has been made to perform an operation that would cause an internal stack to underflow." - GL_STACK_OVERFLOW -> "An attempt has been made to perform an operation that would cause an internal stack to overflow." - else -> "Unknown error occurred: ${getErrorName(error)}" - } - - fun fastCheck(name: String) { - checkGLError { error -> - val message = getErrorName(error) - val description = getErrorDescription(error) - println("Error at $name: ($message): $description") - } - } - - fun getFramebufferStatusName(status: Int) = when (status) { - GL_FRAMEBUFFER_COMPLETE -> "GL_FRAMEBUFFER_COMPLETE" - GL_FRAMEBUFFER_UNDEFINED -> "GL_FRAMEBUFFER_UNDEFINED" - GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT -> "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT" - GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT -> "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" - GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER -> "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER" - GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER -> "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER" - GL_FRAMEBUFFER_UNSUPPORTED -> "GL_FRAMEBUFFER_UNSUPPORTED" - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE -> "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE" - GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS -> "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS" - else -> "Unknown framebuffer status $status" - } - - @JvmStatic - fun getFramebufferStatusDescription(status: Int): String = when (status) { - GL_FRAMEBUFFER_COMPLETE -> "The framebuffer is complete." - GL_FRAMEBUFFER_UNDEFINED -> "The framebuffer is the default read or draw framebuffer, but the default framebuffer does not exist." - GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT -> "One or more framebuffer attachment points are framebuffer incomplete." - GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT -> "The framebuffer does not have at least one image attached to it." - GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER -> "The value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point(s) named by GL_DRAW_BUFFERi." - GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER -> "GL_READ_BUFFER is not GL_NONE and the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER." - GL_FRAMEBUFFER_UNSUPPORTED -> "The combination of internal formats of the attached images violates an implementation-dependent set of restrictions." - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE -> "The value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures." - GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS -> "One or more framebuffer attachments are layered while any populated attachment is not, or not all populated color attachments are from textures of the same target." - 0 -> "(An error occurred while checking framebuffer status) " - else -> "Unknown framebuffer status: $status" - } - - @JvmStatic - fun getPackedPixelDataTypeForFormat(format: Int): Int { - return when (format) { - // Use GL_FLOAT for all float-based formats (even half-float internal) - GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F, - GL_RGBA32F, GL_RGB32F, GL_RG32F, GL_R32F, - GL_DEPTH_COMPONENT32F, - -> GL_FLOAT - - // Normalized formats - GL_RGBA8, GL_RGB8, GL_RG8, GL_R8 -> GL_UNSIGNED_BYTE - - // Integer formats - GL_RGBA8UI, GL_RGB8UI, GL_RG8UI, GL_R8UI -> GL_UNSIGNED_BYTE - GL_RGBA16UI, GL_RGB16UI, GL_RG16UI, GL_R16UI -> GL_UNSIGNED_SHORT - GL_RGBA32UI, GL_RGB32UI, GL_RG32UI, GL_R32UI -> GL_UNSIGNED_INT - - // Depth - GL_DEPTH_COMPONENT24 -> GL_UNSIGNED_INT - GL_DEPTH_COMPONENT16 -> GL_UNSIGNED_SHORT - - else -> throw IllegalArgumentException("Unsupported format: 0x${format.toString(16)}") - } - } - - @JvmStatic - fun getBytesPerPixel(format: Int, type: Int): Int { - return when (format) { - GL_RGBA -> when (type) { - GL_UNSIGNED_BYTE -> 4 - GL_UNSIGNED_SHORT -> 8 - else -> throw IllegalArgumentException("Unsupported type for GL_RGBA") - } - - GL_RGB -> when (type) { - GL_UNSIGNED_BYTE -> 3 - GL_UNSIGNED_SHORT -> 6 - else -> throw IllegalArgumentException("Unsupported type for GL_RGB") - } - - GL_RG -> when (type) { - GL_UNSIGNED_BYTE -> 2 - GL_UNSIGNED_SHORT -> 4 - else -> throw IllegalArgumentException("Unsupported type for GL_RG") - } - - GL_RED -> when (type) { - GL_UNSIGNED_BYTE -> 1 - GL_UNSIGNED_SHORT -> 2 - else -> throw IllegalArgumentException("Unsupported type for GL_RED") - } - - else -> throw IllegalArgumentException("Unsupported format: 0x${format.toString(16)}") - } - } - - fun getUniformBlockUniforms(program: Int, uniformBlockIndex: Int): Int { - return glGetActiveUniformBlocki(program, uniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS) - } - - fun getUniformBlockIndices(program: Int, uniformBlockIndex: Int, count: Int): IntArray { - val indices = IntArray(count) - glGetActiveUniformBlockiv(program, uniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices) - return indices - } - - fun getUniformBlockUniformNames(program: Int, count: Int): Array { - val maxLength = glGetProgrami(program, GL_ACTIVE_UNIFORM_MAX_LENGTH) - val length = IntArray(1) - val size = IntArray(1) - val type = IntArray(1) - - MemoryStack.stackPush().use { memoryStack -> - val nameBuffer = memoryStack.malloc(maxLength) - return Array(count) { index -> - glGetActiveUniform(program, index, length, size, type, nameBuffer) - MemoryUtil.memUTF8(nameBuffer, length[0]) - } - } - } - - fun getUniformBlockOffsets(program: Int, uniformBlockIndex: Int, indices: IntArray): IntArray { - val offsets = IntArray(indices.size) - glGetActiveUniformsiv(program, indices, GL_UNIFORM_OFFSET, offsets) - return offsets - } - - fun initGLContext(name: String = "") { - fun createHiddenWindow(): Long { - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE) - return glfwCreateWindow(1, 1, name, 0, minecraft.window.handle) - } - - // glfwCreateWindow must only be called from the main thread. - val window = minecraft.submit(::createHiddenWindow).get() - glfwMakeContextCurrent(window) - GL.createCapabilities() - } -} \ No newline at end of file + @JvmStatic fun clearGLError() = Unit + @JvmStatic fun checkGLError(handler: (Int) -> Unit) = Unit + @JvmStatic fun getErrorName(error: Int): String = "GL_ERROR_$error" + @JvmStatic fun getErrorDescription(error: Int): String = getErrorName(error) + @JvmStatic fun fastCheck(name: String) = Unit + @JvmStatic fun getFramebufferStatusName(status: Int): String = "GL_FRAMEBUFFER_STATUS_$status" + @JvmStatic fun getFramebufferStatusDescription(status: Int): String = getFramebufferStatusName(status) + @JvmStatic fun getPackedPixelDataTypeForFormat(format: Int): Int = 0 + @JvmStatic fun getBytesPerPixel(format: Int, type: Int): Int = 4 + @JvmStatic fun initGLContext(name: String = "") = Unit +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt index 31473a04..d237e208 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt @@ -5,22 +5,19 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager +import com.mojang.blaze3d.pipeline.RenderPipeline import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.FilterMode +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.event.PostProcessCallback -import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.MinecraftClient +import net.minecraft.client.Minecraft import net.minecraft.client.gl.Framebuffer import net.minecraft.client.gl.SimpleFramebuffer -import org.lwjgl.opengl.GL31 -import org.lwjgl.opengl.GL46 +import net.minecraft.client.renderer.RenderPipelines +import java.util.OptionalDouble +import java.util.OptionalInt val framebufferProvider: UniformProvider get() = PostProcessRenderer.framebufferProvider @@ -28,53 +25,16 @@ val framebufferProvider: UniformProvider object PostProcessRenderer { val postProcessShaders = mutableSetOf() - /** - * The source framebuffer to render the post process effects from. - */ - var sourceFramebuffer = minecraft.framebuffer - private var boundFramebuffer = minecraft.framebuffer - - val framebufferProvider = UniformProvider("framebuffer") { pointer -> - GL31.glActiveTexture(GlConst.GL_TEXTURE0) - GL31.glBindTexture(GlConst.GL_TEXTURE_2D, boundFramebuffer.colorAttachment) - RenderSystem.glUniform1i(pointer, 0) + private val minecraftFramebuffer = object : Framebuffer(1, 1, true) { + override val renderTarget + get() = Minecraft.getInstance().gameRenderer.mainRenderTarget() } + var sourceFramebuffer: Framebuffer = minecraftFramebuffer + private var boundFramebuffer: Framebuffer = sourceFramebuffer + val framebufferProvider = UniformProvider("framebuffer") var useDepthAttachment = false - private val depthAttachmentProvider = UniformProvider("depthAttachment") { pointer -> - if (pointer == -1 || !boundFramebuffer.useDepthAttachment || !useDepthAttachment) { - return@UniformProvider - } - - GL31.glActiveTexture(GlConst.GL_TEXTURE0 + 1) - GL31.glBindTexture(GlConst.GL_TEXTURE_2D, boundFramebuffer.depthAttachment) - RenderSystem.glUniform1i(pointer, 1) - } - var levelOfDetail = .0F - private val levelOfDetailProvider = UniformProvider("lod") { pointer -> - if (pointer == -1) { - return@UniformProvider - } - - GL46.glUniform1f(pointer, levelOfDetail) - } - - private val blitShader by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL46.GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/blit/blit.fsh", GL46.GL_FRAGMENT_SHADER), - uniforms = arrayOf(framebufferProvider, depthAttachmentProvider, levelOfDetailProvider) - ) - } - - private val blitNoDepthShader by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL46.GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/blit/blit_no_depth.fsh", GL46.GL_FRAGMENT_SHADER), - uniforms = arrayOf(framebufferProvider, levelOfDetailProvider) - ) - } private val managedFramebuffers = mutableListOf() private val framebuffers = mutableListOf(createFramebuffer(), createFramebuffer()) @@ -98,23 +58,11 @@ object PostProcessRenderer { } private fun createFramebuffer(): Framebuffer { - val framebuffer = SimpleFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, - true, - MinecraftClient.IS_SYSTEM_MAC - ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) - return framebuffer + return SimpleFramebuffer(1, 1, true, false) } fun createManagedFramebuffer(): Framebuffer { - val framebuffer = SimpleFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, - true, - MinecraftClient.IS_SYSTEM_MAC - ) + val framebuffer = SimpleFramebuffer(1, 1, true, false) framebuffer.setClearColor(.0F, .0F, .0F, .0F) managedFramebuffers.add(framebuffer) return framebuffer @@ -126,11 +74,12 @@ object PostProcessRenderer { @JvmStatic fun onResize(width: Int, height: Int) { + minecraftFramebuffer.resize(width, height, false) for (framebuffer in framebuffers) { - framebuffer.resize(width, height, MinecraftClient.IS_SYSTEM_MAC) + framebuffer.resize(width, height, false) } for (framebuffer in managedFramebuffers) { - framebuffer.resize(width, height, MinecraftClient.IS_SYSTEM_MAC) + framebuffer.resize(width, height, false) } } @@ -145,16 +94,12 @@ object PostProcessRenderer { } fun resetFramebuffers() { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot()) { - currentFramebufferIndex = 0 - framebuffers.forEach { it.clear(MinecraftClient.IS_SYSTEM_MAC) } - } + currentFramebufferIndex = 0 + clearFramebuffers() } fun clearFramebuffers() { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot()) { - framebuffers.forEach { it.clear(MinecraftClient.IS_SYSTEM_MAC) } - } + framebuffers.forEach { it.clear(false) } } @JvmStatic @@ -174,58 +119,67 @@ object PostProcessRenderer { @JvmStatic fun renderToMinecraftFramebuffer() { - renderToFramebuffer(minecraft.framebuffer) + syncMinecraftFramebufferSize() + if (postProcessShaders.isEmpty()) { + resetFramebuffers() + } else { + renderToFramebuffer(sourceFramebuffer) + } PostProcessCallback.EVENT.invoker().onPostProcess() } + private fun syncMinecraftFramebufferSize() { + val window = Minecraft.getInstance().window + if (minecraftFramebuffer.textureWidth != window.width || minecraftFramebuffer.textureHeight != window.height) { + minecraftFramebuffer.resize(window.width, window.height, false) + } + } + @JvmStatic fun renderFramebufferToScreen(framebuffer: Framebuffer, disableBlend: Boolean = false) { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - - framebuffer.endWrite() - framebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, disableBlend) - - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) + framebuffer.draw(framebuffer.viewportWidth, framebuffer.viewportHeight, disableBlend) } @JvmStatic fun renderShaderToFramebuffer(shader: BlitProgram, framebuffer: Framebuffer, disableBlend: Boolean = true) { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() + renderShader(shader, boundFramebuffer, framebuffer) + boundFramebuffer = framebuffer + } - framebuffer.beginWrite(true) - if (disableBlend) { - shader.blit() - } else { - shader.enableShader() - BlitProgram.blit() - shader.disableShader() - } - framebuffer.endWrite() + @JvmStatic + fun renderShaderToFramebuffer( + shader: BlitProgram, + sourceFramebuffer: Framebuffer, + framebuffer: Framebuffer, + disableBlend: Boolean = true, + ) { + renderShader(shader, sourceFramebuffer, framebuffer) + boundFramebuffer = framebuffer + } - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) + @JvmStatic + fun renderShaderToFramebuffer( + shader: BlitProgram, + framebuffer: Framebuffer, + textureBindings: Map, + disableBlend: Boolean = true, + ) { + renderShader(shader, framebuffer, textureBindings) + boundFramebuffer = framebuffer } @JvmStatic fun renderShaders(shaders: Collection): Framebuffer { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - resetFramebuffers() - copyFramebuffer(sourceFramebuffer, currentFramebuffer()) - boundFramebuffer = currentFramebuffer() - - // Render post process effects + var inputFramebuffer = sourceFramebuffer for (shader in shaders) { - // Render shader to next framebuffer + val outputFramebuffer = currentFramebuffer() + renderShader(shader, inputFramebuffer, outputFramebuffer) + inputFramebuffer = outputFramebuffer nextFramebuffer() - currentFramebuffer().beginWrite(false) - shader.blit() - - // Bind the rendered framebuffer - boundFramebuffer = currentFramebuffer() } - - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) - return boundFramebuffer + boundFramebuffer = inputFramebuffer + return inputFramebuffer } @JvmStatic @@ -236,23 +190,145 @@ object PostProcessRenderer { @JvmStatic fun copyFramebuffer(from: Framebuffer, to: Framebuffer, disableBlend: Boolean = true, copyDepth: Boolean = false) { - boundFramebuffer = from - val shader = if (copyDepth) blitShader else blitNoDepthShader - renderShaderToFramebuffer(shader, to, disableBlend) + blitFramebuffer(from, to, RenderPipelines.ENTITY_OUTLINE_BLIT, mapOf("InSampler" to from.colorTextureView)) + if (copyDepth) { + copyDepthTexture(from, to) + } + boundFramebuffer = to + } + + @JvmStatic + fun copyDepthFramebuffer(from: Framebuffer, to: Framebuffer) { + copyDepthTexture(from, to) } fun useFramebuffer(framebuffer: Framebuffer, action: () -> Unit) { val previousFramebuffer = sourceFramebuffer + val previousBoundFramebuffer = boundFramebuffer sourceFramebuffer = framebuffer + resetFramebuffers() + copyFramebuffer(sourceFramebuffer, currentFramebuffer()) + nextFramebuffer() + try { + action() + } finally { + sourceFramebuffer = previousFramebuffer + boundFramebuffer = previousBoundFramebuffer + } + } - val previousBoundFramebuffer = GlStateManager.getBoundFramebuffer() - currentFramebuffer().clear(false) - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousBoundFramebuffer) + private fun renderShader(shader: BlitProgram, input: Framebuffer, output: Framebuffer) { + val pass = shader.fragmentResourcePath() + ?.toMatrixFragmentId() + ?.let(::compiledSingleInputPass) - copyFramebuffer(sourceFramebuffer, currentFramebuffer()) - boundFramebuffer = currentFramebuffer() + if (pass == null) { + blitFramebuffer(input, output, RenderPipelines.ENTITY_OUTLINE_BLIT, mapOf("InSampler" to input.colorTextureView)) + return + } + + val textureBindings = pass.samplers.associateWith { input.colorTextureView } + blitFramebuffer(input, output, pass.pipeline, textureBindings, pass) + } + + private fun renderShader(shader: BlitProgram, output: Framebuffer, textureBindings: Map) { + val fragmentShader = shader.fragmentResourcePath()?.toMatrixFragmentId() + val pass = fragmentShader?.let(::compiledPostPass) + + if (pass == null || !pass.samplers.all(textureBindings::containsKey)) { + val fallbackInput = textureBindings.values.firstOrNull() ?: boundFramebuffer + blitFramebuffer(fallbackInput, output, RenderPipelines.ENTITY_OUTLINE_BLIT, mapOf("InSampler" to fallbackInput.colorTextureView)) + return + } + + val firstInput = textureBindings.values.firstOrNull() ?: boundFramebuffer + val textureViews = pass.samplers.associateWith { sampler -> + val framebuffer = textureBindings.getValue(sampler) + if (sampler.equals("depthAttachment", ignoreCase = true)) { + framebuffer.depthTextureView ?: framebuffer.colorTextureView + } else { + framebuffer.colorTextureView + } + } + blitFramebuffer(firstInput, output, pass.pipeline, textureViews, pass) + } + + private fun compiledPostPass(fragmentShader: String): MatrixShaderPipelines.PostProcessPass? { + val pass = MatrixShaderPipelines.postProcessPass(fragmentShader) + if (!MatrixShaderPipelines.isPostPipelineCompiled(fragmentShader)) { + MatrixShaderPipelines.precompilePostPipeline(fragmentShader) + } + return pass.takeIf { MatrixShaderPipelines.isPostPipelineCompiled(fragmentShader) } + } + + private fun compiledSingleInputPass(fragmentShader: String): MatrixShaderPipelines.PostProcessPass? { + val pass = compiledPostPass(fragmentShader) ?: return null + return pass.takeIf { it.supportsSingleInput() } + } + + private fun blitFramebuffer( + input: Framebuffer, + output: Framebuffer, + pipeline: RenderPipeline, + textureBindings: Map, + matrixPass: MatrixShaderPipelines.PostProcessPass? = null, + ) { + val outputTarget = output.renderTarget + val outputColorView = outputTarget.colorTextureView ?: return + val encoder = RenderSystem.getDevice().createCommandEncoder() + val uniformBindings = matrixPass?.let { MatrixPostUniforms.prepare(it, input, output, encoder) } ?: emptyMap() + val depthView = outputTarget.depthTextureView + val renderPass = if (depthView != null) { + encoder.createRenderPass( + { "Matrix framebuffer blit" }, + outputColorView, + OptionalInt.empty(), + depthView, + OptionalDouble.empty(), + ) + } else { + encoder.createRenderPass( + { "Matrix framebuffer blit" }, + outputColorView, + OptionalInt.empty(), + ) + } + + renderPass.use { pass -> + pass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(pass) + val sampler = RenderSystem.getSamplerCache().getClampToEdge(FilterMode.NEAREST) + for ((name, textureView) in textureBindings) { + pass.bindTexture(name, textureView, sampler) + } + for ((name, uniform) in uniformBindings) { + pass.setUniform(name, uniform) + } + pass.draw(0, 3) + } + } + + private fun copyDepthTexture(from: Framebuffer, to: Framebuffer) { + val sourceDepth = from.depthTexture ?: return + val targetDepth = to.depthTexture ?: return + RenderSystem.getDevice().createCommandEncoder().copyTextureToTexture( + sourceDepth, + targetDepth, + 0, + 0, + 0, + 0, + 0, + to.textureWidth.coerceAtMost(from.textureWidth), + to.textureHeight.coerceAtMost(from.textureHeight), + ) + } - action() - sourceFramebuffer = previousFramebuffer + private fun String.toMatrixFragmentId(): String? { + val normalized = replace('\\', '/') + .removePrefix("/assets/matrix/shaders/") + .removeSuffix(".fsh") + .removeSuffix(".frag") + return normalized.takeIf { it.startsWith("post/") } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt index efbb5d56..0c68fd69 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt @@ -5,55 +5,21 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.platform.GlStateManager.Viewport -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import net.minecraft.client.gl.Framebuffer -import net.minecraft.client.texture.NativeImage import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* -import java.io.File +import org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT +import org.lwjgl.opengl.GL11.GL_LINEAR +import org.lwjgl.opengl.GL11.GL_NEAREST +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -fun Framebuffer.blit(target: Framebuffer, mask: Int, filter: Int) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo) - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target.fbo) - glBlitFramebuffer( - 0, 0, textureWidth, textureHeight, - 0, 0, target.textureWidth, target.textureHeight, - mask, filter - ) -} - -private var primaryFramebuffer: Framebuffer? = null -private var secondaryFramebuffer: Framebuffer? = null var colorMultiplier = Vector4f(1.0F, 1.0F, 1.0F, 1.0F) private val colorFusionShader by lazy { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/color_fusion.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("primaryFramebuffer") { pointer -> - val framebuffer = primaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("secondaryFramebuffer") { pointer -> - val framebuffer = secondaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0 + 1) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 1) - }, - UniformProvider("colorMultiplier") { pointer -> - glUniform4f(pointer, colorMultiplier.x, colorMultiplier.y, colorMultiplier.z, colorMultiplier.w) - } - ) ) } @@ -61,66 +27,54 @@ private val blendScreenShader by lazy { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/blend_screen.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("primaryFramebuffer") { pointer -> - val framebuffer = primaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("secondaryFramebuffer") { pointer -> - val framebuffer = secondaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0 + 1) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 1) - } - ) ) } val tentBlurShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/blur/tent.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(UniformProvider("framebuffer") { pointer -> - val framebuffer = primaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - RenderSystem.glUniform1i(pointer, 0) - }) ) -/** - * - */ +fun Framebuffer.blit(target: Framebuffer, mask: Int, filter: Int) { + if ((mask and GL_DEPTH_BUFFER_BIT) != 0) { + PostProcessRenderer.copyDepthFramebuffer(this, target) + } else { + PostProcessRenderer.copyFramebuffer(this, target) + } +} + infix fun Framebuffer.blend(other: Framebuffer) { - primaryFramebuffer = this - secondaryFramebuffer = other - colorFusionShader.blit() + PostProcessRenderer.renderShaderToFramebuffer( + colorFusionShader, + PostProcessRenderer.currentFramebuffer(), + mapOf("primaryFramebuffer" to this, "secondaryFramebuffer" to other), + ) + PostProcessRenderer.nextFramebuffer() } infix fun Framebuffer.blendScreen(other: Framebuffer) { - primaryFramebuffer = this - secondaryFramebuffer = other - blendScreenShader.blit() + PostProcessRenderer.renderShaderToFramebuffer( + blendScreenShader, + PostProcessRenderer.currentFramebuffer(), + mapOf("primaryFramebuffer" to this, "secondaryFramebuffer" to other), + ) + PostProcessRenderer.nextFramebuffer() } infix fun Framebuffer.copyTo(other: Framebuffer) { - blit(other, GL_COLOR_BUFFER_BIT, GL_LINEAR) + PostProcessRenderer.copyFramebuffer(this, other) } infix fun Framebuffer.copyDepthTo(other: Framebuffer) { - blit(other, GL_DEPTH_BUFFER_BIT, GL_LINEAR) + PostProcessRenderer.copyDepthFramebuffer(this, other) } infix fun Framebuffer.linearCopyTo(other: Framebuffer) { - blit(other, GL_COLOR_BUFFER_BIT, GL_LINEAR) + PostProcessRenderer.copyFramebuffer(this, other) } infix fun Framebuffer.nearestCopyTo(other: Framebuffer) { - blit(other, GL_COLOR_BUFFER_BIT, GL_NEAREST) + PostProcessRenderer.copyFramebuffer(this, other) } /** @@ -185,29 +139,6 @@ fun Framebuffer.dump(levelOfDetail: Int = 0, generateMipmap: Boolean = true) { } fun Framebuffer.dump(name: String, levelOfDetail: Int = 0, generateMipmap: Boolean = true) { - RenderSystem.bindTexture(colorAttachment) - - if (generateMipmap) { - glGenerateMipmap(GL_TEXTURE_2D) - } - val width = glGetTexLevelParameteri(GL_TEXTURE_2D, levelOfDetail, GL_TEXTURE_WIDTH) - val height = glGetTexLevelParameteri(GL_TEXTURE_2D, levelOfDetail, GL_TEXTURE_HEIGHT) - - if (width <= 0 || height <= 0) { - OpenGLExtensions.fastCheck("Framebuffer dump: invalid texture size") - return - } - - NativeImage(width, height, false).use { nativeImage -> - nativeImage.loadFromTextureImage(levelOfDetail, false) - nativeImage.mirrorVertically() - - val file = File("screenshots") - file.mkdir() - - val filename = "framebuffer_dump_${name}.png" - nativeImage.writeTo(File(file, filename)) - } } /** @@ -235,14 +166,5 @@ fun Framebuffer.dump(name: String, levelOfDetail: Int = 0, generateMipmap: Boole */ @Deprecated("Use StateIsolation.isolate(FramebufferState(this)) { action() } instead") fun framebufferGuard(action: () -> Unit) { - val previousBindingFramebuffer = glGetInteger(GL_FRAMEBUFFER_BINDING) - val previousViewportX = Viewport.getX() - val previousViewportY = Viewport.getY() - val previousViewportWidth = Viewport.getWidth() - val previousViewportHeight = Viewport.getHeight() - action() - - glBindFramebuffer(GL_FRAMEBUFFER, previousBindingFramebuffer) - GlStateManager._viewport(previousViewportX, previousViewportY, previousViewportWidth, previousViewportHeight) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt index 8ce5a9de..41c96b20 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt @@ -5,138 +5,47 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.event.PostProcessCallback import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.event.PostProcessCallback import heckerpowered.matrix.client.player import heckerpowered.matrix.client.render.effect.SculkCatalystEffectRenderer -import heckerpowered.matrix.client.render.particle.ParticleSystem -import heckerpowered.matrix.client.render.particle.memory.MemoryLayout -import heckerpowered.matrix.client.render.particle.module.particle_render.ParticleSpriteRendererModule -import heckerpowered.matrix.client.render.particle.module.particle_spawn.InitializeParticleModule -import heckerpowered.matrix.client.render.particle.module.particle_spawn.RandomLifetimeModule -import heckerpowered.matrix.client.render.particle.module.particle_spawn.RandomVelocityModule -import heckerpowered.matrix.client.render.particle.module.particle_update.DragModule -import heckerpowered.matrix.client.render.particle.module.particle_update.KillParticleModule -import heckerpowered.matrix.client.render.particle.module.particle_update.ParticleStateModule -import heckerpowered.matrix.client.render.particle.module.particle_update.ScaleSpriteSizeBySpeedModule -import heckerpowered.matrix.client.render.particle.system.ExplosionParticle -import heckerpowered.matrix.client.render.post.BloomEffect import heckerpowered.matrix.client.render.post.CollapseEffectRenderer import heckerpowered.matrix.client.render.post.ShockwaveRenderer -import heckerpowered.matrix.client.render.shader.RadialBlurRenderer.samples -import heckerpowered.matrix.client.render.shader.VortexRenderer -import heckerpowered.matrix.client.render.state.* -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import heckerpowered.matrix.client.render.state.capabilities.DepthTestState import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.DissolveShader import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import heckerpowered.matrix.client.ui.foundation.animation.ColorAnimation import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.common.effect.ModMobEffects.ANGERED_EFFECT import heckerpowered.matrix.common.effect.ModMobEffects.WITHER_ARMOR_EFFECT -import heckerpowered.matrix.common.effect.isBloodPactActive -import heckerpowered.matrix.common.magic.spell.SculkCatalystMagic -import heckerpowered.matrix.core.approximatelyEqual import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents -import net.minecraft.client.MinecraftClient -import net.minecraft.util.math.Vec3d -import org.lwjgl.opengl.GL46.* +import net.minecraft.client.Minecraft +import net.minecraft.core.particles.ParticleTypes +import org.joml.Vector4f +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER import java.time.Duration +import kotlin.math.abs +import kotlin.random.Random +import net.minecraft.world.phys.Vec3 object ScreenEffectRenderer { - private var previousAngryState = false - private var previousWitherArmorState = false - private var previousWitherArmorDuration = 0L + private var previousWitherArmorDuration = 0 + private var initialized = false private val colorAnimation = ColorAnimation( red = SimpleDoubleAnimation(from = 1.0, to = 1.0, initValue = 1.0, duration = Duration.ofMillis(1000)), green = SimpleDoubleAnimation(from = 1.0, to = 1.0, initValue = 1.0, duration = Duration.ofMillis(1000)), - blue = SimpleDoubleAnimation(from = 1.0, to = 1.0, initValue = 1.0, duration = Duration.ofMillis(1000)) + blue = SimpleDoubleAnimation(from = 1.0, to = 1.0, initValue = 1.0, duration = Duration.ofMillis(1000)), ) - private val ghostStrengthAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(1000)) - private val auraAlphaAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(1000)) - - private val auraShader by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/aura.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("entityDepthAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, sceneFramebuffer.depthAttachment) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("entityColorAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 1) - glBindTexture(GlConst.GL_TEXTURE_2D, sceneFramebuffer.colorAttachment) - RenderSystem.glUniform1i(pointer, 1) - }, - UniformProvider("sceneDepthAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 2) - glBindTexture(GlConst.GL_TEXTURE_2D, minecraft.framebuffer.depthAttachment) - glUniform1i(pointer, 2) - }, - UniformProvider("sceneColorAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 3) - glBindTexture(GlConst.GL_TEXTURE_2D, minecraft.framebuffer.colorAttachment) - glUniform1i(pointer, 3) - }, - UniformProvider("noiseColorAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 4) - glBindTexture(GlConst.GL_TEXTURE_2D, DissolveShader.perlinNoiseTextureId) - glUniform1i(pointer, 4) - }, - UniformProvider("time") { pointer -> - val age = minecraft.player?.age?.toFloat() ?: 0F - val deltaTime = minecraft.renderTickCounter.tickDelta - val time = age + deltaTime - glUniform1f(pointer, time / 1000.0F) - }, - UniformProvider("alpha") { pointer -> - glUniform1f(pointer, auraAlphaAnimation.animatedValue.toFloat()) - }, - UniformProvider("auraColor") { pointer -> - val color = colorAnimation - glUniform4f( - pointer, - color.red.animatedValue.toFloat() / color.red.to.toFloat(), - color.red.animatedValue.toFloat() / color.red.to.toFloat(), - color.red.animatedValue.toFloat() / color.red.to.toFloat(), - color.red.animatedValue.toFloat() / color.red.to.toFloat() - ) - } - ) - ) - } - - private val blurRadiusAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(1000)) - - private val edgeThresholdAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(1000)) - val bloomThresholdAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(1000)) + private val edgeThresholdAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(1000)) + val bloomThresholdAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(1000)) private val colorFilterShader by lazy { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/color_filter.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("color") { pointer -> - glUniform4f( - pointer, - colorAnimation.red.animatedValue.toFloat(), - colorAnimation.green.animatedValue.toFloat(), - colorAnimation.blue.animatedValue.toFloat(), - 1.0F - ) - } - ) ) } @@ -144,235 +53,62 @@ object ScreenEffectRenderer { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/edge_highlight.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("edgeThreshold") { pointer -> - glUniform1f(pointer, edgeThresholdAnimation.animatedValue.toFloat()) - }, - UniformProvider("edgeColor") { pointer -> - glUniform4f(pointer, 0.7F, 0.1F, 0.1F, 1.0F) - } - ) - ) - } - - private val radialBlurShader by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/radial_blur.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("strength") { pointer -> - glUniform1f(pointer, ghostStrengthAnimation.animatedValue.toFloat()) - }, - UniformProvider("samples") { pointer -> - glUniform1i(pointer, samples) - } - ) ) } fun onInitialize() { + if (initialized) { + return + } + initialized = true ClientTickEvents.START_CLIENT_TICK.register(::onTick) PostProcessCallback.EVENT.register(::onPostProcess) colorAnimation.red.start() colorAnimation.green.start() colorAnimation.blue.start() - edgeThresholdAnimation.start() - edgeThresholdAnimation.animatedValue = 1.0 - bloomThresholdAnimation.animatedValue = 1.0 - } - - private fun shouldRenderBloom(): Boolean { - return true - return !bloomThresholdAnimation.animatedValue.approximatelyEqual(1.0) || - CollapseEffectRenderer.dissolveFactor.animatedValue != .0 || - ShockwaveRenderer.waveSize.animatedValue != .0 - } - - private fun onPostProcess() { - StateIsolation.isolate( - FramebufferState(minecraft.framebuffer), ViewportState(minecraft.framebuffer), - BlendState(true), BlendFuncSeparateState(GL_ONE, GL_ONE) - ) { - VortexRenderer.render() - } - bloomThresholdAnimation.animatedValue = 1.0 - if (!shouldRenderBloom()) { - return - } - - BloomEffect.brightnessThreshold = bloomThresholdAnimation.animatedValue.toFloat() + 0.1F - BloomEffect.brightnessPassFramebuffer = minecraft.framebuffer - BloomEffect.renderBloom() - - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState(true), BlendFuncSeparateState(GL_ONE, GL_ONE) - ) { - PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.framebuffer, false) - } - - // ToneMapping.exposureLinear = 1.0f - // ToneMapping.exposureEv = 0.0f - // ToneMapping.render(minecraft.framebuffer, toneMapFramebuffer) - // StateIsolation.isolate( - // FramebufferState(minecraft.framebuffer), - // ViewportState(minecraft.framebuffer) - // ) { - // PostProcessRenderer.copyFramebuffer(toneMapFramebuffer, minecraft.framebuffer, false) - // } + bloomThresholdAnimation.start() } - val particleSystem by lazy { - ParticleSystem( - 10000, - particleSpawnModules = arrayOf( - InitializeParticleModule(), - RandomVelocityModule(), - RandomLifetimeModule(), - ), - particleUpdateModules = arrayOf( - KillParticleModule(), - ParticleStateModule(), - DragModule(), - ScaleSpriteSizeBySpeedModule() - ), - particleRenderModules = arrayOf( - ParticleSpriteRendererModule() - ), - MemoryLayout.DEFAULT_LAYOUT - ) + fun beginRenderEntity() { + // Entity post effects are currently driven by the 26.2 post-process and tick paths. } - fun spawnParticleAt(position: Vec3d, count: Int = 1) { - val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState - particleState.x = position.x.toFloat() - particleState.y = position.y.toFloat() - particleState.z = position.z.toFloat() - - val multiplier = 4F - - particleState.colorR = 1.0F * multiplier - particleState.colorG = 0.5F * multiplier - particleState.colorB = 1.0F * multiplier - particleState.colorA = 1.0F - - particleState.spriteSize = 80.0F - particleState.scale = 1F - - index += count - if (index > particleSystem.particleCount) { - index = 0 + fun endRenderEntity() { + if (SculkCatalystEffectRenderer.entity?.isAlive == false) { + SculkCatalystEffectRenderer.entity = null } - particleSystem.spawnPartialParticles(index, count) } - var index: Int = 0 - - fun onTick(minecraftClient: MinecraftClient) { - if (minecraftClient.player == null) { - return - } - if (player.getStatusEffect(ANGERED_EFFECT) == null && previousAngryState) { - onAngeredEffectRemoved() - previousAngryState = false - } else if (player.getStatusEffect(ANGERED_EFFECT) != null && !previousAngryState) { - onAngeredEffectApplied() - previousAngryState = true - } - - val witherArmorStatusEffect = player.getStatusEffect(WITHER_ARMOR_EFFECT) - if (witherArmorStatusEffect == null && previousWitherArmorState) { - previousWitherArmorState = false - } else if (witherArmorStatusEffect != null && !previousWitherArmorState || - (witherArmorStatusEffect?.duration?.toLong() ?: 0L) > previousWitherArmorDuration - ) { - onWitherArmorEffectApplied() - previousWitherArmorState = true - } - previousWitherArmorDuration = witherArmorStatusEffect?.duration?.toLong() ?: 0L - - if (edgeThresholdAnimation.animatedValue >= 1.0) { - PostProcessRenderer.postProcessShaders.remove(edgeHighlightShader) - } - - /** - for (particleSystem in particleSystems) { - val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState - if (minecraft.player != null) { - particleState.x = 0F - particleState.y = 0F - particleState.z = 0F - - val multiplier = 4F - - particleState.colorR = 1.0F * multiplier - particleState.colorG = 0.5F * multiplier - particleState.colorB = 1.0F * multiplier - particleState.colorA = 1.0F - - particleState.spriteSize = 8.0F - particleState.scale = 10F - - particleState.velocityX = 0F - particleState.velocityY = 0F - particleState.velocityZ = 0F - } + fun spawnParticleAt(position: Vec3, count: Int = 1) { + val level = minecraft.level ?: return + repeat(count.coerceAtLeast(0)) { + val velocity = randomVelocity(0.045) + level.addParticle( + ParticleTypes.WITCH, + position.x, + position.y, + position.z, + velocity.x, + velocity.y, + velocity.z, + ) } - **/ - // val count = 10 - - // index += count - // if (index > particleSystem.particleCount) { - // index = 0 - // } - // println("Spawn: ") - // particleSystem.particleStates.retrieve().use { - // it.particles.forEach { particle -> - // println("${particle.x}, ${particle.y}, ${particle.z}, colorRGBA: ${particle.colorR},${particle.colorG},${particle.colorB},${particle.colorA}, velocity: ${particle.velocityX}, ${particle.velocityY}, ${particle.velocityZ}") - // } - // } - // println("Update: ") - // particleSystem.updateParticles() - // particleSystem.particleStates.retrieve().use { - // it.particles.forEach { particle -> - // println("$particle") - // } - // } - // println("===index=$index===") - - // } } fun onWitherArmorEffectApplied() { + val player = player ?: return previousWitherArmorState = true - val witherArmorStatusEffect = player.getStatusEffect(WITHER_ARMOR_EFFECT) - previousWitherArmorDuration = witherArmorStatusEffect?.duration?.toLong() ?: 0L - - PostProcessRenderer.postProcessShaders.add(colorFilterShader) - PostProcessRenderer.postProcessShaders.add(edgeHighlightShader) - PostProcessRenderer.postProcessShaders.add(radialBlurShader) - - ghostStrengthAnimation.from = 5.0 - ghostStrengthAnimation.to = ghostStrengthAnimation.value - ghostStrengthAnimation.duration = Duration.ofMillis(1000) - ghostStrengthAnimation.start() + previousWitherArmorDuration = player.getEffect(WITHER_ARMOR_EFFECT)?.duration ?: 0 colorAnimation.red.from = 2.0 + colorAnimation.red.to = if (previousAngryState) 2.0 else 1.0 colorAnimation.red.duration = Duration.ofMillis(10000) - colorAnimation.red.to = if (previousAngryState) { - 2.0 - } else { - 1.0 - } colorAnimation.red.start() - edgeThresholdAnimation.from = 0.0 - - edgeThresholdAnimation.to = edgeThresholdAnimation.value + edgeThresholdAnimation.from = .0 + edgeThresholdAnimation.to = 1.0 edgeThresholdAnimation.duration = Duration.ofMillis(10000) edgeThresholdAnimation.start() @@ -386,8 +122,7 @@ object ScreenEffectRenderer { CollapseEffectRenderer.dissolveFactor.duration = Duration.ofMillis(1000) CollapseEffectRenderer.dissolveFactor.start() - ShockwaveRenderer.wavePosition = player.pos.toVector3f() - + ShockwaveRenderer.wavePosition = player.position().toVector3f() ShockwaveRenderer.waveRadius.from = .0 ShockwaveRenderer.waveRadius.to = 128.0 ShockwaveRenderer.waveRadius.duration = Duration.ofMillis(1000) @@ -397,30 +132,67 @@ object ScreenEffectRenderer { ShockwaveRenderer.waveSize.to = .0 ShockwaveRenderer.waveSize.duration = Duration.ofMillis(1000) ShockwaveRenderer.waveSize.start() + + applyPostProcessState() } - private fun onAngeredEffectApplied() { - PostProcessRenderer.postProcessShaders.add(colorFilterShader) - PostProcessRenderer.postProcessShaders.add(edgeHighlightShader) - PostProcessRenderer.postProcessShaders.add(radialBlurShader) - // PostProcessRenderer.postProcessShaders.add(ghostShader) + private fun onTick(minecraft: Minecraft) { + val player = minecraft.player ?: run { + previousAngryState = false + previousWitherArmorState = false + resetPostProcessState() + return + } + val angry = player.hasEffect(ANGERED_EFFECT) + if (!angry && previousAngryState) { + onAngeredEffectRemoved() + } else if (angry && !previousAngryState) { + onAngeredEffectApplied() + } + previousAngryState = angry + + val witherArmor = player.getEffect(WITHER_ARMOR_EFFECT) + val witherArmorDuration = witherArmor?.duration ?: 0 + if (witherArmor == null && previousWitherArmorState) { + previousWitherArmorState = false + } else if (witherArmor != null && (!previousWitherArmorState || witherArmorDuration > previousWitherArmorDuration)) { + onWitherArmorEffectApplied() + } + previousWitherArmorDuration = witherArmorDuration + + if (SculkCatalystEffectRenderer.entity != null) { + SculkCatalystEffectRenderer.render() + edgeThresholdAnimation.value = edgeThresholdAnimation.animatedValue.coerceAtMost(0.45) + } + + applyPostProcessState() + } + + private fun onPostProcess() { + if (!CollapseEffectRenderer.dissolveFactor.isAnimating && + CollapseEffectRenderer.dissolveFactor.animatedValue <= 0.001 + ) { + return + } + + val source = PostProcessRenderer.sourceFramebuffer + val output = PostProcessRenderer.currentFramebuffer() + PostProcessRenderer.renderShaderToFramebuffer( + CollapseEffectRenderer.shader, + output, + mapOf("framebuffer" to source, "depthAttachment" to source), + ) + PostProcessRenderer.copyFramebuffer(output, source) + } + + private fun onAngeredEffectApplied() { colorAnimation.red.value = 2.0 colorAnimation.red.duration = Duration.ofMillis(1000) - colorAnimation.green.value = 1.0 colorAnimation.green.duration = Duration.ofMillis(1000) - colorAnimation.blue.value = 1.0 - edgeThresholdAnimation.value = 0.3 - edgeThresholdAnimation.duration = Duration.ofMillis(1000) - blurRadiusAnimation.value = 5.0 - - ghostStrengthAnimation.duration = Duration.ofMillis(1000) - ghostStrengthAnimation.value = 1.0 - - auraAlphaAnimation.value = 1.0 } private fun onAngeredEffectRemoved() { @@ -428,89 +200,57 @@ object ScreenEffectRenderer { colorAnimation.green.value = 1.0 colorAnimation.blue.value = 1.0 edgeThresholdAnimation.value = 1.0 - ghostStrengthAnimation.value = 0.0 - auraAlphaAnimation.value = .0 } - private val sceneFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } - private var previousFramebuffer = -1 - private var useAuraShader = false - private var useBloom = false + private fun applyPostProcessState() { + MatrixPostUniforms.colorFilterColor = Vector4f( + colorAnimation.red.animatedValue.toFloat(), + colorAnimation.green.animatedValue.toFloat(), + colorAnimation.blue.animatedValue.toFloat(), + 1.0F, + ) + MatrixPostUniforms.edgeHighlightThreshold = edgeThresholdAnimation.animatedValue.toFloat() + MatrixPostUniforms.edgeHighlightColor = Vector4f(0.7F, 0.1F, 0.1F, 1.0F) - @JvmStatic - fun beginRenderEntity() { - if (player.isBloodPactActive) { - useBloom = false - } else if (previousAngryState || auraAlphaAnimation.animatedValue != .0) { - useAuraShader = false // Disabled temporarily + if (isColorFilterActive()) { + PostProcessRenderer.postProcessShaders.add(colorFilterShader) + } else { + PostProcessRenderer.postProcessShaders.remove(colorFilterShader) } - if (!useBloom && !useAuraShader) { - return + if (isEdgeHighlightActive()) { + PostProcessRenderer.postProcessShaders.add(edgeHighlightShader) + } else { + PostProcessRenderer.postProcessShaders.remove(edgeHighlightShader) } - - previousFramebuffer = GlStateManager.getBoundFramebuffer() - sceneFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - sceneFramebuffer.beginWrite(false) } - @JvmStatic - fun endRenderEntity() { - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { - val sculkCatalystIsAlreadyActive = SculkCatalystMagic.isSculkCatalystActive(player) - if (!sculkCatalystIsAlreadyActive && CollapseEffectRenderer.dissolveFactor.to != .0) { - CollapseEffectRenderer.dissolveFactor.value = .0 - CollapseEffectRenderer.dissolveFactor.duration = Duration.ofMillis(300) - } - if (CollapseEffectRenderer.dissolveFactor.animatedValue != .0) { - PostProcessRenderer.clearFramebuffers() - - CollapseEffectRenderer.depthAttachment = minecraft.framebuffer.depthAttachment - PostProcessRenderer.renderShaderToFramebuffer(CollapseEffectRenderer.shader, PostProcessRenderer.ping) - PostProcessRenderer.copyFramebuffer(PostProcessRenderer.ping, minecraft.framebuffer, false) - } - if (ShockwaveRenderer.waveRadius.animatedValue != .0) { - PostProcessRenderer.clearFramebuffers() - - ShockwaveRenderer.depthAttachment = minecraft.framebuffer.depthAttachment - PostProcessRenderer.renderShaderToFramebuffer(ShockwaveRenderer.shockwaveShader, PostProcessRenderer.ping) - PostProcessRenderer.copyFramebuffer(PostProcessRenderer.ping, minecraft.framebuffer, false) - } - } - - particleSystem.updateParticles() - ExplosionParticle.particleSystem.updateParticles() - StateIsolation.isolate(DepthTestState(true), BlendState(false)) { - particleSystem.renderParticles() - ExplosionParticle.particleSystem.renderParticles() - } - - SculkCatalystEffectRenderer.render() - - if (!useBloom) { - return - } + private fun resetPostProcessState() { + colorAnimation.red.animatedValue = 1.0 + colorAnimation.green.animatedValue = 1.0 + colorAnimation.blue.animatedValue = 1.0 + edgeThresholdAnimation.animatedValue = 1.0 + applyPostProcessState() + } - BloomEffect.brightnessThreshold = -1F - BloomEffect.brightnessPassFramebuffer = sceneFramebuffer - BloomEffect.renderBloom() + private fun isColorFilterActive(): Boolean { + return colorAnimation.red.isAnimating || + colorAnimation.green.isAnimating || + colorAnimation.blue.isAnimating || + abs(colorAnimation.red.animatedValue - 1.0) > 0.001 || + abs(colorAnimation.green.animatedValue - 1.0) > 0.001 || + abs(colorAnimation.blue.animatedValue - 1.0) > 0.001 + } - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState(true), BlendFuncState(GL_ONE, GL_ONE) - ) { - PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.framebuffer, false) - } + private fun isEdgeHighlightActive(): Boolean { + return edgeThresholdAnimation.isAnimating || edgeThresholdAnimation.animatedValue < 0.999 + } - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState(true), BlendFuncSeparateState(), - ) { - PostProcessRenderer.copyFramebuffer(sceneFramebuffer, minecraft.framebuffer, false) - } - useBloom = false + private fun randomVelocity(scale: Double): Vec3 { + return Vec3( + (Random.nextDouble() - 0.5) * scale, + Random.nextDouble() * scale, + (Random.nextDouble() - 0.5) * scale, + ) } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/TargetGuideRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/TargetGuideRenderer.kt new file mode 100644 index 00000000..eb6f9093 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/TargetGuideRenderer.kt @@ -0,0 +1,116 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.client.render + +import com.mojang.blaze3d.vertex.PoseStack +import com.mojang.blaze3d.vertex.VertexConsumer +import heckerpowered.matrix.client.MatrixHud +import heckerpowered.matrix.core.getLerpedPos +import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderContext +import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderEvents +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.rendertype.RenderTypes +import net.minecraft.util.ARGB +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.phys.Vec3 +import org.joml.Vector3f +import kotlin.math.sqrt + +object TargetGuideRenderer { + private const val LINE_WIDTH = 1.0F + private val selectedTargetColor = ARGB.color(255, 25, 255, 25) + private val candidateTargetColor = ARGB.color(255, 255, 25, 25) + + @JvmStatic + fun onInitialize() { + LevelRenderEvents.COLLECT_SUBMITS.register(::collectSubmits) + } + + private fun collectSubmits(context: LevelRenderContext) { + if (!MatrixHud.shouldRenderHud()) { + return + } + + val minecraft = Minecraft.getInstance() + val player = minecraft.player ?: return + val targets = MatrixHud.targetGuideChain() + if (targets.isEmpty()) { + return + } + + val tickDelta = minecraft.deltaTracker.getGameTimeDeltaPartialTick(false) + val lines = buildTargetLines(player, targets, tickDelta) + if (lines.isEmpty()) { + return + } + + val cameraPosition = context.levelState().cameraRenderState.pos + val poseStack = PoseStack() + poseStack.translate(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z) + + context.submitNodeCollector().submitCustomGeometry(poseStack, RenderTypes.linesTranslucent()) { pose, vertexConsumer -> + lines.forEach { line -> + renderLine(pose, vertexConsumer, line) + } + } + } + + private fun buildTargetLines( + player: LivingEntity, + targets: List, + tickDelta: Float, + ): List { + val result = mutableListOf() + var from = player.guidePosition(tickDelta) + val selectedTarget = MatrixHud.targetedEntity + + for (target in targets) { + val to = target.guidePosition(tickDelta) + val color = if (target === selectedTarget) selectedTargetColor else candidateTargetColor + result += TargetLine(from, to, color) + from = to + } + + return result + } + + private fun renderLine( + pose: PoseStack.Pose, + vertexConsumer: VertexConsumer, + line: TargetLine, + ) { + val normal = line.normal() ?: return + vertexConsumer.addVertex(pose, line.from.x.toFloat(), line.from.y.toFloat(), line.from.z.toFloat()) + .setColor(line.color) + .setNormal(pose, normal) + .setLineWidth(LINE_WIDTH) + vertexConsumer.addVertex(pose, line.to.x.toFloat(), line.to.y.toFloat(), line.to.z.toFloat()) + .setColor(line.color) + .setNormal(pose, normal) + .setLineWidth(LINE_WIDTH) + } + + private fun LivingEntity.guidePosition(tickDelta: Float): Vec3 { + return getLerpedPos(tickDelta).add(.0, boundingBox.ysize * 0.5, .0) + } + + private data class TargetLine( + val from: Vec3, + val to: Vec3, + val color: Int, + ) { + fun normal(): Vector3f? { + val x = (to.x - from.x).toFloat() + val y = (to.y - from.y).toFloat() + val z = (to.z - from.z).toFloat() + val length = sqrt(x * x + y * y + z * z) + if (length <= 0.0001F) { + return null + } + return Vector3f(x / length, y / length, z / length) + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt index 278cf7e0..d0a303fc 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt @@ -6,56 +6,66 @@ package heckerpowered.matrix.client.render.effect import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.render.shader.VolumeDistortion -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState +import heckerpowered.matrix.client.render.post.ShockwaveRenderer import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import net.minecraft.entity.LivingEntity +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.world.entity.LivingEntity +import java.time.Duration object SculkCatalystEffectRenderer { var entity: LivingEntity? = null set(value) { if (value == null) { - volumeRadius.value = 0.0 - } else if (value != field) { + volumeRadius.value = .0 + } else if (value !== field) { volumeRadius.from = .0 volumeRadius.to = 16.0 + volumeRadius.duration = Duration.ofMillis(300) volumeRadius.start() - emissiveStrength.from = 0.0 + emissiveStrength.from = .0 emissiveStrength.to = 4.0 + emissiveStrength.duration = Duration.ofMillis(300) emissiveStrength.start() + + ShockwaveRenderer.wavePosition = value.position().toVector3f() + ShockwaveRenderer.waveRadius.from = .0 + ShockwaveRenderer.waveRadius.to = 16.0 + ShockwaveRenderer.waveRadius.duration = Duration.ofMillis(500) + ShockwaveRenderer.waveRadius.start() + + ShockwaveRenderer.waveSize.from = 0.5 + ShockwaveRenderer.waveSize.to = .0 + ShockwaveRenderer.waveSize.duration = Duration.ofMillis(500) + ShockwaveRenderer.waveSize.start() } field = value } + val volumeRadius = SimpleDoubleAnimation() val emissiveStrength = SimpleDoubleAnimation() fun render() { - val entity = this.entity ?: return + val entity = entity ?: return if (!entity.isAlive) { this.entity = null return } - VolumeDistortion.grayscaleIntensity = 1.0F - VolumeDistortion.depthAttachment = minecraft.framebuffer.depthAttachment - VolumeDistortion.sceneColorTexture = minecraft.framebuffer.colorAttachment - - VolumeDistortion.volumeRadius = volumeRadius.animatedValue.toFloat() - VolumeDistortion.emissiveStrength = emissiveStrength.animatedValue.toFloat() - - val tickDelta = minecraft.renderTickCounter.getTickDelta(false) - VolumeDistortion.volumePosition = entity.getLerpedPos(tickDelta).toVector3f() - - StateIsolation.isolate( - FramebufferState(minecraft.framebuffer), ViewportState(minecraft.framebuffer), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { - VolumeDistortion.Shader.blit() + if (entity.tickCount % 2 != 0) { + return } + + val level = minecraft.level ?: return + val position = entity.position().add(.0, entity.boundingBox.ysize * 0.5, .0) + level.addParticle( + ParticleTypes.WITCH, + position.x, + position.y, + position.z, + .0, + 0.03, + .0, + ) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt index 024c4f21..71bfff60 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt @@ -8,18 +8,13 @@ package heckerpowered.matrix.client.render.entity import heckerpowered.matrix.common.entity.DevEntity import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.client.render.entity.MobEntityRenderer -import net.minecraft.client.render.entity.model.EntityModelLayers -import net.minecraft.client.render.entity.model.PlayerEntityModel -import net.minecraft.client.util.DefaultSkinHelper -import net.minecraft.util.Identifier +import net.minecraft.client.renderer.entity.EntityRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.EntityRenderState @Environment(EnvType.CLIENT) -class DevEntityRenderer(context: EntityRendererFactory.Context) : MobEntityRenderer>( - context, PlayerEntityModel(context.getPart(EntityModelLayers.PLAYER), false), 0.5F -) { - override fun getTexture(entity: DevEntity): Identifier { - return DefaultSkinHelper.getTexture() +class DevEntityRenderer(context: EntityRendererProvider.Context) : EntityRenderer(context) { + override fun createRenderState(): EntityRenderState { + return EntityRenderState() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt index 816dea80..a10860a3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt @@ -7,18 +7,19 @@ package heckerpowered.matrix.client.render.entity import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.Frustum -import net.minecraft.client.render.entity.EntityRenderer -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.entity.Entity -import net.minecraft.screen.PlayerScreenHandler -import net.minecraft.util.Identifier +import net.minecraft.client.renderer.culling.Frustum +import net.minecraft.client.renderer.entity.EntityRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.EntityRenderState +import net.minecraft.world.entity.Entity @Environment(EnvType.CLIENT) -class EmptyRenderer(context: EntityRendererFactory.Context) : EntityRenderer(context) { - override fun shouldRender(entity: Entity, frustum: Frustum, x: Double, y: Double, z: Double): Boolean { +class EmptyRenderer(context: EntityRendererProvider.Context) : EntityRenderer(context) { + override fun shouldRender(entity: T, frustum: Frustum, x: Double, y: Double, z: Double): Boolean { return false } - override fun getTexture(entity: Entity): Identifier = PlayerScreenHandler.BLOCK_ATLAS_TEXTURE -} \ No newline at end of file + override fun createRenderState(): EntityRenderState { + return EntityRenderState() + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt index 2b183a21..44d8b2af 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt @@ -6,33 +6,31 @@ package heckerpowered.matrix.client.render.entity import heckerpowered.matrix.client.render.ScreenEffectRenderer -import heckerpowered.matrix.client.render.ScreenEffectRenderer.particleSystem -import heckerpowered.matrix.client.render.particle.module.particle_spawn.InitializeParticleModule import heckerpowered.matrix.common.entity.FinderArrowEntity +import heckerpowered.matrix.core.getLerpedPos import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.client.render.entity.ProjectileEntityRenderer -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.util.Identifier +import net.minecraft.client.renderer.entity.ArrowRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.ArrowRenderState +import net.minecraft.resources.Identifier @Environment(EnvType.CLIENT) -class FinderArrowEntityRenderer(context: EntityRendererFactory.Context) : ProjectileEntityRenderer(context) { - override fun getTexture(spectralArrowEntity: FinderArrowEntity): Identifier { +class FinderArrowEntityRenderer(context: EntityRendererProvider.Context) : ArrowRenderer(context) { + override fun getTextureLocation(state: ArrowRenderState): Identifier { return TEXTURE } - override fun render(persistentProjectileEntity: FinderArrowEntity, f: Float, g: Float, matrixStack: MatrixStack?, vertexConsumerProvider: VertexConsumerProvider?, i: Int) { - val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState - - particleState.age = 0F - ScreenEffectRenderer.spawnParticleAt(persistentProjectileEntity.getLerpedPos(g), 10) + override fun createRenderState(): ArrowRenderState { + return ArrowRenderState() + } - super.render(persistentProjectileEntity, f, g, matrixStack, vertexConsumerProvider, i) + override fun extractRenderState(entity: FinderArrowEntity, state: ArrowRenderState, tickDelta: Float) { + super.extractRenderState(entity, state, tickDelta) + ScreenEffectRenderer.spawnParticleAt(entity.getLerpedPos(tickDelta), 10) } companion object { - val TEXTURE: Identifier = Identifier.ofVanilla("textures/entity/projectiles/spectral_arrow.png") + val TEXTURE: Identifier = Identifier.withDefaultNamespace("textures/entity/projectiles/spectral_arrow.png") } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt index 3ec1acfb..cfaf525e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt @@ -5,119 +5,25 @@ package heckerpowered.matrix.client.render.entity -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.common.entity.MagicLightningBolt import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.VertexConsumer -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.entity.EntityRenderer -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.screen.PlayerScreenHandler -import net.minecraft.util.Identifier -import net.minecraft.util.math.random.Random -import org.joml.Matrix4f +import net.minecraft.client.renderer.entity.EntityRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.LightningBoltRenderState @Environment(EnvType.CLIENT) -class MagicLightningEntityRenderer(context: EntityRendererFactory.Context) : EntityRenderer(context) { - override fun render(lightningEntity: MagicLightningBolt, f: Float, g: Float, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, i: Int) { - val multiplier = 5.825f - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) - RenderSystem.disableBlend() - val fs = FloatArray(8) - val gs = FloatArray(8) - var h = 0.0f - var j = 0.0f - val random = Random.create(lightningEntity.seed) - - for (k in 7 downTo 0) { - fs[k] = h - gs[k] = j - h += (random.nextInt(11) - 5).toFloat() - j += (random.nextInt(11) - 5).toFloat() - } - - val vertexConsumer = vertexConsumerProvider.getBuffer(RenderLayer.getLightning()) - val matrix4f = matrixStack.peek().positionMatrix - - for (l in 0..3) { - val random2 = Random.create(lightningEntity.seed) - - for (m in 0..2) { - var n = 7 - var o = 0 - if (m > 0) { - n = 7 - m - } - - if (m > 0) { - o = n - 2 - } - - var p = fs[n] - h - var q = gs[n] - j - - for (r in n downTo o) { - val s = p - val t = q - if (m == 0) { - p += (random2.nextInt(11) - 5).toFloat() - q += (random2.nextInt(11) - 5).toFloat() - } else { - p += (random2.nextInt(31) - 15).toFloat() - q += (random2.nextInt(31) - 15).toFloat() - } - - var y = 0.1f + l.toFloat() * 0.2f - if (m == 0) { - y *= r.toFloat() * 0.1f + 1.0f - } - - var z = 0.1f + l.toFloat() * 0.2f - if (m == 0) { - z *= (r.toFloat() - 1.0f) * 0.1f + 1.0f - } - - val color = lightningEntity.lightningType.color - val red = color.red.toFloat() / 255F - val green = color.green.toFloat() / 255F - val blue = color.blue.toFloat() / 255F - - drawBranch(matrix4f, vertexConsumer, p, q, r, s, t, red, green, blue, y, z, shiftEast1 = false, shiftSouth1 = false, shiftEast2 = true, shiftSouth2 = false) - drawBranch(matrix4f, vertexConsumer, p, q, r, s, t, red, green, blue, y, z, shiftEast1 = true, shiftSouth1 = false, shiftEast2 = true, shiftSouth2 = true) - drawBranch(matrix4f, vertexConsumer, p, q, r, s, t, red, green, blue, y, z, shiftEast1 = true, shiftSouth1 = true, shiftEast2 = false, shiftSouth2 = true) - drawBranch(matrix4f, vertexConsumer, p, q, r, s, t, red, green, blue, y, z, shiftEast1 = false, shiftSouth1 = true, shiftEast2 = false, shiftSouth2 = false) - } - } - } - // RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) +class MagicLightningEntityRenderer(context: EntityRendererProvider.Context) : EntityRenderer(context) { + override fun createRenderState(): LightningBoltRenderState { + return LightningBoltRenderState() } - private fun drawBranch( - matrix: Matrix4f, - buffer: VertexConsumer, - x1: Float, - z1: Float, - y: Int, - x2: Float, - z2: Float, - red: Float, - green: Float, - blue: Float, - offset2: Float, - offset1: Float, - shiftEast1: Boolean, - shiftSouth1: Boolean, - shiftEast2: Boolean, - shiftSouth2: Boolean, - ) { - buffer.vertex(matrix, x1 + (if (shiftEast1) offset1 else -offset1), (y * 16).toFloat(), z1 + (if (shiftSouth1) offset1 else -offset1)).color(red, green, blue, 0.3f) - buffer.vertex(matrix, x2 + (if (shiftEast1) offset2 else -offset2), ((y + 1) * 16).toFloat(), z2 + (if (shiftSouth1) offset2 else -offset2)).color(red, green, blue, 0.3f) - buffer.vertex(matrix, x2 + (if (shiftEast2) offset2 else -offset2), ((y + 1) * 16).toFloat(), z2 + (if (shiftSouth2) offset2 else -offset2)).color(red, green, blue, 0.3f) - buffer.vertex(matrix, x1 + (if (shiftEast2) offset1 else -offset1), (y * 16).toFloat(), z1 + (if (shiftSouth2) offset1 else -offset1)).color(red, green, blue, 0.3f) + override fun extractRenderState(entity: MagicLightningBolt, state: LightningBoltRenderState, tickDelta: Float) { + super.extractRenderState(entity, state, tickDelta) + state.seed = entity.seed } - override fun getTexture(entity: MagicLightningBolt): Identifier = PlayerScreenHandler.BLOCK_ATLAS_TEXTURE -} \ No newline at end of file + override fun affectedByCulling(entity: MagicLightningBolt): Boolean { + return false + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt index fd19e54b..28e48082 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt @@ -5,44 +5,4 @@ package heckerpowered.matrix.client.render.item -import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry.DynamicItemRenderer -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.model.json.ModelTransformationMode -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.item.ItemStack - -object VortexItemRenderer : DynamicItemRenderer { - override fun render(itemStack: ItemStack, modelTransformationMode: ModelTransformationMode, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, light: Int, overlay: Int) { - // matrixStack.push() -// - // val model = minecraft.itemRenderer.getModel(ItemStack(Items.ITEM_FRAME), minecraft.world, minecraft.player, 0) -// - // // matrixStack.scale(0.5f, 0.5f, 0.5f) - // // model.transformation.getTransformation(modelTransformationMode).apply(false, matrixStack) - // // matrixStack.translate(0.5f, 0.5f, 0.5f) -// - // val matrices = MatrixStack() - // val matrix = matrices.peek().positionMatrix -// - // val builder = Tessellator.getInstance() - // val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) -// - // buffer.vertex(matrix, -1F, -1F, 0F).texture(0F, 0F) - // buffer.vertex(matrix, 1F, -1F, 0F).texture(1F, 0F) - // buffer.vertex(matrix, 1F, 1F, 0F).texture(1F, 1F) - // buffer.vertex(matrix, -1F, 1F, 0F).texture(0F, 1F) -// - // buffer.vertex(matrix, -1F, 1F, 0F).texture(0F, 1F) - // buffer.vertex(matrix, 1F, 1F, 0F).texture(1F, 1F) - // buffer.vertex(matrix, 1F, -1F, 0F).texture(1F, 0F) - // buffer.vertex(matrix, -1F, -1F, 0F).texture(0F, 0F) -// - // RenderSystem.disableBlend() - // RenderSystem.disableDepthTest() - // VortexRenderer.vortexShader.enableShader() - // BufferRenderer.draw(buffer.end()) - // VortexRenderer.vortexShader.disableShader() -// - // matrixStack.pop() - } -} \ No newline at end of file +object VortexItemRenderer diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/system/ExplosionParticle.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/system/ExplosionParticle.kt index 4ea67605..993521dc 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/system/ExplosionParticle.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/system/ExplosionParticle.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.client.render.particle.system +import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.particle.ParticleSystem import heckerpowered.matrix.client.render.particle.memory.MemoryLayout import heckerpowered.matrix.client.render.particle.module.particle_render.ParticleSpriteRendererModule @@ -15,8 +16,10 @@ import heckerpowered.matrix.client.render.particle.module.particle_update.DragMo import heckerpowered.matrix.client.render.particle.module.particle_update.KillParticleModule import heckerpowered.matrix.client.render.particle.module.particle_update.ParticleStateModule import heckerpowered.matrix.client.render.particle.module.particle_update.ScaleSpriteSizeBySpeedModule -import net.minecraft.util.math.Vec3d +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.world.phys.Vec3 import org.joml.Vector3f +import kotlin.random.Random object ExplosionParticle { val randomVelocityModule = RandomVelocityModule() @@ -46,7 +49,9 @@ object ExplosionParticle { ) } - fun spawnParticleAt(position: Vec3d) { + fun spawnParticleAt(position: Vec3) { + spawnVanillaFallback(position) + val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState particleState.x = position.x.toFloat() particleState.y = position.y.toFloat() @@ -64,4 +69,24 @@ object ExplosionParticle { particleSystem.spawnParticles() } -} \ No newline at end of file + + private fun spawnVanillaFallback(position: Vec3) { + val level = minecraft.level ?: return + repeat(80) { + val velocity = Vec3( + (Random.nextDouble() - 0.5) * 0.7, + Random.nextDouble() * 0.7, + (Random.nextDouble() - 0.5) * 0.7, + ) + level.addParticle( + ParticleTypes.END_ROD, + position.x, + position.y, + position.z, + velocity.x, + velocity.y, + velocity.z, + ) + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt index e755060f..59540f23 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt @@ -5,173 +5,38 @@ package heckerpowered.matrix.client.render.post -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.event.InitAttachmentCallback -import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.render.recommendMipLevel -import heckerpowered.matrix.client.render.shader.TentShader -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState +import heckerpowered.matrix.client.render.tentBlurShader import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider -import heckerpowered.matrix.core.FramebufferExtension.Companion.allocateMipmaps -import heckerpowered.matrix.core.FramebufferExtension.Companion.beginReadLod -import heckerpowered.matrix.core.FramebufferExtension.Companion.beginWriteLod import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* -import org.slf4j.MarkerFactory +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER object BloomEffect { - private val MARKER = MarkerFactory.getMarker("BLOOM_RENDERER") - - private val brightFramebuffer = PostProcessRenderer.createManagedFramebuffer() + var brightnessThreshold = 1.0F + var bloomIntensity = 1.0F + var brightnessPassFramebuffer: Framebuffer = PostProcessRenderer.sourceFramebuffer + private val brightFramebuffer: Framebuffer = PostProcessRenderer.createManagedFramebuffer() val bloomDownFramebuffer: Framebuffer = PostProcessRenderer.createManagedFramebuffer() val bloomUpFramebuffer: Framebuffer = PostProcessRenderer.createManagedFramebuffer() - init { - InitAttachmentCallback.EVENT.register(::onInitAttachment) - - bloomDownFramebuffer.resize(bloomDownFramebuffer.textureWidth, bloomDownFramebuffer.textureHeight, true) - bloomUpFramebuffer.resize(bloomDownFramebuffer.textureWidth, bloomDownFramebuffer.textureHeight, true) - } - - private fun onInitAttachment(framebuffer: Framebuffer) { - if (framebuffer != bloomDownFramebuffer && framebuffer != bloomUpFramebuffer) { - return - } - - framebuffer.allocateMipmaps = true - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - } - - var brightnessPassFramebuffer: Framebuffer = minecraft.framebuffer - var brightnessThreshold = 0F - var bloomIntensity = 1.0F - private val brightnessShader by lazy { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - val framebuffer = brightnessPassFramebuffer - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("threshold") { pointer -> - glUniform1f(pointer, brightnessThreshold) - }, - UniformProvider("intensity") { pointer -> - glUniform1f(pointer, bloomIntensity) - } - ) ) } - private fun clearBloomPasses(mipLevel: Int) { - brightFramebuffer.clear(true) - - for (i in 0..() private val upScalingFramebuffers = mutableMapOf() - fun getDownScalingFramebuffer(scaling: Double): ScalingFramebuffer { - return downScalingFramebuffers.computeIfAbsent(scaling) { - val framebuffer = ScalingFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, - true, - MinecraftClient.IS_SYSTEM_MAC, - scaling - ) + var levelOfDetail = .0F + + val bilinearSample by lazy { + BlitProgram( + ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), + ResourceShader("/assets/matrix/shaders/post/sampling/bilinear.fsh", GL_FRAGMENT_SHADER), + ) + } + + val textureLod by lazy { + BlitProgram( + ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), + ResourceShader("/assets/matrix/shaders/post/lower_sampling/lod.fsh", GL_FRAGMENT_SHADER), + ) + } + + fun createManagedScalingFramebuffer(scaling: Double): Framebuffer { + return ScalingFramebuffer(scaling, framebufferWidth(), framebufferHeight(), true, false).also { framebuffer -> framebuffer.setClearColor(.0F, .0F, .0F, .0F) PostProcessRenderer.manageFramebuffer(framebuffer) - framebuffer } } - fun getUpScalingFramebuffer(scaling: Double): ScalingFramebuffer { - return upScalingFramebuffers.computeIfAbsent(scaling) { - val framebuffer = ScalingFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, - true, - MinecraftClient.IS_SYSTEM_MAC, - scaling - ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) - PostProcessRenderer.manageFramebuffer(framebuffer) - framebuffer + fun getDownScalingFramebuffer(scaling: Double): Framebuffer { + return downScalingFramebuffers.getOrPut(scaling) { + createManagedScalingFramebuffer(scaling) as ScalingFramebuffer } } - fun createManagedScalingFramebuffer(scaling: Double): ScalingFramebuffer { - val framebuffer = ScalingFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, - true, - MinecraftClient.IS_SYSTEM_MAC, - scaling - ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) - PostProcessRenderer.manageFramebuffer(framebuffer) - return framebuffer + fun getUpScalingFramebuffer(scaling: Double): Framebuffer { + return upScalingFramebuffers.getOrPut(scaling) { + createManagedScalingFramebuffer(scaling) as ScalingFramebuffer + } } fun clearAll() { @@ -72,71 +57,15 @@ object ScaleSampling { upScalingFramebuffers.values.forEach { it.clear(false) } } - val framebuffer = PostProcessRenderer.createManagedFramebuffer() - - var levelOfDetail = 0F - - private var sourceFramebuffer: Framebuffer? = null - private var targetFramebuffer: Framebuffer? = null - - private val sourceFramebufferProvider = UniformProvider("framebuffer") { pointer -> - val sourceFramebuffer = sourceFramebuffer ?: return@UniformProvider - - GL31.glActiveTexture(GlConst.GL_TEXTURE0) - GL31.glBindTexture(GlConst.GL_TEXTURE_2D, sourceFramebuffer.colorAttachment) - - RenderSystem.glUniform1i(pointer, 0) - } - - private val sourceResolutionProvider = UniformProvider("sourceResolution") { pointer -> - val framebuffer = sourceFramebuffer ?: return@UniformProvider - - GL31.glUniform2f(pointer, framebuffer.textureWidth.toFloat(), framebuffer.textureHeight.toFloat()) - } - - private val targetResolutionProvider = UniformProvider("targetResolution") { pointer -> - val framebuffer = targetFramebuffer ?: return@UniformProvider - - GL31.glUniform2f(pointer, framebuffer.textureWidth.toFloat(), framebuffer.textureHeight.toFloat()) - } - - // Bi-linear sampling method - val bilinearSample by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/sampling/bilinear.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(sourceFramebufferProvider, sourceResolutionProvider, targetResolutionProvider) - ) + fun sample(sourceFramebuffer: Framebuffer, targetFramebuffer: Framebuffer, sampler: BlitProgram) { + PostProcessRenderer.renderShaderToFramebuffer(sampler, sourceFramebuffer, targetFramebuffer) } - val textureLod by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/lower_sampling/lod.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - sourceFramebufferProvider, - UniformProvider("levelOfDetail") { pointer -> - GL31.glUniform1f(pointer, levelOfDetail) - } - ) - ) + private fun framebufferWidth(): Int { + return Minecraft.getInstance().gameRenderer.mainRenderTarget().width.coerceAtLeast(1) } - fun sample(sourceFramebuffer: Framebuffer, targetFramebuffer: Framebuffer, sampler: BlitProgram) { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - val previousViewportX = Viewport.getX() - val previousViewportY = Viewport.getY() - val previousViewportWidth = Viewport.getWidth() - val previousViewportHeight = Viewport.getHeight() - - this.sourceFramebuffer = sourceFramebuffer - this.targetFramebuffer = targetFramebuffer - - targetFramebuffer.beginWrite(true) - sampler.blit() - targetFramebuffer.endWrite() - - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) - GlStateManager._viewport(previousViewportX, previousViewportY, previousViewportWidth, previousViewportHeight) + private fun framebufferHeight(): Int { + return Minecraft.getInstance().gameRenderer.mainRenderTarget().height.coerceAtLeast(1) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt index 70f049f5..c7e908a3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt @@ -5,30 +5,21 @@ package heckerpowered.matrix.client.render.post -import heckerpowered.matrix.core.approximatelyEqual -import net.minecraft.client.MinecraftClient import net.minecraft.client.gl.SimpleFramebuffer -import kotlin.math.floor - -class ScalingFramebuffer(width: Int, height: Int, useDepth: Boolean, getError: Boolean = MinecraftClient.IS_SYSTEM_MAC, private val resolutionScaling: Double) : SimpleFramebuffer(width, height, useDepth, getError) { - val actualWidth - get() = floor(textureWidth * resolutionScaling).toInt() - - val actualHeight - get() = floor(textureHeight * resolutionScaling).toInt() - - init { - resize(width, height, getError) - } +import kotlin.math.roundToInt +class ScalingFramebuffer( + private val scaling: Double, + width: Int = 1, + height: Int = 1, + useDepth: Boolean = false, + getError: Boolean = false, +) : SimpleFramebuffer(scaledSize(width, scaling), scaledSize(height, scaling), useDepth, getError) { override fun resize(width: Int, height: Int, getError: Boolean) { - if (resolutionScaling.approximatelyEqual(.0)) { - super.resize(width, height, getError) - return - } - - val scaledWidth = floor(width * resolutionScaling).toInt().coerceAtLeast(1) - val scaledHeight = floor(height * resolutionScaling).toInt().coerceAtLeast(1) - super.resize(scaledWidth, scaledHeight, getError) + super.resize(scaledSize(width, scaling), scaledSize(height, scaling), getError) } -} \ No newline at end of file +} + +private fun scaledSize(size: Int, scaling: Double): Int { + return (size * scaling).roundToInt().coerceAtLeast(1) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt index 7aeb3b15..bbc31430 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt @@ -5,16 +5,18 @@ package heckerpowered.matrix.client.render.post -import heckerpowered.matrix.client.shader.* +import heckerpowered.matrix.client.event.PostProcessCallback +import heckerpowered.matrix.client.render.PostProcessRenderer +import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.shader.ResourceShader import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.core.times import org.joml.Vector3f import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER object ShockwaveRenderer { - var depthAttachment: Int = -1 - var wavePosition: Vector3f = Vector3f() var waveColor = Vector4f(0.1F, 0.5F, 1.0F, 1.0F) * 4.0F var waveRadius = SimpleDoubleAnimation() @@ -23,26 +25,30 @@ object ShockwaveRenderer { val shockwaveShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/shockwave.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("depthAttachment") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, depthAttachment) - glUniform1i(pointer, 0) - }, - inverseProjectionMatrixProvider, - inverseViewMatrixProvider, - UniformProvider("wavePosition") { pointer -> - glUniform3f(pointer, wavePosition.x, wavePosition.y, wavePosition.z) - }, - UniformProvider("waveColor") { pointer -> - glUniform4f(pointer, waveColor.x, waveColor.y, waveColor.z, waveColor.w) - }, - UniformProvider("waveRadius") { pointer -> - glUniform1f(pointer, waveRadius.animatedValue.toFloat()) - }, - UniformProvider("waveSize") { pointer -> - glUniform1f(pointer, waveSize.animatedValue.toFloat()) - } - ) ) -} \ No newline at end of file + + fun onInitialize() { + PostProcessCallback.EVENT.register(::render) + } + + private fun render() { + if (!isActive()) { + return + } + + val source = PostProcessRenderer.sourceFramebuffer + val output = PostProcessRenderer.currentFramebuffer() + PostProcessRenderer.renderShaderToFramebuffer( + shockwaveShader, + output, + mapOf("framebuffer" to source, "depthAttachment" to source), + ) + PostProcessRenderer.copyFramebuffer(output, source) + } + + private fun isActive(): Boolean { + return waveRadius.isAnimating || + waveSize.isAnimating || + waveSize.animatedValue > 0.001 + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt index 56a1ef4f..745dd29e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt @@ -5,55 +5,30 @@ package heckerpowered.matrix.client.render.post -import com.mojang.blaze3d.platform.GlConst import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER object ToneMapping { - var exposureLinear: Float = 1.0f - var exposureEv: Float = 0.0f + var exposureLinear = 1.0F + var exposureEv = 0.0F + val toneMapFramebuffer: Framebuffer = PostProcessRenderer.createManagedFramebuffer() private val toneMappingProgram by lazy { BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("hdrScene") { location -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, currentSource.colorAttachment) - glUniform1i(location, 0) - }, - UniformProvider("exposure") { location -> - glUniform1f(location, exposureLinear) - }, - UniformProvider("exposureEv") { location -> - glUniform1f(location, exposureEv) - } - ) ) } - private lateinit var currentSource: Framebuffer - val toneMapFramebuffer = PostProcessRenderer.createManagedFramebuffer() - fun render(sourceFramebuffer: Framebuffer, targetFramebuffer: Framebuffer) { - currentSource = sourceFramebuffer - StateIsolation.isolate( - FramebufferState(targetFramebuffer), - ViewportState(targetFramebuffer), - BlendState.captureSnapshot(), - BlendFuncSeparateState.captureSnapshot() - ) { - PostProcessRenderer.renderShaderToFramebuffer(toneMappingProgram, targetFramebuffer, false) - } + PostProcessRenderer.renderShaderToFramebuffer( + toneMappingProgram, + targetFramebuffer, + mapOf("hdrScene" to sourceFramebuffer), + ) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt index 7ea2d207..1d30b104 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt @@ -9,12 +9,11 @@ import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.render.post.ScaleSampling import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import org.joml.Vector2f -import org.lwjgl.opengl.GL46.* +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER object GaussianBlurRenderer { - var colorAttachment: Int = 0 var gaussianKernel: FloatArray = FloatArray(0) var direction: Vector2f = Vector2f(1F, 0F) @@ -27,22 +26,6 @@ object GaussianBlurRenderer { val gaussianBlurShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/blur/gaussian_blur.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("kernel") { pointer -> - glUniform1fv(pointer, gaussianKernel) - }, - UniformProvider("kernelSize") { pointer -> - glUniform1i(pointer, (gaussianKernel.size - 1).coerceAtLeast(0)) - }, - UniformProvider("direction") { pointer -> - glUniform2f(pointer, direction.x, direction.y) - } - ) ) /** @@ -143,4 +126,4 @@ object GaussianBlurRenderer { val (kernelSize, sigma) = computeBlurParameters(strength, maxKernelSize, maxSigma) return generateSymmetricGaussianKernel(kernelSize, sigma) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt index 4888d727..5d324886 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt @@ -5,103 +5,31 @@ package heckerpowered.matrix.client.render.shader +import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.Program import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -/** - * A renderer that applies an opacity mask to discard fully transparent or fully black pixels. - * - * This class uses a custom fragment shader (`opacity_mask.fsh`) to perform per-pixel discarding based on the - * following rules: - * - * - Discards a pixel if its **alpha channel is 0.0**. - * - Discards a pixel if **all RGB channels are 0** (i.e., a fully black pixel). - * - * It uses two framebuffers: - * - `opacityMaskFramebuffer`: Provides the mask texture to control pixel visibility. - * - `colorFramebuffer`: Contains the source color data to be masked. - * - * During rendering, the appropriate color attachments from each framebuffer are bound to shader uniforms, - * and a full-screen blit is performed with the mask applied. - * - * @see Program - * @see Framebuffer - * @see UniformProvider - */ object OpacityMaskRenderer { - /** - * The OpenGL texture ID for the color attachment from the opacity mask framebuffer. - */ - private var opacityMaskColorAttachment: Int = -1 - - /** - * The OpenGL texture ID for the color attachment from the color framebuffer. - */ - private var colorAttachment: Int = -1 - - /** - * The shader used to apply the opacity mask. - * - * It binds two texture inputs: - * - `opacityMask` bound to texture unit 0. - * - `colorAttachment` bound to texture unit 1. - * - * The actual discard logic is implemented in the `opacity_mask.fsh` shader. - */ - private val opacityMaskShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/opacity_mask.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("colorAttachment") { pointer -> - glActiveTexture(GL_TEXTURE1) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 1) - }, - UniformProvider("opacityMask") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, opacityMaskColorAttachment) - glUniform1i(pointer, 0) - } + private val opacityMaskShader by lazy { + BlitProgram( + ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), + ResourceShader("/assets/matrix/shaders/post/opacity_mask.fsh", GL_FRAGMENT_SHADER), ) - ) + } - /** - * Renders the opacity-masked result using the provided framebuffers. - * - * This method sets up the shader with appropriate texture bindings from the given framebuffers, - * enables the shader, performs a full-screen blit, and then disables the shader. - * - * @param opacityMaskFramebuffer The framebuffer containing the opacity mask texture. - * @param colorFramebuffer The framebuffer containing the color texture to be masked. - */ fun render(opacityMaskFramebuffer: Framebuffer, colorFramebuffer: Framebuffer) { - opacityMaskColorAttachment = opacityMaskFramebuffer.colorAttachment - colorAttachment = colorFramebuffer.colorAttachment - opacityMaskShader.enableShader() - BlitProgram.blit() - opacityMaskShader.disableShader() + PostProcessRenderer.renderShaderToFramebuffer( + opacityMaskShader, + PostProcessRenderer.currentFramebuffer(), + mapOf("opacityMask" to opacityMaskFramebuffer, "colorAttachment" to colorFramebuffer), + ) + PostProcessRenderer.nextFramebuffer() } } -/** - * Applies an opacity mask from this [Framebuffer] to the specified [colorFramebuffer], using [OpacityMaskRenderer]. - * - * This infix extension function allows for expressive syntax like: - * ``` - * maskFramebuffer opacityMask colorFramebuffer - * ``` - * It renders the contents of [colorFramebuffer] with pixels masked out according to the rules defined - * in [OpacityMaskRenderer], using this framebuffer as the opacity mask source. - * - * @receiver The framebuffer providing the opacity mask (usually grayscale or alpha-based). - * @param colorFramebuffer The framebuffer whose contents are masked and rendered. - * - * @see OpacityMaskRenderer - */ infix fun Framebuffer.opacityMask(colorFramebuffer: Framebuffer) { OpacityMaskRenderer.render(this, colorFramebuffer) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt index 407cae2f..0a8db50e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt @@ -7,8 +7,8 @@ package heckerpowered.matrix.client.render.shader import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider -import org.lwjgl.opengl.GL46.* +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER /** * A singleton object responsible for applying a radial blur post-processing effect. @@ -26,7 +26,7 @@ import org.lwjgl.opengl.GL46.* */ object RadialBlurRenderer : PostProcessEffect { - /** The OpenGL texture ID of the framebuffer's color attachment to be blurred. */ + /** Retained for callers that still set the old OpenGL texture id; RenderPipeline uses framebuffer views instead. */ override var colorAttachment = 0 /** Controls how strong the radial blur effect appears. */ @@ -44,22 +44,9 @@ object RadialBlurRenderer : PostProcessEffect { val radialBlurShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/blur/radial_blur.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("strength") { pointer -> - glUniform1f(pointer, strength) - }, - UniformProvider("samples") { pointer -> - glUniform1i(pointer, samples) - } - ) ) override fun blit() { radialBlurShader.blit() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt index f1879799..aedbbca2 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt @@ -5,48 +5,12 @@ package heckerpowered.matrix.client.render.shader -import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.render.dump -import heckerpowered.matrix.client.render.recommendMipLevel +import heckerpowered.matrix.client.render.post.BloomEffect import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* object StandardBloomRenderer { - private var brightnessPass: Int = -1 - private val framebuffer: Framebuffer by lazy { - val framebuffer = PostProcessRenderer.createManagedFramebuffer() - // (framebuffer as FramebufferExtension).useMipmaps = true - // glBindTexture(GL_TEXTURE_2D, framebuffer.colorAttachment) - // glGenerateMipmap(GL_TEXTURE_2D) - framebuffer - } - fun render(brightnessPass: Framebuffer) { - // this.brightnessPass = brightnessPass.fbo - // val colorAttachment = this.brightnessPass -// - // glBindTexture(GL_TEXTURE_2D, colorAttachment) - // glGenerateMipmap(GL_TEXTURE_2D) -// - // val boundFramebuffer = glGetInteger(GL_FRAMEBUFFER_BINDING) - // val boundColorAttachment = glGetFramebufferParameteri(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0) -// - // glBindTexture(GL_TEXTURE_2D, boundColorAttachment) - - // Render to mipmaps - framebuffer.beginWrite(true) - glBindTexture(GL_TEXTURE_2D, framebuffer.colorAttachment) - glTexStorage2D(GL_TEXTURE_2D, framebuffer.recommendMipLevel(), GL_RGBA8, framebuffer.textureWidth, framebuffer.textureHeight) - - glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, framebuffer.colorAttachment, 1 - ) - - brightnessPass.draw(brightnessPass.textureWidth, brightnessPass.textureHeight) - framebuffer.dump(1, false) - - minecraft.framebuffer.beginWrite(false) + BloomEffect.brightnessPassFramebuffer = brightnessPass + BloomEffect.renderBloom() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt index 4396d1e5..7076fc3f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt @@ -5,34 +5,17 @@ package heckerpowered.matrix.client.render.shader -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider -import org.lwjgl.opengl.GL11.glBindTexture -import org.lwjgl.opengl.GL13.glActiveTexture import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object TentShader { - var framebufferObject: Int = -1 - var levelOfDetail = .0F - + var framebufferObject = 0 + var levelOfDetail = 0.0F val tentBlurShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/blur/tent.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("lod") { pointer -> - GL46.glUniform1f(pointer, levelOfDetail) - } - ) ) fun enable(framebufferObject: Int, levelOfDetail: Float) { @@ -44,4 +27,4 @@ object TentShader { fun disable() { tentBlurShader.disableShader() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt index 75bd6827..1321cf29 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt @@ -5,53 +5,10 @@ package heckerpowered.matrix.client.render.shader -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider -import heckerpowered.matrix.core.times -import org.joml.Matrix4f -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object VelocityMapRenderer { - private var previousModelViewProjectionMatrix = Matrix4f() - private var currentModelViewProjectionMatrix = Matrix4f() - - private val matrixBuffer = FloatArray(16) - val velocityMap = PostProcessRenderer.createManagedFramebuffer() - - val velocityMapShader by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/post/velocity_map/velocity_map.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/velocity_map/velocity_map.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("previousModelViewProjectionMatrix") { pointer -> - previousModelViewProjectionMatrix.get(matrixBuffer) - GL46.glUniformMatrix4fv(pointer, false, matrixBuffer) - }, - UniformProvider("currentModelViewProjectionMatrix") { pointer -> - currentModelViewProjectionMatrix.get(matrixBuffer) - GL46.glUniformMatrix4fv(pointer, false, matrixBuffer) - } - ) - ) - } - - init { - // PostProcessCallback.event.register(::onPostProcess) - } - - private fun onPostProcess() { - previousModelViewProjectionMatrix = currentModelViewProjectionMatrix - - val modelViewMatrix = RenderSystem.getModelViewMatrix() - val projectionMatrix = RenderSystem.getProjectionMatrix() - - // MVP = P * M * V - currentModelViewProjectionMatrix = projectionMatrix * modelViewMatrix - } -} \ No newline at end of file + val velocityMapShader = BlitProgram() +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt index 48956bb4..5fca90a3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt @@ -5,12 +5,12 @@ package heckerpowered.matrix.client.render.shader.hud -import heckerpowered.matrix.client.shader.* +import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.shader.ResourceShader import org.joml.Vector2f import org.joml.Vector4f import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object ProgressRingRenderer { /** @@ -44,24 +44,5 @@ object ProgressRingRenderer { val progressRingShader = BlitProgram( ResourceShader("/assets/matrix/shaders/position_texture.fsh", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/hud/progress_ring.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - modelViewMatrixProvider, - projectionMatrixProvider, - UniformProvider("progress") { pointer -> - GL46.glUniform1f(pointer, progress) - }, - UniformProvider("radius") { pointer -> - GL46.glUniform1f(pointer, radius) - }, - UniformProvider("thickness") { pointer -> - GL46.glUniform1f(pointer, thickness) - }, - UniformProvider("center") { pointer -> - GL46.glUniform2f(pointer, center.x, center.y) - }, - UniformProvider("color") { pointer -> - GL46.glUniform4f(pointer, color.x, color.y, color.z, color.w) - } - ) ) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt index 098a8a9e..e6f6fb9a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt @@ -5,59 +5,31 @@ package heckerpowered.matrix.client.render.shader.sdf -import com.mojang.blaze3d.platform.GlConst +import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import net.minecraft.client.gl.Framebuffer import org.joml.Vector2f import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER +import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER object DropShadowRenderer { - /** - * The color attachment of the signed distance field. - */ - var signedDistanceField: Int = -1 - var shadowOffset = Vector2f() + var shadowSize = 8.0F + var shadowColor = Vector4f(.0F, .0F, .0F, .5F) - /** - * The size of the shadow in pixels. - */ - var shadowSize = 8F - - /** - * The RGBA color of the shadow. - */ - var shadowColor = Vector4f() - - val dropShadowShader = BlitProgram( + private val dropShadowShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/sdf/drop_shadow.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("signedDistanceField") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, signedDistanceField) - glUniform1i(pointer, 0) - }, - UniformProvider("shadowOffset") { pointer -> - glUniform2f(pointer, shadowOffset.x, shadowOffset.y) - }, - UniformProvider("shadowSize") { pointer -> - glUniform1f(pointer, shadowSize) - }, - UniformProvider("shadowColor") { pointer -> - glUniform4f(pointer, shadowColor.x, shadowColor.y, shadowColor.z, shadowColor.w) - } - ) ) fun render(signedDistanceField: Framebuffer) { - this.signedDistanceField = signedDistanceField.colorAttachment - dropShadowShader.enableShader() - BlitProgram.blit() - dropShadowShader.disableShader() - this.signedDistanceField = -1 + PostProcessRenderer.renderShaderToFramebuffer( + dropShadowShader, + PostProcessRenderer.currentFramebuffer(), + mapOf("signedDistanceField" to signedDistanceField), + ) + PostProcessRenderer.nextFramebuffer() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt index 08d0efbb..428ad155 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt @@ -5,114 +5,70 @@ package heckerpowered.matrix.client.render.shader.sdf -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL11 -import org.lwjgl.opengl.GL13 import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object SignedDistanceField { - var framebufferObject: Int = -1 - var originFramebufferObject: Int = -1 - var stepSize: Float = 1.0F + var stepSize = 1.0F - init { - RenderSystem.assertOnRenderThread() - } - - val seedGenShader = BlitProgram( + private val seedGenShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/sdf/seed_gen.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE0) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - } - ) ) - val jumpFloodingShader = BlitProgram( + private val jumpFloodingShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/sdf/jump_flooding.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE0) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("stepSize") { pointer -> - GL46.glUniform1f(pointer, stepSize) - } - ) ) - val sdfEvalShader = BlitProgram( + private val sdfEvalShader = BlitProgram( ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), ResourceShader("/assets/matrix/shaders/post/sdf/sdf_eval.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE0) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("originFramebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE1) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, originFramebufferObject) - RenderSystem.glUniform1i(pointer, 1) - } - ) ) fun generateStepSizes(width: Int, height: Int): List { - val maxRes = maxOf(width, height) + val maxResolution = maxOf(width, height).coerceAtLeast(1) var step = 1 - while (step * 2 <= maxRes) { + while (step * 2 <= maxResolution) { step *= 2 } + val steps = mutableListOf() while (step >= 1) { - steps.add(step) + steps += step step /= 2 } return steps } fun computeSignedDistanceField(source: Framebuffer, pingFramebuffer: Framebuffer, pongFramebuffer: Framebuffer): Framebuffer { - framebufferObject = source.colorAttachment - originFramebufferObject = source.colorAttachment - PostProcessRenderer.renderShaderToFramebuffer(seedGenShader, pingFramebuffer) - this.framebufferObject = pingFramebuffer.colorAttachment + PostProcessRenderer.renderShaderToFramebuffer(seedGenShader, source, pingFramebuffer) - val resolutionX = source.textureWidth - val resolutionY = source.textureHeight + var input = pingFramebuffer + var output = pongFramebuffer + for (step in generateStepSizes(source.textureWidth, source.textureHeight)) { + stepSize = step.toFloat() + PostProcessRenderer.renderShaderToFramebuffer(jumpFloodingShader, input, output) - var ping = pingFramebuffer - var pong = pongFramebuffer - for (stepSize in generateStepSizes(resolutionX, resolutionY)) { - this.stepSize = stepSize.toFloat() - val swap = ping - ping = pong - pong = swap - - framebufferObject = pong.colorAttachment - PostProcessRenderer.renderShaderToFramebuffer(jumpFloodingShader, ping) + val swap = input + input = output + output = swap } - framebufferObject = ping.colorAttachment - PostProcessRenderer.renderShaderToFramebuffer(sdfEvalShader, pong) - return pong + PostProcessRenderer.renderShaderToFramebuffer( + sdfEvalShader, + output, + mapOf("framebuffer" to input, "originFramebuffer" to source), + ) + return output } fun computeSignedDistanceField(source: Framebuffer): Framebuffer { PostProcessRenderer.resetFramebuffers() return computeSignedDistanceField(source, PostProcessRenderer.ping, PostProcessRenderer.pong) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt index d52a993e..67d75eba 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt @@ -6,15 +6,11 @@ package heckerpowered.matrix.client.render.state import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL11.glGetInteger -import org.lwjgl.opengl.GL30.* class FramebufferState(val framebuffer: Int) : RenderPipelineState { companion object { fun captureSnapshot(): FramebufferState { - val previousBindingFramebuffer = glGetInteger(GL_FRAMEBUFFER_BINDING) - val snapshot = FramebufferState(previousBindingFramebuffer) - return snapshot + return FramebufferState(0) } } @@ -22,9 +18,6 @@ class FramebufferState(val framebuffer: Int) : RenderPipelineState { override fun apply(): RenderPipelineSnapshot { val snapshot = captureSnapshot() - - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer) - return RenderPipelineSnapshot(snapshot) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/LineWidthState.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/LineWidthState.kt index 7e646882..b760c937 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/LineWidthState.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/LineWidthState.kt @@ -5,25 +5,15 @@ package heckerpowered.matrix.client.render.state -import com.mojang.blaze3d.systems.RenderSystem -import org.lwjgl.opengl.GL46.* - class LineWidthState(val lineWidth: Float, val shaderLineWidth: Float = lineWidth) : RenderPipelineState { companion object { fun captureSnapshot(): LineWidthState { - val lineWidth = glGetFloat(GL_LINE_WIDTH) - val shaderLineWidth = RenderSystem.getShaderLineWidth() - - return LineWidthState(lineWidth, shaderLineWidth) + return LineWidthState(1.0F) } } override fun apply(): RenderPipelineSnapshot { val snapshot = captureSnapshot() - - glLineWidth(lineWidth) - RenderSystem.lineWidth(shaderLineWidth) - return RenderPipelineSnapshot(snapshot) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ShaderProgramState.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ShaderProgramState.kt index 0332059b..f965a091 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ShaderProgramState.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ShaderProgramState.kt @@ -5,23 +5,12 @@ package heckerpowered.matrix.client.render.state -import com.mojang.blaze3d.systems.RenderSystem -import net.minecraft.client.gl.ShaderProgram -import java.util.function.Supplier - -class ShaderProgramState(val program: Supplier) : RenderPipelineState { +class ShaderProgramState(val program: Any? = null) : RenderPipelineState { companion object { - fun captureSnapshot(): ShaderProgramState { - val shader = RenderSystem.getShader() - return ShaderProgramState { shader } - } + fun captureSnapshot(): ShaderProgramState = ShaderProgramState() } override fun apply(): RenderPipelineSnapshot { - val snapshot = captureSnapshot() - - RenderSystem.setShader(program) - - return RenderPipelineSnapshot(snapshot) + return RenderPipelineSnapshot(captureSnapshot()) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt index 4ec77909..03b3fedb 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt @@ -6,21 +6,11 @@ package heckerpowered.matrix.client.render.state import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46 class ViewportState(val viewportX: Int, val viewportY: Int, val viewportWidth: Int, val viewportHeight: Int) : RenderPipelineState { companion object { fun captureSnapshot(): ViewportState { - val viewportState = IntArray(4) - GL46.glGetIntegerv(GL46.GL_VIEWPORT, viewportState) - - val snapshot = ViewportState( - viewportX = viewportState[0], - viewportY = viewportState[1], - viewportWidth = viewportState[2], - viewportHeight = viewportState[3] - ) - return snapshot + return ViewportState(0, 0, 1, 1) } } @@ -28,9 +18,6 @@ class ViewportState(val viewportX: Int, val viewportY: Int, val viewportWidth: I override fun apply(): RenderPipelineSnapshot { val snapshot = captureSnapshot() - - GL46.glViewport(viewportX, viewportY, viewportWidth, viewportHeight) - return RenderPipelineSnapshot(snapshot) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt index 0e4f30c1..d479a3c3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt @@ -5,12 +5,9 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.systems.RenderSystem +import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.component.ShaderComponent -import net.minecraft.client.gl.VertexBuffer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats +import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER open class BlitProgram( vararg shaders: Shader, @@ -20,34 +17,20 @@ open class BlitProgram( ) : Program(*shaders, uniforms = uniforms, uniformBuffers = uniformBuffers, components = components) { companion object { - private var buffer = VertexBuffer(VertexBuffer.Usage.DYNAMIC) - - init { - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) - buffer.vertex(-1F, -1F, 0F).texture(0F, 0F) - buffer.vertex(1F, -1F, 0F).texture(1F, 0F) - buffer.vertex(1F, 1F, 0F).texture(1F, 1F) - buffer.vertex(-1F, 1F, 0F).texture(0F, 1F) - this.buffer.bind() - this.buffer.upload(buffer.end()) - VertexBuffer.unbind() - } - fun blit() { - buffer.bind() - buffer.draw() - VertexBuffer.unbind() + (activeProgram as? BlitProgram)?.blit() } } fun blit() { - RenderSystem.disableBlend() - enableShader() - buffer.bind() - buffer.draw() - VertexBuffer.unbind() - disableShader() - RenderSystem.enableBlend() + PostProcessRenderer.renderShaderToFramebuffer(this, PostProcessRenderer.currentFramebuffer()) + PostProcessRenderer.nextFramebuffer() + } + + fun fragmentResourcePath(): String? { + return shaderStages + .filterIsInstance() + .firstOrNull { it.type == GL_FRAGMENT_SHADER } + ?.path } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt index 6a368a30..b38ce3c1 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt @@ -5,237 +5,40 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.MatrixHud -import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.render.linearCopyTo -import heckerpowered.matrix.client.render.nearestCopyTo -import heckerpowered.matrix.client.render.post.ScaleSampling -import heckerpowered.matrix.client.render.shader.GaussianBlurRenderer -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import net.minecraft.client.MinecraftClient import net.minecraft.client.gl.Framebuffer -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import net.minecraft.client.texture.NativeImage -import org.joml.Vector2f -import org.lwjgl.opengl.GL46.* -import java.io.File - object BlurRenderer { - var initialFramebuffer = minecraft.framebuffer - var currentFramebuffer = minecraft.framebuffer + var initialFramebuffer: Framebuffer = PostProcessRenderer.sourceFramebuffer + var currentFramebuffer: Framebuffer = PostProcessRenderer.sourceFramebuffer var radius = 5.0F var kawaseOffset = 1.0F var useDownscaling: Boolean = true - private val imageProvider = UniformProvider("image") { pointer -> - GlStateManager._activeTexture(GL_TEXTURE0) - GlStateManager._bindTexture(currentFramebuffer.colorAttachment) - glUniform1i(pointer, 0) - } - - private val radiusProvider = UniformProvider("radius") { pointer -> - glUniform1f(pointer, radius * MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat()) - } - - private val kawaseOffsetProvider = UniformProvider("offset") { pointer -> - kawaseOffset += 3F - val progress = MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat() - glUniform2f(pointer, progress * kawaseOffset, progress * kawaseOffset) - } - - private val halfResolutionBlurFramebuffer by lazy { - ScaleSampling.createManagedScalingFramebuffer(0.5) - } - val blurFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } - val horizontalBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/gaussian_blur_horizontal.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider, radiusProvider) - ) - - val verticalBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/gaussian_blur_vertical.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider, radiusProvider) - ) - - val kawaseBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/kawase_blur.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider, kawaseOffsetProvider) - ) - - val tentBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/tent.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider) - ) - - private val colorfulShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/color/colorful.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("brightness") { pointer -> - glUniform1f(pointer, 1.1F) - }, - UniformProvider("saturation") { pointer -> - glUniform1f(pointer, 2.0F) - }, - UniformProvider("contrast") { pointer -> - glUniform1f(pointer, 1.0F) - }) - ) - - val blurTextureRenderProgram = Program( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/blur_mask.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(UniformProvider("image") { pointer -> - GlStateManager._activeTexture(GL_TEXTURE0) - GlStateManager._bindTexture(blurFramebuffer.colorAttachment) - glUniform1i(pointer, 0) - }) - ) + val horizontalBlurShader = BlitProgram() + val verticalBlurShader = BlitProgram() + val kawaseBlurShader = BlitProgram() + val tentBlurShader = BlitProgram() + val blurTextureRenderProgram = Program() fun dumpFrameBuffer(framebuffer: Framebuffer) { - val framebufferWidth = framebuffer.textureWidth - val framebufferHeight = framebuffer.textureHeight - - NativeImage(framebufferWidth, framebufferHeight, false).use { nativeImage -> - RenderSystem.bindTexture(framebuffer.colorAttachment) - nativeImage.loadFromTextureImage(0, false) - nativeImage.mirrorVertically() - - val file = File("screenshots") - file.mkdir() - - val filename = "framebuffer_dump_${framebuffer.hashCode()}.png" - nativeImage.writeTo(File(file, filename)) - } } fun renderQuad() { - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) - buffer.vertex(-1F, -1F, 0F).texture(0F, 0F) - buffer.vertex(1F, -1F, 0F).texture(1F, 0F) - buffer.vertex(1F, 1F, 0F).texture(1F, 1F) - buffer.vertex(-1F, 1F, 0F).texture(0F, 1F) - BufferRenderer.draw(buffer.end()) } fun renderGaussianBlurFullResolution(source: Framebuffer = PostProcessRenderer.sourceFramebuffer) { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), BlendState(false)) { - glBindTexture(GlConst.GL_TEXTURE_2D, PostProcessRenderer.sourceFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, blurFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - blurFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - GaussianBlurRenderer.fullPing.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(1F, 0F) - GaussianBlurRenderer.colorAttachment = source.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() - - GaussianBlurRenderer.fullPong.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(0F, 1F) - GaussianBlurRenderer.colorAttachment = GaussianBlurRenderer.fullPing.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() - - GaussianBlurRenderer.fullPong nearestCopyTo blurFramebuffer - } } fun renderGaussianBlur(source: Framebuffer = PostProcessRenderer.sourceFramebuffer, target: Framebuffer = blurFramebuffer) { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), BlendState(false)) { - glBindTexture(GlConst.GL_TEXTURE_2D, PostProcessRenderer.sourceFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 2).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 4).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, blurFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - source linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 2) - ScaleSampling.getDownScalingFramebuffer(1.0 / 2) linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - val downscalingFramebuffer = ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - - // blurFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - GaussianBlurRenderer.ping.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(1F, 0F) - GaussianBlurRenderer.colorAttachment = downscalingFramebuffer.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() - - GaussianBlurRenderer.pong.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(0F, 1F) - GaussianBlurRenderer.colorAttachment = GaussianBlurRenderer.ping.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() - - GaussianBlurRenderer.pong linearCopyTo halfResolutionBlurFramebuffer - halfResolutionBlurFramebuffer linearCopyTo target - } } fun renderKawaseBlur() { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot()) { - glBindTexture(GlConst.GL_TEXTURE_2D, PostProcessRenderer.sourceFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 2).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 4).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, blurFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - PostProcessRenderer.sourceFramebuffer linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 2) - ScaleSampling.getDownScalingFramebuffer(1.0 / 2) linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - val downscalingFramebuffer = ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - - blurFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - - kawaseOffset = 0F - val shaders = mutableListOf() - for (i in 0..4) { - shaders.add(kawaseBlurShader) - } - PostProcessRenderer.useFramebuffer(downscalingFramebuffer) { - PostProcessRenderer.renderShadersToFramebuffer(shaders, blurFramebuffer) - } - } } fun renderBlur() { @@ -245,7 +48,6 @@ object BlurRenderer { @JvmStatic fun onResize(width: Int, height: Int) { - blurFramebuffer.resize(width, height, MinecraftClient.IS_SYSTEM_MAC) - // GL30.glViewport(0, 0, width, height) + blurFramebuffer.resize(width, height, false) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt index 1c7f6ec0..24c33e1a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt @@ -5,87 +5,6 @@ package heckerpowered.matrix.client.shader -import heckerpowered.matrix.Matrix -import heckerpowered.matrix.client.minecraft -import net.minecraft.client.texture.ResourceTexture -import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* -import kotlin.time.Duration.Companion.nanoseconds -import kotlin.time.DurationUnit - -class DissolveShader : AutoCloseable { - val noiseTexture by lazy { perlinNoiseTextureId } - var dissolveFactor: Float = 1.0f - - var resolutionX: Float = 1.0F - var resolutionY: Float = 1.0F - var emissiveStrength: Float = 15.0F - var emissiveColor: Vector4f = Vector4f(0.1F, 0.5F, 1.0F, 1.0F) - - private val dissolveProgramUniforms = arrayOf( - modelViewMatrixProvider, - projectionMatrixProvider, - UniformProvider("noiseTexture") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, noiseTexture) - glUniform1i(pointer, 0) - }, - UniformProvider("dissolveFactor") { pointer -> - glUniform1f(pointer, dissolveFactor) - }, - UniformProvider("resolution") { pointer -> - glUniform2f(pointer, resolutionX, resolutionY) - }, - UniformProvider("time") { pointer -> - glUniform1f(pointer, System.nanoTime().nanoseconds.toDouble(DurationUnit.SECONDS).toFloat() % 10) - }, - UniformProvider("emissiveStrength") { pointer -> - glUniform1f(pointer, emissiveStrength) - }, - UniformProvider("emissiveColor") { pointer -> - glUniform4f(pointer, emissiveColor.x, emissiveColor.y, emissiveColor.z, emissiveColor.w) - }) - - private val program by lazy { - Program( - ResourceShader("/assets/matrix/shaders/position_texture_color.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/noise_mask.fsh", GL_FRAGMENT_SHADER), - uniforms = dissolveProgramUniforms - ) - } - - val plainDissolveProgram by lazy { - Program( - ResourceShader("/assets/matrix/shaders/position_texture_color.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/dissolve/dissolve.fsh", GL_FRAGMENT_SHADER), - uniforms = dissolveProgramUniforms - ) - } - - companion object { - private val perlinNoiseTexture = ResourceTexture(Matrix.identifier("textures/noise/perlin_noise.png")) - val perlinNoiseTextureId by lazy { loadPerlinNoiseTexture() } - - private fun loadPerlinNoiseTexture(): Int { - perlinNoiseTexture.load(minecraft.resourceManager) - - glBindTexture(GL_TEXTURE_2D, perlinNoiseTexture.glId) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT) - - return perlinNoiseTexture.glId - } - } - - fun enableShader() { - program.enableShader() - } - - fun disableShader() { - program.disableShader() - } - - override fun close() { - program.close() - } -} \ No newline at end of file +object DissolveShader { + var perlinNoiseTextureId: Int = 0 +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt index af341fcd..8a8a4051 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt @@ -5,37 +5,8 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.render.Color -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.system.MemoryUtil +import org.joml.Vector3f -object PositionColorProgram : Program( - ResourceShader("/assets/matrix/shaders/position_color.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/position_color.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - modelViewMatrixProvider, - projectionMatrixProvider, - UniformProvider("colorModulator") { pointer -> - RenderSystem.glUniform3(pointer, PositionColorProgram.colorBuffer) - } - ) -) { - private val colorBuffer = MemoryUtil.memAllocFloat(4) - var color = Color(1, 1, 1, 1) - set(value) { - field = value - uploadBuffer() - } - - private fun uploadBuffer() { - val color = color - val colorBuffer = colorBuffer - colorBuffer.clear() - colorBuffer.put(color.red / 255F) - colorBuffer.put(color.green / 255F) - colorBuffer.put(color.blue / 255F) - colorBuffer.put(color.alpha / 255F) - } -} \ No newline at end of file +object PositionColorProgram : Program() { + var color = Vector3f(1.0F, 1.0F, 1.0F) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Program.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/Program.kt index 214b37a8..fd395424 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Program.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/Program.kt @@ -5,13 +5,7 @@ package heckerpowered.matrix.client.shader -import heckerpowered.matrix.client.render.OpenGLExtensions import heckerpowered.matrix.client.shader.component.ShaderComponent -import kotlinx.coroutines.* -import net.minecraft.client.gl.GlProgramManager -import org.lwjgl.glfw.GLFW -import org.lwjgl.opengl.GL46.* -import org.slf4j.MarkerFactory import java.io.Closeable open class Program( @@ -21,96 +15,39 @@ open class Program( val components: Array = emptyArray(), ) : Closeable { companion object { - private val MARKER = MarkerFactory.getMarker("UniformProvider") - - private fun ensureGLContext() { - if (GLFW.glfwGetCurrentContext() == 0L) { - OpenGLExtensions.initGLContext("Shader-Compile") - } - } - - private fun compileShader(shader: Shader): Int { - if (shader is ResourceShader) { - ShaderStageStore.Default.compiledStage[shader.path]?.let { - return it - } - } - ensureGLContext() - return ShaderCompilerV1.compileShader(shader.source, shader.type) - } + internal var activeProgram: Program? = null } + protected val shaderStages: List = shaders.toList() + @Volatile var program = 0 - init { - val creationStack = Throwable().stackTraceToString() - CoroutineScope(ShaderCompilerV1.Dispatcher).launch { - try { - val shaderSourceDeferreds = shaders.map { async(Dispatchers.IO) { it.source; it } } - val shaderSources = shaderSourceDeferreds.awaitAll() - - val shaderObjects = shaderSources.map { compileShader(it) } - - program = glCreateProgram() - - shaderObjects.forEach { glAttachShader(program, it) } - components.forEach { component -> component.init(program) } - - glLinkProgram(program) - if (glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) { - val log = glGetProgramInfoLog(program, 1024) - error("Failed to compile shader: $log") - } - - shaderObjects.forEach { glDeleteShader(it) } - initUniforms() - } catch (exception: Exception) { - exception.printStackTrace() - println(creationStack) - } - } - } - protected fun attachShader(program: Int, shader: Int?) { - if (shader != null) { - glAttachShader(program, shader) - } } protected fun deleteShader(shader: Int?) { - if (shader != null) { - glDeleteShader(shader) - } } override fun close() { - glDeleteProgram(program) - components.forEach { component -> component.delete() } + if (activeProgram == this) { + activeProgram = null + } } fun enableShader() { - if (program == 0) { - return - } - GlProgramManager.useProgram(program) - initUniforms() - uploadUniforms() - components.filter { it.enabled }.forEach { it.enable() } + activeProgram = this } fun uploadUniforms() { - uniforms.forEach { uniform -> uniform.set(uniform.pointer) } - uniformBuffers.forEach { uniformBuffer -> uniformBuffer.set(program, uniformBuffer.pointer) } } fun initUniforms() { - uniforms.forEach { uniform -> uniform.init(program) } - uniformBuffers.forEach { uniformBuffer -> uniformBuffer.init(program) } } fun disableShader() { - components.filter { it.enabled }.forEach { it.disable() } - GlProgramManager.useProgram(0) + if (activeProgram == this) { + activeProgram = null + } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt index 1c1ba815..15e58489 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt @@ -5,30 +5,7 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst -import heckerpowered.matrix.client.render.MatrixRenderSystem -import heckerpowered.matrix.client.shader.cache.ShaderCompilationException -import org.lwjgl.opengl.ARBShadingLanguageInclude -import org.lwjgl.opengl.GL20.* - object ShaderCompiler { - fun compileShader(descriptor: ShaderSourceDescriptor): Int { - val shader = MatrixRenderSystem.createShader(descriptor.stage.shaderType) - - glShaderSource(shader, descriptor.source) - glCompileShader(shader) - - if (glGetShaderi(shader, GlConst.GL_COMPILE_STATUS) == GlConst.GL_FALSE) { - val logLength = glGetShaderi(shader, GL_INFO_LOG_LENGTH) - val log = glGetShaderInfoLog(shader, logLength) - throw ShaderCompilationException("$log\n${descriptor.source}") - } - - return shader - } - - fun addInclude(virtualPath: String, shaderSource: String) { - // println("Add include: $virtualPath") - ARBShadingLanguageInclude.glNamedStringARB(ARBShadingLanguageInclude.GL_SHADER_INCLUDE_ARB, virtualPath, shaderSource) - } -} \ No newline at end of file + fun addInclude(path: String, source: String) = Unit + fun compileShader(shader: Shader): Int = 0 +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt index 2591ed1e..befb5aff 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt @@ -5,74 +5,9 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst -import heckerpowered.matrix.client.render.OpenGLExtensions -import heckerpowered.matrix.client.shader.cache.ShaderCompilationException -import kotlinx.coroutines.* -import org.lwjgl.glfw.GLFW -import org.lwjgl.opengl.GL46.* -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryUtil +import kotlinx.coroutines.Dispatchers object ShaderCompilerV1 { - private fun shaderSource(shader: Int, source: String) { - try { - MemoryStack.stackPush().use { memoryStack -> - val sourceBuffer = memoryStack.UTF8(source, false) - val pointerBuffer = memoryStack.mallocPointer(1) - .put(sourceBuffer) - .flip() - val lengthBuffer = memoryStack.mallocInt(1) - .put(sourceBuffer.capacity()) - .flip() - glShaderSource(shader, pointerBuffer, lengthBuffer) - return - } - } catch (exception: OutOfMemoryError) { - exception.printStackTrace() - } - - val sourceBuffer = MemoryUtil.memUTF8(source, false) - try { - MemoryStack.stackPush().use { memoryStack -> - val pointerBuffer = memoryStack.mallocPointer(1) - .put(sourceBuffer) - .flip() - val lengthBuffer = memoryStack.mallocInt(1) - .put(sourceBuffer.capacity()) - .flip() - glShaderSource(shader, pointerBuffer, lengthBuffer) - } - } finally { - MemoryUtil.memFree(sourceBuffer) - } - } - - fun compileShader(source: String, type: Int): Int { - val shader = glCreateShader(type) - glShaderSource(shader, source) - glCompileShader(shader) - - if (glGetShaderi(shader, GlConst.GL_COMPILE_STATUS) == GlConst.GL_FALSE) { - val logLength = glGetShaderi(shader, GL_INFO_LOG_LENGTH) - val log = glGetShaderInfoLog(shader, logLength) - throw ShaderCompilationException("$log\n$source") - } - - return shader - } - - @OptIn(DelicateCoroutinesApi::class) - val Dispatcher = newFixedThreadPoolContext(1, "Shader-Compile") - - private fun ensureGLContext() { - if (GLFW.glfwGetCurrentContext() == 0L) { - OpenGLExtensions.initGLContext("Shader-Compile") - } - } - - fun CoroutineScope.compileShaderAsync(source: String, type: Int): Deferred = async(Dispatcher) { - ensureGLContext() - compileShader(source, type) - } -} \ No newline at end of file + val Dispatcher = Dispatchers.Default + fun compileShader(source: String, type: Int): Int = 0 +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt index fb95d03e..ac3a3e15 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt @@ -5,45 +5,8 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst -import heckerpowered.matrix.Matrix -import heckerpowered.matrix.client.minecraft -import net.minecraft.client.texture.ResourceTexture -import org.lwjgl.opengl.GL20 -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER - -object TexturePixelDissolveProgram : BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/texture_pixel_dissolve.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("noiseTexture") { pointer -> - GL20.glActiveTexture(GlConst.GL_TEXTURE0) - GL20.glBindTexture(GL20.GL_TEXTURE_2D, TexturePixelDissolveProgram.noiseTexture) - GL20.glUniform1i(pointer, 0) - }, - UniformProvider("normalTexture") { pointer -> - GL20.glActiveTexture(GlConst.GL_TEXTURE1) - GL20.glBindTexture(GL20.GL_TEXTURE_2D, TexturePixelDissolveProgram.normalTexture) - GL20.glUniform1i(pointer, 1) - }, - UniformProvider("dissolveFactor") { pointer -> - GL20.glUniform1f(pointer, TexturePixelDissolveProgram.dissolveFactor) - } - ) -) { - private val perlinNoiseTexture = ResourceTexture(Matrix.identifier("textures/perlin_noise.png")) - private var perlinNoiseTextureId: Int = 0 - private fun loadPerlinNoiseTexture() { - perlinNoiseTexture.load(minecraft.resourceManager) - perlinNoiseTextureId = perlinNoiseTexture.glId - } - - init { - loadPerlinNoiseTexture() - } - - var noiseTexture: Int = perlinNoiseTextureId - var normalTexture: Int = 0 - var dissolveFactor: Float = 1.0f -} \ No newline at end of file +object TexturePixelDissolveProgram : BlitProgram() { + var noiseTextureId: Int = 0 + var normalTextureId: Int = 0 + var dissolveFactor: Float = 0.0F +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt index 8aa8223a..fae83c24 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt @@ -5,103 +5,22 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.Matrix -import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.player -import heckerpowered.matrix.client.projectionMatrix -import heckerpowered.matrix.client.render.MatrixRenderSystem -import org.joml.Matrix4f -import org.lwjgl.opengl.GL46.* -import org.lwjgl.system.MemoryUtil -import org.slf4j.MarkerFactory -import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.DurationUnit - -private val buffer = MemoryUtil.memAllocFloat(16) - -val projectionMatrixProvider = UniformProvider("projectionMatrix") { pointer -> - buffer.position(0) - RenderSystem.getProjectionMatrix().get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val modelViewMatrixProvider = UniformProvider("modelViewMatrix") { pointer -> - buffer.position(0) - RenderSystem.getModelViewMatrix().get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val inverseProjectionMatrixProvider = UniformProvider("inverseProjectionMatrix") { pointer -> - buffer.position(0) - - val projectionMatrix = projectionMatrix - val invertProjectionMatrix = Matrix4f(projectionMatrix).invert() - invertProjectionMatrix.get(buffer) - - glUniformMatrix4fv(pointer, false, buffer) -} - -val inverseModelViewMatrixProvider = UniformProvider("inverseModelViewMatrix") { pointer -> - buffer.position(0) - - val modelViewMatrix = RenderSystem.getModelViewMatrix() - val invertModelViewMatrix = Matrix4f(modelViewMatrix).invert() - invertModelViewMatrix.get(buffer) - - glUniformMatrix4fv(pointer, false, buffer) -} - -val inverseViewMatrixProvider = UniformProvider("inverseViewMatrix") { pointer -> - buffer.position(0) - MatrixRenderSystem.inverseViewMatrix.get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val viewMatrixProvider = UniformProvider("inverseViewMatrix") { pointer -> - buffer.position(0) - MatrixRenderSystem.viewMatrix.get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val viewProjectionMatrixProvider = UniformProvider("viewProjectionMatrix") { pointer -> - buffer.position(0) - MatrixRenderSystem.viewProjectionMatrix.get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val playerPositionProvider = UniformProvider("playerPosition") { pointer -> - val tickDelta = minecraft.renderTickCounter.getTickDelta(true) - val position = player.getLerpedPos(tickDelta) - glUniform3f(pointer, position.x.toFloat(), position.y.toFloat(), position.z.toFloat()) -} - -val cameraPositionProvider = UniformProvider("cameraPosition") { pointer -> - val camera = minecraft.gameRenderer.camera - glUniform3f(pointer, camera.pos.x.toFloat(), camera.pos.y.toFloat(), camera.pos.z.toFloat()) -} - -val resolutionProvider = UniformProvider("resolution") { pointer -> - val width = minecraft.window.framebufferWidth.toFloat() - val height = minecraft.window.framebufferHeight.toFloat() - glUniform2f(pointer, width, height) -} - -val timeProvider = UniformProvider("time") { pointer -> - glUniform1f(pointer, System.nanoTime().milliseconds.toDouble(DurationUnit.SECONDS).toFloat()) -} - -open class UniformProvider(val name: String, val set: (pointer: Int) -> Unit) { - companion object { - private val MARKER = MarkerFactory.getMarker("UniformProvider") - } - +val projectionMatrixProvider = UniformProvider("projectionMatrix") +val modelViewMatrixProvider = UniformProvider("modelViewMatrix") +val inverseProjectionMatrixProvider = UniformProvider("inverseProjectionMatrix") +val inverseModelViewMatrixProvider = UniformProvider("inverseModelViewMatrix") +val inverseViewMatrixProvider = UniformProvider("inverseViewMatrix") +val viewMatrixProvider = UniformProvider("viewMatrix") +val viewProjectionMatrixProvider = UniformProvider("viewProjectionMatrix") +val playerPositionProvider = UniformProvider("playerPosition") +val cameraPositionProvider = UniformProvider("cameraPosition") +val resolutionProvider = UniformProvider("resolution") +val timeProvider = UniformProvider("time") + +open class UniformProvider(val name: String, val set: (pointer: Int) -> Unit = {}) { var pointer = -1 fun init(program: Int) { - pointer = glGetUniformLocation(program, name) - if (pointer == -1) { - Matrix.LOGGER.error(MARKER, "Cannot find uniform location, name: $name") - } + pointer = -1 } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt index 5d684c38..63b6c9fe 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt @@ -5,75 +5,4 @@ package heckerpowered.matrix.client.ui.element -import heckerpowered.matrix.client.easingFunction -import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.client.render.LegacyMatrixUIRenderer -import heckerpowered.matrix.client.render.Point -import heckerpowered.matrix.client.render.Rectangle -import heckerpowered.matrix.client.ui.foundation.animation.AnimationClock -import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation -import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus -import heckerpowered.matrix.common.magic.core.description -import net.minecraft.client.gui.DrawContext -import java.time.Duration -import kotlin.math.min - -object AvailableStatusTooltip { - private val opacityClock = AnimationClock(Duration.ofMillis(300), 128.0, 0.0) - private val shownAnimationClock = AnimationClock(Duration.ofMillis(300), -50.0, .0) - private val shownAnimation = DoubleAnimation(shownAnimationClock, easingFunction) - private val opacityAnimation = DoubleAnimation(opacityClock, easingFunction) - - private var currentStatus = LMagicAvailableStatus.AVAILABLE - private var displayStatus = LMagicAvailableStatus.AVAILABLE - private val statusChangeAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) - - fun show() { - opacityAnimation.currentValue = 1.0 - shownAnimation.currentValue = 0.0 - } - - fun hide() { - opacityAnimation.currentValue = 0.0 - shownAnimation.currentValue = -50.0 - } - - fun render(drawContext: DrawContext, renderer: LegacyMatrixUIRenderer, status: LMagicAvailableStatus) { - val minPoint = Point( - renderer.scaledWindowWidth / 2 - 125.0, - 30.0 + shownAnimation.animatedValue - ) - val maxPoint = Point( - renderer.scaledWindowWidth / 2 + 125.0, - 45.0 + shownAnimation.animatedValue - ) - - val backgroundColor = Color(128, 0, 0, (128 * opacityAnimation.animatedValue).toInt()) - renderer.renderRectangle(Rectangle(minPoint, maxPoint), backgroundColor) - - if (currentStatus != status && status != LMagicAvailableStatus.AVAILABLE) { - currentStatus = status - statusChangeAnimation.value = .0 - } - if (statusChangeAnimation.animatedValue == .0) { - statusChangeAnimation.value = 1.0 - displayStatus = currentStatus - } - - val opacity = (min(opacityAnimation.animatedValue, statusChangeAnimation.animatedValue) * 255).toInt() - if (opacity <= 3) { - return - } - - renderer.render( - displayStatus.description, - Point( - renderer.scaledWindowWidth / 2 - 125.0 + 5, - 32.5 + shownAnimation.animatedValue - ), - Color(255, 255, 255, opacity), - true - ) - } -} \ No newline at end of file +object AvailableStatusTooltip diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt index b10b4171..6a90c827 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt @@ -5,34 +5,41 @@ package heckerpowered.matrix.client.ui.element -import heckerpowered.foundation.ui.animation.core.AnimationScope -import heckerpowered.foundation.ui.animation.tween.TweenSpec import heckerpowered.foundation.ui.color.Argb8 -import heckerpowered.matrix.client.easingFunction +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.core.worldToScreen -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.util.math.Vec3d -import kotlin.math.roundToLong -import kotlin.time.Duration.Companion.milliseconds +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.util.ARGB +import net.minecraft.world.phys.Vec3 +import org.joml.Vector3f +import java.time.Duration +import kotlin.math.round +import kotlin.math.roundToInt object DamageNumberHud { - private val scope = AnimationScope() - - private class DamageNumber(val text: String, val color: Argb8, val position: Vec3d, scope: AnimationScope, val uid: Long) { - var size by scope.doubleAnimation(20.0) - var yOffset by scope.doubleAnimation(.0) - var opacity by scope.doubleAnimation(.0) - - var isFading = false - } + private data class DamageNumber( + val damage: Float, + val color: Int, + val position: Vec3, + val size: SimpleDoubleAnimation, + val yOffset: SimpleDoubleAnimation, + val opacity: SimpleDoubleAnimation, + val uid: Long, + ) private val damageNumbers = mutableListOf() private var counter = 0L + fun onInitialize() { + HudElementRegistry.addLast(Matrix.identifier("damage_numbers")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) + } + } + fun nextInstantKillMessage(uid: Long): String { return when (uid % 5) { 0L -> "代码是这样写的" @@ -44,107 +51,104 @@ object DamageNumberHud { } } - fun onInitialize() { - HudRenderCallback.EVENT.register(this::onHudRender) - } - - private fun formatDamage(value: Float): String { - if (value.isInfinite()) return "9999" - - if (value >= 1.0) { - return value.roundToLong().toString() + fun addDamageNumber(damage: Float, color: Any, position: Vec3) { + val size = SimpleDoubleAnimation().apply { + from = 20.0 + to = 4.0 + duration = Duration.ofMillis(300) + start() + } + val yOffset = SimpleDoubleAnimation().apply { + from = .0 + to = .5 + duration = Duration.ofMillis(900) + start() + } + val opacity = SimpleDoubleAnimation(initValue = 255.0).apply { + from = 255.0 + to = .0 + duration = Duration.ofMillis(900) + startTime = Duration.ofMillis(300) + start() } - val truncated = (value * 10.0).toInt() / 10.0 - return truncated.toString() - } - - fun addDamageNumber(damage: Float, color: Argb8, position: Vec3d) { - val formattedDamage = formatDamage(damage) - addDamageNumber(formattedDamage, color, position) + damageNumbers += DamageNumber( + damage = damage, + color = toPackedColor(color), + position = position, + size = size, + yOffset = yOffset, + opacity = opacity, + uid = counter++, + ) } - private var createdThisSecond = 0 - private var lastSecondMarkNanos = System.nanoTime() - - fun addDamageNumber(text: String, color: Argb8, position: Vec3d) { - createdThisSecond++ - - val damageNumber = DamageNumber(text, color, position, scope, ++counter) - scope.withAnimation(TweenSpec(300.milliseconds, easingFunction)) { - damageNumber.size = 4.0 - } - scope.withAnimation(TweenSpec(900.milliseconds, easingFunction)) { - damageNumber.yOffset = .5 + private fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + if (damageNumbers.isEmpty()) { + return } - scope.withAnimation(TweenSpec(300.milliseconds, easingFunction)) { - damageNumber.opacity = 255.0 + + damageNumbers.forEach { damageNumber -> + renderDamageNumber(drawContext, damageNumber) } - damageNumbers.add(damageNumber) + damageNumbers.removeIf { it.opacity.animatedValue <= .0 } } - private fun renderDamageNumber(damageNumber: DamageNumber, drawContext: DrawContext, tickCounter: RenderTickCounter) { - if (damageNumber.opacity <= 4.0) return - if (!damageNumber.isFading && damageNumber.opacity >= 255.0) { - damageNumber.isFading = true - scope.withAnimation(TweenSpec(300.milliseconds, easingFunction, 0.milliseconds)) { - damageNumber.opacity = .0 - } + private fun renderDamageNumber(drawContext: GuiGraphicsExtractor, damageNumber: DamageNumber) { + val opacity = damageNumber.opacity.animatedValue + if (opacity < 4.0) { + return } - val base = damageNumber.position val screenPosition = worldToScreen( - Vec3d(base.x, base.y + damageNumber.yOffset, base.z) + damageNumber.position.add(.0, damageNumber.yOffset.animatedValue, .0), + viewportWidth = drawContext.guiWidth(), + viewportHeight = drawContext.guiHeight(), ) ?: return - val text = damageNumber.text - val textRenderer = minecraft.textRenderer - - val width = textRenderer.getWidth(text) - val height = textRenderer.fontHeight - - val centerX = screenPosition.x + width / 2 - val centerY = screenPosition.y + height / 2 - - val matrices = drawContext.matrices - matrices.push() - matrices.translate(centerX, centerY, 0.0) - matrices.scale( - damageNumber.size.toFloat(), - damageNumber.size.toFloat(), - 1.0f - ) - matrices.translate(-centerX, -centerY, 0.0) - - val argb = damageNumber.color - .withAlpha(damageNumber.opacity.toInt()) - .packed - - textRenderer.draw( - text, - screenPosition.x.toFloat(), - screenPosition.y.toFloat(), - argb, - true, - matrices.peek().positionMatrix, - drawContext.vertexConsumers, - TextRenderer.TextLayerType.SEE_THROUGH, - 0, - 15728880 + val text = damageNumber.text() + val textWidth = minecraft.font.width(text) + val textHeight = minecraft.font.lineHeight + val textX = screenPosition.x.roundToInt() + val textY = screenPosition.y.roundToInt() + val centerX = textX + textWidth / 2.0F + val centerY = textY + textHeight / 2.0F + val scale = damageNumber.size.animatedValue.toFloat() + val color = ARGB.color( + opacity.roundToInt().coerceIn(0, 255), + ARGB.red(damageNumber.color), + ARGB.green(damageNumber.color), + ARGB.blue(damageNumber.color), ) - matrices.pop() + val pose = drawContext.pose() + pose.pushMatrix() + pose.translate(centerX, centerY) + pose.scale(scale, scale) + pose.translate(-centerX, -centerY) + drawContext.text(minecraft.font, text, textX, textY, color, true) + pose.popMatrix() } - fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - for (damageNumber in damageNumbers) { - renderDamageNumber(damageNumber, drawContext, tickCounter) + private fun DamageNumber.text(): String { + return when { + damage.isInfinite() -> "9999" + damage >= 1 -> round(damage).toULong().toString() + else -> ((damage * 10.0).toULong().toDouble() / 10.0).toString() } + } - for (i in damageNumbers.lastIndex downTo 0) { - if (damageNumbers[i].opacity <= 0.0 && damageNumbers[i].isFading) { - damageNumbers.removeAt(i) - } + private fun toPackedColor(color: Any): Int { + return when (color) { + is Argb8 -> color.packed + is Int -> color + is Vector3f -> ARGB.color( + 255, + color.x.toInt().coerceIn(0, 255), + color.y.toInt().coerceIn(0, 255), + color.z.toInt().coerceIn(0, 255), + ) + else -> ARGB.white(255) } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt index f4cd5005..94d7bff3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt @@ -5,265 +5,206 @@ package heckerpowered.matrix.client.ui.element -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.MatrixHud.targetedEntity import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.player -import heckerpowered.matrix.client.shader.BlurRenderer -import heckerpowered.matrix.client.ui.foundation.animation.ColorAnimation -import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus import heckerpowered.matrix.common.magic.core.Magic import heckerpowered.matrix.common.magic.core.MagicCalculationContext import heckerpowered.matrix.common.magic.core.description -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.text.Text -import net.minecraft.util.math.ColorHelper +import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana +import heckerpowered.matrix.data.language.MatrixLanguage +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.network.chat.Component +import net.minecraft.util.ARGB +import net.minecraft.world.entity.LivingEntity +import kotlin.math.roundToInt -/** - * Renderer of the magic list in the HUD. - */ object MagicList { - - private const val MAGIC_ELEMENT_HEIGHT = 100.0 - private const val MAGIC_ELEMENT_MARGIN = 50.0 - private const val MAGIC_ELEMENT_SPAN = 10.0 - - /** - * The list of magics to be displayed in the HUD. - */ - val magics = mutableListOf() - - /** - * Cached indent list for the magics, regenerates when the size of the list changes. - */ - private var cachedIndentList: List? = null - - /** - * Indent list for the magics, regenerates when the size of the list changes. - */ - private val indentList: List - get() { - if (cachedIndentList?.size != magics.size) { - cachedIndentList = generateIndentList(magics.size) - } - - return cachedIndentList!! + private const val MAGIC_ELEMENT_HEIGHT = 100 + private const val MAGIC_ELEMENT_MARGIN = 50 + private const val MAGIC_ELEMENT_SPAN = 10 + + fun render( + drawContext: GuiGraphicsExtractor, + magics: List, + selectedIndex: Int, + target: LivingEntity?, + alpha: Double, + availableMana: Double, + maxMana: Double, + manaRate: Double, + magicRate: Double, + ) { + if (magics.isEmpty()) { + return } - /** - * Cached use animation list for the magics, regenerates when the size of the list changes. - */ - private var cachedAnimationList: MutableList? = null - - /** - * Cached use animation list for the magics, regenerates when the size of the list changes. - */ - private val animationList: MutableList - get() { - if (cachedAnimationList?.size != magics.size) { - cachedAnimationList = mutableListOf().apply { - repeat(magics.size) { - add(.0) - } - } - } - - return cachedAnimationList!! + val width = drawContext.guiWidth() + val height = drawContext.guiHeight() + + HudShaderLayer.applyMagicListBackdrop(drawContext, alpha) + + val visibleRows = ((height - 70) / (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN)) + .coerceAtLeast(1) + .coerceAtMost(magics.size) + val firstIndex = firstVisibleIndex(selectedIndex, magics.size, visibleRows) + val indentList = generateIndentList(visibleRows, MAGIC_ELEMENT_SPAN) + val baseTop = height / 2 - (visibleRows * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) - MAGIC_ELEMENT_MARGIN) / 2 + val player = minecraft.player + + for (visibleIndex in 0 until visibleRows) { + val magicIndex = firstIndex + visibleIndex + val magic = magics.getOrNull(magicIndex) ?: continue + val indent = indentList.getOrElse(visibleIndex) { 0 } + val rowTop = baseTop + visibleIndex * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) + val rowLeft = 50 + indent + val rowWidth = 270.coerceAtMost((width * 0.42).roundToInt()) + val selected = magicIndex == selectedIndex + val rowAlpha = (alpha * if (selected) 190 else 72).roundToInt() + val accent = if (selected) 0x76D8FF else 0x2F6E82 + + drawContext.fill(rowLeft, rowTop, rowLeft + rowWidth, rowTop + MAGIC_ELEMENT_HEIGHT, color(rowAlpha, 7, 16, 22)) + drawContext.outline(rowLeft, rowTop, rowWidth, MAGIC_ELEMENT_HEIGHT, color((alpha * if (selected) 185 else 80).roundToInt(), 118, 216, 255)) + drawContext.fill(rowLeft, rowTop, rowLeft + 5, rowTop + MAGIC_ELEMENT_HEIGHT, color((alpha * 220).roundToInt(), accent shr 16 and 0xFF, accent shr 8 and 0xFF, accent and 0xFF)) + + val calculationContext = MagicCalculationContext.fromEntity(player, target) + val cost = runCatching { magic.getCost(calculationContext) }.getOrDefault(magic.definition.baseCost.toDouble().toLong()) + val channelTime = runCatching { magic.getChannelTime(calculationContext) }.getOrDefault(magic.definition.baseChannelTime.ticks) + val availability = runCatching { magic.availableStatus(calculationContext) }.getOrNull() + val available = availability?.isAvailable == true + val textAlpha = (alpha * if (available || selected) 255 else 150).roundToInt() + + drawContext.text(minecraft.font, magic.definition.name, rowLeft + 14, rowTop + 12, color(textAlpha, 244, 250, 255)) + + val costText = "${cost.mana.toDouble().roundToInt()}M" + val timeText = "${channelTime.coerceAtLeast(0)}t" + drawContext.text(minecraft.font, costText, rowLeft + 14, rowTop + 33, color(textAlpha, 144, 229, 255)) + drawContext.text(minecraft.font, timeText, rowLeft + 74, rowTop + 33, color(textAlpha, 188, 255, 218)) + + val availabilityText = availability?.firstOrNull()?.description ?: MatrixLanguage.magicAvailable + drawContext.textWithWordWrap( + minecraft.font, + availabilityText, + rowLeft + 14, + rowTop + 54, + rowWidth - 28, + if (available) color((alpha * 180).roundToInt(), 188, 255, 218) else color((alpha * 190).roundToInt(), 255, 192, 128), + ) } - /** - * Extra width animation list for the magics, regenerates when the size of the list changes. - */ - private var cachedWidthAnimationList: MutableList? = null - - /** - * Width animation list for the magics. - */ - private val widthAnimationList: MutableList - get() { - if (cachedWidthAnimationList?.size != magics.size) { - cachedWidthAnimationList = mutableListOf().apply { - repeat(magics.size) { - add(SimpleDoubleAnimation()) - } - } - } + val detailRight = width - 42 + val detailLeft = (width * 0.58).roundToInt().coerceAtMost(detailRight - 260) + val detailTop = 58 + val detailBottom = height - 40 + drawPanel(drawContext, detailLeft, detailTop, detailRight, detailBottom, alpha) + drawContext.text( + minecraft.font, + "Mana ${availableMana.toInt()}/${maxMana.toInt()} M x${formatRate(manaRate)} C x${formatRate(magicRate)}", + detailLeft + 12, + detailTop - 18, + color((alpha * 190).roundToInt(), 178, 226, 246), + ) + renderDetails(drawContext, detailLeft, detailTop, detailRight, detailBottom, magics[selectedIndex.coerceIn(magics.indices)], target, alpha) + } - return cachedWidthAnimationList!! + private fun renderDetails( + drawContext: GuiGraphicsExtractor, + left: Int, + top: Int, + right: Int, + bottom: Int, + magic: Magic, + target: LivingEntity?, + alpha: Double, + ) { + val contentLeft = left + 12 + val contentWidth = right - left - 24 + var y = top + 12 + val textColor = color((alpha * 245).roundToInt(), 234, 246, 255) + val mutedColor = color((alpha * 175).roundToInt(), 160, 201, 222) + + drawContext.text(minecraft.font, Component.translatable("matrix.hud.target"), contentLeft, y, mutedColor) + y += 13 + if (target != null) { + drawContext.text(minecraft.font, target.displayName, contentLeft, y, textColor) + y += 13 + val healthText = "HP ${target.health.roundToInt()}/${target.maxHealth.roundToInt()}" + drawContext.text(minecraft.font, healthText, contentLeft, y, color((alpha * 220).roundToInt(), 188, 255, 218)) + y += 22 + } else { + drawContext.text(minecraft.font, Component.translatable("matrix.magic.available_status.target_missing"), contentLeft, y, color((alpha * 210).roundToInt(), 255, 170, 150)) + y += 35 } - private var cachedBackgroundColorAnimationList: MutableList? = null - private val backgroundColorAnimationList: MutableList - get() { - if (cachedBackgroundColorAnimationList?.size != magics.size) { - cachedBackgroundColorAnimationList = mutableListOf().apply { - repeat(magics.size) { - add(ColorAnimation()) - } - } - } - - return cachedBackgroundColorAnimationList!! - } + drawContext.text(minecraft.font, Component.translatable("matrix.hud.selected_magic"), contentLeft, y, mutedColor) + y += 13 + drawContext.text(minecraft.font, magic.definition.name, contentLeft, y, textColor) + y += 15 - /** - * Whether the HUD is visible or not. - */ - private var visibility: Boolean = false + val calculationContext = MagicCalculationContext.fromEntity(minecraft.player, target) + val cost = runCatching { magic.getCost(calculationContext) }.getOrDefault(magic.definition.baseCost.toDouble().toLong()) + val channelTime = runCatching { magic.getChannelTime(calculationContext) }.getOrDefault(magic.definition.baseChannelTime.ticks) + drawContext.text(minecraft.font, "${cost.mana.toDouble().roundToInt()}M ${channelTime.coerceAtLeast(0)}t", contentLeft, y, color((alpha * 220).roundToInt(), 144, 229, 255)) + y += 18 - /** - * The opacity of the HUD, used for fading in and out. - */ - private val opacity = SimpleDoubleAnimation() + val availability = runCatching { magic.availableStatus(calculationContext) }.getOrNull() + val availabilityText = availability?.firstOrNull()?.description ?: MatrixLanguage.magicAvailable + drawContext.text(minecraft.font, availabilityText, contentLeft, y, if (availability?.isAvailable == true) color((alpha * 220).roundToInt(), 188, 255, 218) else color((alpha * 220).roundToInt(), 255, 192, 128)) + y += 20 - /** - * The x offset animation of the HUD, used for performing a sliding animation. - */ - private val xOffset = SimpleDoubleAnimation(-50.0) + drawContext.textWithWordWrap(minecraft.font, magic.definition.description, contentLeft, y, contentWidth, color((alpha * 205).roundToInt(), 214, 232, 242)) - /** - * Update the use animation list for the magics, called every frame. - */ - private fun updateUseAnimationList(tickCounter: RenderTickCounter) { - for (i in animationList.indices) { - val animation = animationList[i] - if (animation == .0) { - continue - } + drawContext.horizontalLine(contentLeft, right - 12, bottom - 18, color((alpha * 80).roundToInt(), 118, 216, 255)) + } - // Just update the animation for the current magic, they will automatically stop - // when they reach their full duration. - animationList[i] = animation + tickCounter.lastFrameDuration / 2000000 + private fun firstVisibleIndex(selectedIndex: Int, size: Int, visibleRows: Int): Int { + if (size <= visibleRows) { + return 0 } + return (selectedIndex - visibleRows / 2).coerceIn(0, size - visibleRows) } - fun render(drawContext: DrawContext, tickCounter: RenderTickCounter) { - if (magics.isEmpty()) { - return + private fun generateIndentList(size: Int, indentSize: Int): List { + if (size <= 1) { + return listOf(0) } - updateUseAnimationList(tickCounter) - } - - private fun getMagicAvailableStatus(magic: Magic): LMagicAvailableStatus { - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - return magic.availableStatus(calculationContext) + val center = (size - 1) / 2.0 + return List(size) { index -> + val distance = kotlin.math.abs(index - center) + ((center - distance) * indentSize).roundToInt().coerceAtLeast(0) + } } - private fun calculateMagicWidth(magic: Magic): Double { - val textRenderer = minecraft.textRenderer - - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - val costString = magic.getCost(calculationContext).toString() - val statusString = magic.availableStatus(calculationContext).description.toString() - - val magicNameWidth = textRenderer.getWidth(magic.definition.name) - val costWidth = textRenderer.getWidth(costString) - val statusWidth = textRenderer.getWidth(statusString) - - return magicNameWidth + costWidth + statusWidth + MAGIC_ELEMENT_SPAN * 3 // 3 spans for the name, cost, and status + private fun drawPanel(drawContext: GuiGraphicsExtractor, left: Int, top: Int, right: Int, bottom: Int, alpha: Double) { + drawContext.fill(left, top, right, bottom, color((alpha * 150).roundToInt(), 4, 14, 20)) + drawContext.fill(left + 1, top + 1, right - 1, bottom - 1, color((alpha * 42).roundToInt(), 45, 186, 224)) + drawContext.outline(left, top, right - left, bottom - top, color((alpha * 150).roundToInt(), 118, 216, 255)) } - private fun renderMagic(index: Int, drawContext: DrawContext, tickCounter: RenderTickCounter) { - if (opacity.animatedValue == .0) { - return - } - - val magic = magics[index] - val indent = indentList[index] - - val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - val costString = magic.getCost(calculationContext).toString() - val statusString = magic.availableStatus(calculationContext).description.toString() - - val textRenderer = minecraft.textRenderer - val magicNameWidth = textRenderer.getWidth(magic.definition.name) - val costWidth = textRenderer.getWidth(costString) - val statusWidth = textRenderer.getWidth(statusString) - - val magicWidth = magicNameWidth + costWidth + statusWidth + MAGIC_ELEMENT_SPAN * 3 // 3 spans for the name, cost, and status - - val widthAnimation = widthAnimationList[index] - widthAnimation.value = magicWidth - - val startX = (MAGIC_ELEMENT_MARGIN + indent + xOffset.animatedValue).toFloat() - val endX = (startX + widthAnimation.animatedValue).toFloat() - val startY = (index * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) + drawContext.scaledWindowHeight / 2 - (indentList.size + 1) * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) / 2).toFloat() - val endY = startY + MAGIC_ELEMENT_HEIGHT.toFloat() - - drawContext.enableScissor(startX.toInt(), startY.toInt(), endX.toInt(), endY.toInt()) - - BlurRenderer.blurTextureRenderProgram.enableShader() - BlurRenderer.renderQuad() - BlurRenderer.blurTextureRenderProgram.disableShader() - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) - - val backgroundColorAnimation = backgroundColorAnimationList[index] - val backgroundColor = ColorHelper.Argb.getArgb( - (opacity.animatedValue * 127.5).toInt(), - backgroundColorAnimation.red.animatedValue.toInt(), - backgroundColorAnimation.green.animatedValue.toInt(), - backgroundColorAnimation.blue.animatedValue.toInt() - ) - - buffer.vertex(transformationMatrix, startX, startY, 0F).color(backgroundColor) - buffer.vertex(transformationMatrix, endX, startY, 0F).color(backgroundColor) - buffer.vertex(transformationMatrix, endX, endY, 0F).color(backgroundColor) - buffer.vertex(transformationMatrix, startX, endY, 0F).color(backgroundColor) - - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - BufferRenderer.drawWithGlobalProgram(buffer.end()) - RenderSystem.disableBlend() - - val foregroundColor = ColorHelper.Argb.getArgb((opacity.animatedValue * 255).toInt(), 255, 255, 255) - drawContext.drawText(textRenderer, magic.definition.name, startX.toInt() + 5, startY.toInt() + 5, foregroundColor, false) - drawContext.drawText(textRenderer, Text.literal(costString), startX.toInt() + magicNameWidth + 15, startY.toInt() + 5, foregroundColor, false) - drawContext.drawText(textRenderer, statusString, startX.toInt() + magicNameWidth + costWidth + 25, startY.toInt() + 5, foregroundColor, false) - - drawContext.disableScissor() + private fun formatRate(value: Double): String { + return if (value % 1.0 == 0.0) value.toInt().toString() else value.toString() } - - fun onHudVisibilityChanged(visibility: Boolean) { - if (visibility) { - opacity.value = 1.0 - xOffset.value = .0 - } else { - opacity.value = .0 - xOffset.value = -50.0 +} + +object HudShaderLayer { + fun applyMagicListBackdrop( + drawContext: GuiGraphicsExtractor, + alpha: Double, + ) { + val opacity = alpha.coerceIn(.0, 1.0) + val screenWidth = drawContext.guiWidth() + val screenHeight = drawContext.guiHeight() + + drawContext.fill(0, 0, screenWidth, screenHeight, color((opacity * 88).roundToInt(), 2, 8, 12)) + drawContext.fillGradient(0, 0, screenWidth, screenHeight, color((opacity * 52).roundToInt(), 17, 45, 55), color((opacity * 18).roundToInt(), 2, 8, 12)) + + var scanY = 30 + while (scanY < screenHeight) { + drawContext.fill(0, scanY, screenWidth, scanY + 1, color((opacity * 18).roundToInt(), 120, 226, 255)) + scanY += 8 } } +} - /** - * Generate an indented list with the given indent and size in the approximate shape of a right-facing arc. - * - * @param size the size of the list. - * @param indentSize the size of indent. - * @return the indented list. - */ - private fun generateIndentList(size: Int, indentSize: Double = 5.0): List { - val indentList = mutableListOf() - - var current = .0 - for (i in 0 until size) { - indentList.add(current) - - if (size % 2 == 0 && i == size / 2 - 1) { - continue - } - - if (i >= size / 2) { - current += indentSize - } else { - current -= indentSize - } - } - - return indentList - } -} \ No newline at end of file +private fun color(alpha: Int, red: Int, green: Int, blue: Int): Int { + return ARGB.color(alpha.coerceIn(0, 255), red.coerceIn(0, 255), green.coerceIn(0, 255), blue.coerceIn(0, 255)) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt index e666131a..6e6b4f25 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt @@ -5,193 +5,4 @@ package heckerpowered.matrix.client.ui.element -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.player -import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.client.render.LegacyMatrixUIRenderer -import heckerpowered.matrix.client.render.Point -import heckerpowered.matrix.client.render.Rectangle -import heckerpowered.matrix.client.shader.DissolveShader -import heckerpowered.matrix.client.ui.foundation.animation.EasingMode -import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase -import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.magic.channel.CasterContext -import heckerpowered.matrix.common.magic.core.MagicCalculationContext -import heckerpowered.matrix.common.magic.rule.resource.CastingResourcePipeline -import heckerpowered.matrix.data.language.MatrixLanguage -import net.minecraft.client.gui.DrawContext -import net.minecraft.text.Text -import net.minecraft.util.math.MathHelper - -class ManaBar { - companion object { - val manaBarColor = Color(25, 128, 255, 64) - val usageManaColor = Color(255, 25, 25, 128) - val costManaColor = Color(128, 25, 25, 128) - } - - private val easingFunction = ElasticEase() - private var visibility = false - - private val shownAnimation = SimpleDoubleAnimation() - private val opacityAnimation = SimpleDoubleAnimation() - - val maxMana = SimpleDoubleAnimation() - val mana = SimpleDoubleAnimation() - var manaUsage = SimpleDoubleAnimation() - val manaCost = SimpleDoubleAnimation() - - private val castingResources = SimpleDoubleAnimation() - - init { - easingFunction.easingMode = EasingMode.OUT - easingFunction.oscillations = 0 - } - - private fun manaPercentage(): Double { - if (mana.value.isInfinite()) { - return 1.0 - } - return mana.animatedValue / maxMana.animatedValue - } - - private val actualManaPercentage: Double - get() = if (mana.value.isInfinite()) { - 1.0 - } else { - (mana.animatedValue - manaUsage.animatedValue) / maxMana.animatedValue - } - - private val dissolveShader = DissolveShader() - - private fun renderManaBar(drawContext: DrawContext, renderer: LegacyMatrixUIRenderer) { - if (!manaUsage.isAnimating) { - mana.value -= manaUsage.value - manaUsage.value = .0 - } - val minPoint = Point( - 50.0, - 10.0 + shownAnimation.animatedValue - ) - val maxPoint = Point( - MathHelper.lerp(manaPercentage(), 50.0, renderer.scaledWindowWidth - 50.0), - 25.0 + shownAnimation.animatedValue - ) - - /** - val width = maxPoint.x - minPoint.x - val height = maxPoint.y - minPoint.y - dissolveShader.dissolveFactor = 1.0F - actualManaPercentage.toFloat() / 2.0F - dissolveShader.resolutionX = width.toFloat() / 10.0F - dissolveShader.resolutionY = height.toFloat() / 10.0F - dissolveShader.emissiveColor = Vector4f(0.1F, 0.5F, 1F, 1.0F) - dissolveShader.plainDissolveProgram.enableShader() - - val backgroundColor = ColorHelper.Argb.getArgb(255, 0, 0, 0) - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR) - - buffer.vertex(minPoint.x.toFloat(), maxPoint.y.toFloat(), 0F).texture(1F, 1F).color(backgroundColor) - buffer.vertex((renderer.scaledWindowWidth - 50.0).toFloat(), maxPoint.y.toFloat(), 0F).texture(0F, 1F).color(backgroundColor) - buffer.vertex((renderer.scaledWindowWidth - 50.0).toFloat(), minPoint.y.toFloat(), 0F).texture(0F, 0F).color(backgroundColor) - buffer.vertex(minPoint.x.toFloat(), minPoint.y.toFloat(), 0F).texture(1F, 0F).color(backgroundColor) - - val window = MinecraftClient.getInstance().window - val scaleFactor = window.scaleFactor - val maxX = MathHelper.lerp(actualManaPercentage, 50.0, renderer.scaledWindowWidth - 50.0) - RenderSystem.enableScissor( - (minPoint.x * scaleFactor).toInt(), - (window.framebufferHeight - maxPoint.y * scaleFactor).toInt(), - ((maxX - minPoint.x) * scaleFactor).toInt(), - ((maxPoint.y - minPoint.y) * scaleFactor).toInt(), - ) - isolate( - BlendState(true), - BlendFuncSeparateState() - ) { - BufferRenderer.draw(buffer.end()) - } - RenderSystem.disableScissor() - - dissolveShader.disableShader() - dissolveShader.resolutionX = 1.0F - dissolveShader.resolutionY = 1.0F - */ - val multiplier = 1F - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) - renderer.renderRectangle(Rectangle(minPoint, maxPoint), manaBarColor) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - - val usagePercentage = manaUsage.animatedValue / maxMana.animatedValue - val usageMinPoint = Point( - (maxPoint.x - usagePercentage * (renderer.scaledWindowWidth - 100)).coerceAtLeast(50.0), - minPoint.y - ) - - renderer.renderRectangle(Rectangle(usageMinPoint, maxPoint), usageManaColor) - - val costPercentage = manaCost.animatedValue / maxMana.animatedValue - val costMinPoint = Point( - (usageMinPoint.x - costPercentage * (renderer.scaledWindowWidth - 100)).coerceAtLeast(50.0), - maxPoint.y - ) - - // val multiplier = 1.0F - // RenderSystem.setShaderColor(multiplier, multiplier, multiplier, multiplier) - renderer.renderRectangle(Rectangle(costMinPoint, Point(usageMinPoint.x, maxPoint.y + 3)), costManaColor) - // RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - } - - private fun renderManaText(renderer: LegacyMatrixUIRenderer) { - val mana = mana.animatedValue - val manaUsage = this.manaUsage.animatedValue - val currentMana = ((mana * 10).toLong() - (manaUsage * 10).toLong()) / 10.0 - val maxMana = (maxMana.animatedValue * 10).toLong() / 10.0 - - val context = MagicCalculationContext(CasterContext.fromEntity(player)) - castingResources.value = CastingResourcePipeline.collect(context).resources.drop(1).sumOf { it.availableAmount(context).toDouble() } - - val total = (castingResources.animatedValue * 10).toLong() / 10.0 - if (total != 0.0) { - renderer.render( - Text.literal("${MatrixLanguage.mana.string} ≈ $total + ${currentMana}/${maxMana}"), - Point(55.0, 12.5 + shownAnimation.animatedValue), Color(255, 255, 255, 255), - true - ) - } else { - renderer.render( - Text.literal("${MatrixLanguage.mana.string} = ${currentMana}/${maxMana}"), - Point(55.0, 12.5 + shownAnimation.animatedValue), Color(255, 255, 255, 255), - true - ) - } - } - - val animationRemaining: Boolean - get() = manaUsage.isAnimating || mana.isAnimating - - fun render(drawContext: DrawContext, renderer: LegacyMatrixUIRenderer) { - if (!visibility) { - opacityAnimation.value = .0 - shownAnimation.value = -50.0 - } - - manaBarColor.alpha = (opacityAnimation.animatedValue * 127.5).toInt() - usageManaColor.alpha = (opacityAnimation.animatedValue * 127.5).toInt() - costManaColor.alpha = (opacityAnimation.animatedValue * 127.5).toInt() - - renderManaBar(drawContext, renderer) - renderManaText(renderer) - } - - fun onHudVisibilityChanged(visibility: Boolean) { - this.visibility = visibility - if (visibility) { - opacityAnimation.value = 1.0 - shownAnimation.value = .0 - } - } - - fun onRemoteManaUpdate() { - } -} \ No newline at end of file +object ManaBar diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt index e94852f8..d1c3c752 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt @@ -5,151 +5,4 @@ package heckerpowered.matrix.client.ui.element -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.MatrixHud -import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.player -import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.client.render.Point -import heckerpowered.matrix.client.ui.foundation.animation.ColorAnimation -import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.magic.core.MagicCalculationContext -import heckerpowered.matrix.data.language.MatrixLanguage -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import java.time.Duration -import kotlin.math.abs -import kotlin.math.min - -object ManaCostTooltip { - private val shownAnimation = SimpleDoubleAnimation() - private val opacityAnimation = SimpleDoubleAnimation() - private val backgroundColorAnimation = ColorAnimation() - private var visibility = false - - private var differenceChangedAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150)) - private var stateChangedAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150)) - private var lastState = false - private var displayState = false - - private var lastDifference = 0L - private var displayedDifference = 0L - - fun show() { - if (!visibility) { - return - } - shownAnimation.value = 70.0 - opacityAnimation.value = 1.0 - } - - fun hide() { - shownAnimation.value = .0 - opacityAnimation.value = 0.0 - } - - fun onHudVisibilityChanged(visibility: Boolean) { - this.visibility = visibility - if (!visibility) { - hide() - } - } - - fun render(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val currentMagic = MatrixHud.selectedMagic - val target = MatrixHud.targetedEntity - val calculationContext = MagicCalculationContext.fromEntity(player, target) - val cost = currentMagic.getCost(calculationContext) - val normalCost = currentMagic.getNormalCost() - if (cost == normalCost) { - hide() - } else { - show() - } - - if (cost > normalCost) { - backgroundColorAnimation.red.value = 0.5 - backgroundColorAnimation.green.value = .0 - backgroundColorAnimation.blue.value = .0 - } else if (cost < normalCost) { - backgroundColorAnimation.red.value = .0 - backgroundColorAnimation.green.value = 0.5 - backgroundColorAnimation.blue.value = .0 - } - if (opacityAnimation.animatedValue == .0) { - return - } - - val minPoint = Point(drawContext.scaledWindowWidth / 2 - 125.0, drawContext.scaledWindowHeight - shownAnimation.animatedValue) - val maxPoint = Point(drawContext.scaledWindowWidth / 2 + 125.0, minPoint.y + 15) - - val color = backgroundColorAnimation - val red = color.red.animatedValue.toFloat() - val green = color.green.animatedValue.toFloat() - val blue = color.blue.animatedValue.toFloat() - val alpha = (opacityAnimation.animatedValue * 0.5).toFloat() - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - - val buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) - buffer.vertex(transformationMatrix, maxPoint.x.toFloat(), maxPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - buffer.vertex(transformationMatrix, maxPoint.x.toFloat(), minPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - buffer.vertex(transformationMatrix, minPoint.x.toFloat(), minPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - buffer.vertex(transformationMatrix, minPoint.x.toFloat(), maxPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - BufferRenderer.drawWithGlobalProgram(buffer.end()) - RenderSystem.disableBlend() - - val textRenderer = minecraft.textRenderer - val difference = abs(normalCost - cost) - if (difference != lastDifference) { - differenceChangedAnimation.value = .0 - lastDifference = difference - } - if (differenceChangedAnimation.animatedValue == .0) { - differenceChangedAnimation.value = 1.0 - displayedDifference = difference - } - - if (cost != normalCost) { - val state = cost > normalCost - if (state != lastState) { - lastState = state - stateChangedAnimation.value = .0 - } - } - if (stateChangedAnimation.animatedValue == .0) { - stateChangedAnimation.value = 1.0 - displayState = lastState - } - - val foregroundOpacity = min(differenceChangedAnimation.animatedValue, opacityAnimation.animatedValue) - val stateForegroundOpacity = (min(stateChangedAnimation.animatedValue, opacityAnimation.animatedValue) * 255).toInt() - val foregroundColor = Color(255, 255, 255, stateForegroundOpacity) - val differenceForegroundColor = Color(255, 255, 255, (foregroundOpacity * 255).toInt()) - if ((opacityAnimation.animatedValue * 255).toInt() <= 3) { - return - } - - val vertexConsumerProvider = drawContext.vertexConsumers - val yOffset = 2.5F - - if (stateForegroundOpacity > 3) { - if (displayState) { - textRenderer.draw(MatrixLanguage.manaCostIncreased, minPoint.x.toFloat() + 5F, minPoint.y.toFloat() + yOffset, foregroundColor.toInt(), false, transformationMatrix, vertexConsumerProvider, TextRenderer.TextLayerType.NORMAL, 0, 15728880) - } else { - textRenderer.draw(MatrixLanguage.manaCostReduced, minPoint.x.toFloat() + 5F, minPoint.y.toFloat() + yOffset, foregroundColor.toInt(), false, transformationMatrix, vertexConsumerProvider, TextRenderer.TextLayerType.NORMAL, 0, 15728880) - } - } - - if ((foregroundOpacity * 255).toInt() > 3 && cost != normalCost) { - val width = textRenderer.getWidth(displayedDifference.toString()) - textRenderer.draw(displayedDifference.toString(), maxPoint.x.toFloat() - 5F - width, minPoint.y.toFloat() + yOffset, differenceForegroundColor.toInt(), false, transformationMatrix, vertexConsumerProvider, TextRenderer.TextLayerType.NORMAL, 0, 15728880) - } - drawContext.draw() - } -} \ No newline at end of file +object ManaCostTooltip diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt index 6a0e7afc..42f02146 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt @@ -5,164 +5,4 @@ package heckerpowered.matrix.client.ui.element -import heckerpowered.matrix.client.MatrixHud -import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.player -import heckerpowered.matrix.client.render.shader.hud.ProgressRingRenderer -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.ProgramState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import heckerpowered.matrix.client.render.state.capabilities.CullFaceState -import heckerpowered.matrix.client.render.state.capabilities.DepthTestState -import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.effect.ModMobEffects.WITHER_ARMOR_CHARGED_EFFECT -import heckerpowered.matrix.common.item.ModComponents.borrowedTimeCharge -import heckerpowered.matrix.common.item.ModComponents.borrowedTimeMaxCharge -import heckerpowered.matrix.common.item.ModComponents.borrowedTimeState -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.entity.EquipmentSlot -import net.minecraft.util.math.ColorHelper -import org.joml.Vector4f - -object StatusHud { - private const val PROGRESS_RING_SIZE = 32F - private const val X_PADDING = 16F - - private var previousCharges = -1 - private val progress = SimpleDoubleAnimation(initValue = .0) - private val opacityAnimation = SimpleDoubleAnimation(initValue = .0) - - fun onInitialize() { - // HudRenderCallback.EVENT.register(this::onHudRender) - } - - fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - renderWitherArmor(drawContext, tickCounter) - renderPhaseWalk(drawContext, tickCounter) - } - - private val phaseWalkProgress = SimpleDoubleAnimation(initValue = .0) - private val phaseWalkOpacity = SimpleDoubleAnimation(initValue = .0) - private val phaseWalkYOffset = SimpleDoubleAnimation() - - private fun renderPhaseWalk(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val chestplate = player.getEquippedStack(EquipmentSlot.CHEST) - val isPhaseWalking = chestplate.components.getOrDefault(borrowedTimeState, false) - val currentCharge = chestplate.components.getOrDefault(borrowedTimeCharge, 0L) - val maxCharge = chestplate.components.getOrDefault(borrowedTimeMaxCharge, 0L) - if (isPhaseWalking) { - phaseWalkOpacity.value = 1.0 - } else if (currentCharge >= maxCharge) { - phaseWalkOpacity.value = 0.0 - } - - if (phaseWalkOpacity.animatedValue == .0) { - return - } - if (opacityAnimation.to == .0) { - phaseWalkYOffset.value = .0 - } else { - phaseWalkYOffset.value = 65.0 - } - - phaseWalkProgress.value = currentCharge.toDouble() / maxCharge.toDouble() - renderProgressRing( - drawContext, phaseWalkProgress.animatedValue.toFloat(), - "${(phaseWalkProgress.animatedValue * 100).toInt()}%", "时不我待", - phaseWalkOpacity.animatedValue.toFloat(), - yOffset = phaseWalkYOffset.animatedValue.toFloat() - ) - } - - private fun renderWitherArmor(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val statusEffect = player.getStatusEffect(WITHER_ARMOR_CHARGED_EFFECT) - if (statusEffect != null) { - val previousValue = progress.value - progress.value = 1.0 - statusEffect.duration / 200.0 - if (statusEffect.amplifier >= 3) { - progress.value = 1.0 - } else if (progress.value < previousValue) { - progress.animatedValue = progress.value - } - if (previousCharges != statusEffect.amplifier) { - previousCharges = statusEffect.amplifier - opacityAnimation.value = 1.0 - } else if (statusEffect.amplifier == 3) { - opacityAnimation.value = .0 - } - } else { - opacityAnimation.value = .0 - } - - if (opacityAnimation.animatedValue == .0) { - return - } - - renderProgressRing(drawContext, progress.animatedValue.toFloat(), (statusEffect?.amplifier ?: 0).toString(), "凋零护甲", opacityAnimation.animatedValue.toFloat()) - } - - private fun renderProgressRing(drawContext: DrawContext, progress: Float, progressString: String, description: String, opacity: Float, xOffset: Float = 0F, yOffset: Float = 0F) { - MatrixHud.renderHud = true - MatrixHud.useBloom = true - - val scaledWidth = drawContext.scaledWindowWidth - val scaledHeight = drawContext.scaledWindowHeight - - val progressRingX = scaledWidth.toFloat() - val progressRingY = scaledHeight / 2F - - val minX = progressRingX - PROGRESS_RING_SIZE - X_PADDING + xOffset - val maxX = progressRingX - X_PADDING + xOffset - - val minY = progressRingY + PROGRESS_RING_SIZE / 2 + yOffset - val maxY = progressRingY - PROGRESS_RING_SIZE / 2 + yOffset - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - val buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) - - buffer.vertex(transformationMatrix, minX, minY, 0F).texture(0F, 0F) - buffer.vertex(transformationMatrix, maxX, minY, 0F).texture(1F, 0F) - buffer.vertex(transformationMatrix, maxX, maxY, 0F).texture(1F, 1F) - buffer.vertex(transformationMatrix, minX, maxY, 0F).texture(0F, 1F) - - ProgressRingRenderer.color = Vector4f(1.5F, 1.5F, 1.5F, opacity) - ProgressRingRenderer.progress = progress - - StateIsolation.isolate( - BlendState(true), - BlendFuncSeparateState(), - DepthTestState(false), - CullFaceState(false), - ProgramState(ProgressRingRenderer.progressRingShader) - ) { - BufferRenderer.draw(buffer.end()) - } - - val width = minecraft.textRenderer.getWidth(progressString) - val textAlpha = (opacity * 255).toInt() - if (textAlpha <= 3) { - return - } - drawContext.drawText( - minecraft.textRenderer, - progressString, - ((minX + maxX) / 2).toInt() - width / 2, - ((minY + maxY) / 2).toInt() - minecraft.textRenderer.fontHeight / 2, - ColorHelper.Argb.getArgb(textAlpha, 255, 255, 255), - true - ) - - val descWidth = minecraft.textRenderer.getWidth(description) - drawContext.drawText( - minecraft.textRenderer, - description, - ((minX + maxX) / 2).toInt() - descWidth / 2, - minY.toInt() + minecraft.textRenderer.fontHeight, - ColorHelper.Argb.getArgb(textAlpha, 255, 255, 255), - true - ) - } -} \ No newline at end of file +object StatusHud diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt index d5bae526..6a74eb0b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt @@ -5,116 +5,6 @@ package heckerpowered.matrix.client.ui.element -import com.google.common.base.Stopwatch -import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.client.render.LegacyMatrixUIRenderer -import heckerpowered.matrix.client.render.Point -import heckerpowered.matrix.client.render.Rectangle -import heckerpowered.matrix.client.ui.foundation.animation.AnimationClock -import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation -import heckerpowered.matrix.client.ui.foundation.animation.EasingMode -import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase -import heckerpowered.matrix.data.language.MatrixLanguage -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.util.math.MathHelper -import java.io.File -import java.io.FileOutputStream -import java.time.Duration -import java.util.concurrent.TimeUnit - object SystemCrashBar { - private var isCrashing = false - private var stopWatch = Stopwatch.createUnstarted() - private val CHANNEL_TIME = Duration.ofSeconds(10) - private var bsod = false - - private val easingFunction = ElasticEase().also { - it.oscillations = 0 - it.easingMode = EasingMode.OUT - } - - private val opacityClock = AnimationClock(Duration.ofMillis(300), .0, 1.0) - private val opacityAnimation = DoubleAnimation(opacityClock, easingFunction) - - fun onInitialize() { - HudRenderCallback.EVENT.register(this::onHudRender) - } - - private fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val renderer = LegacyMatrixUIRenderer(drawContext.vertexConsumers) - render(renderer) - } - - fun systemCrash() { - isCrashing = true - if (stopWatch.isRunning) { - stopWatch.reset() - } - stopWatch.start() - opacityClock.start() - } - - private fun windowsBlueScreen() { - try { - val file = File("SystemCrash.exe") - if (file.exists()) { - file.delete() - } - - javaClass.classLoader.getResourceAsStream("SystemCrash.exe")?.use { stream -> - FileOutputStream("SystemCrash.exe").use { fileOutputStream -> - stream.copyTo(fileOutputStream) - } - } - - @Suppress("deprecated") - Runtime.getRuntime().exec("\"${file.absolutePath}\"") - } catch (e: Exception) { - e.printStackTrace() - MinecraftClient.getInstance().close() - } - } - - fun render(renderer: LegacyMatrixUIRenderer) { - if (stopWatch.elapsed(TimeUnit.NANOSECONDS).toDouble() >= CHANNEL_TIME.toNanos().toDouble() && !bsod) { - bsod = true - windowsBlueScreen() - } - val progress = - (stopWatch.elapsed(TimeUnit.NANOSECONDS).toDouble() / CHANNEL_TIME.toNanos().toDouble()).coerceIn(.0..1.0) - val progressBackground = Color(128, 0, 0, (128.0 * opacityAnimation.animatedValue).toInt()) - val progressForeground = Color(255, 0, 0, (255.0 * opacityAnimation.animatedValue).toInt()) - - val minPoint = Point( - renderer.scaledWindowWidth / 2 - 125.0, - renderer.scaledWindowHeight - 100.0 - ) - val maxPoint = Point( - renderer.scaledWindowWidth / 2 + 125.0, - renderer.scaledWindowHeight - 125.0 - ) - renderer.renderRectangle(Rectangle(minPoint, maxPoint), progressBackground) - - val progressMaxPoint = Point( - MathHelper.lerp(progress, minPoint.x, maxPoint.x), - maxPoint.y - ) - renderer.renderRectangle(Rectangle(minPoint, progressMaxPoint), progressForeground) - - if (255 * opacityAnimation.animatedValue <= 0.05) { - return - } - renderer.render( - MatrixLanguage.systemCrashing, - Point( - renderer.scaledWindowWidth / 2 - 125.0 + 8, - renderer.scaledWindowHeight - 125.0 + 8.5 - ), - Color(255, 255, 255, (255 * opacityAnimation.animatedValue).toInt()), - true - ) - } -} \ No newline at end of file + fun systemCrash() = Unit +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt index 0b39fad2..bdf83977 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt @@ -6,7 +6,7 @@ package heckerpowered.matrix.client.ui.foundation.animation import heckerpowered.matrix.core.lerp -import net.minecraft.util.math.MathHelper +import net.minecraft.util.Mth import org.apache.commons.lang3.time.StopWatch import java.time.Duration import kotlin.math.max @@ -50,7 +50,7 @@ class AnimationClock(var duration: Duration, var from: Double, var to: Double, v private fun getValueAt(timeNanos: Long): Double { val progress = (timeNanos.toDouble() / duration.toNanos().toDouble()).coerceIn(.0..1.0) - return MathHelper.lerp(progress, 0.0, 1.0) + return Mth.lerp(progress, 0.0, 1.0) } val progress: Double diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt b/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt index 9450849f..623ef52c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt @@ -15,6 +15,7 @@ object MatrixServerPlayNetworking { PayloadTypeRegistry.serverboundPlay().register(ServerboundWarpPayload.type, ServerboundWarpPayload.codec) PayloadTypeRegistry.serverboundPlay().register(ServerboundActivateBloodPactPayload.type, ServerboundActivateBloodPactPayload.codec) PayloadTypeRegistry.serverboundPlay().register(ServerboundBorrowedTimePayload.type, ServerboundBorrowedTimePayload.codec) + PayloadTypeRegistry.serverboundPlay().register(ServerboundOverclockPayload.type, ServerboundOverclockPayload.codec) PayloadTypeRegistry.clientboundPlay().register(ClientboundSyncManaPayload.type, ClientboundSyncManaPayload.codec) PayloadTypeRegistry.clientboundPlay().register(ClientboundSystemCrashPayload.type, ClientboundSystemCrashPayload.codec) @@ -30,5 +31,6 @@ object MatrixServerPlayNetworking { ServerPlayNetworking.registerGlobalReceiver(ServerboundWarpPayload.type, ServerboundWarpPayload::handle) ServerPlayNetworking.registerGlobalReceiver(ServerboundActivateBloodPactPayload.type, ServerboundActivateBloodPactPayload::handle) ServerPlayNetworking.registerGlobalReceiver(ServerboundBorrowedTimePayload.type, ServerboundBorrowedTimePayload::handle) + ServerPlayNetworking.registerGlobalReceiver(ServerboundOverclockPayload.type, ServerboundOverclockPayload::handle) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt b/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt index 13b348e2..a3f6741b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt @@ -5,6 +5,16 @@ package heckerpowered.matrix.common.combat.damage +import heckerpowered.matrix.extension.MatrixDamageSource import net.minecraft.world.damagesource.DamageSource -class DamageSourceEnvelope(val origin: DamageSource, val rawDamage: Float) : DamageSource(origin.typeRegistryEntry, origin.source, origin.attacker) \ No newline at end of file +class DamageSourceEnvelope( + val origin: DamageSource, + val rawDamage: Float, +) : DamageSource(origin.typeHolder(), origin.getDirectEntity(), origin.getEntity()), MatrixDamageSource { + override var isAdditionalDamage: Boolean + get() = (origin as? MatrixDamageSource)?.isAdditionalDamage ?: false + set(value) { + (origin as? MatrixDamageSource)?.isAdditionalDamage = value + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt b/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt index 629afc54..b1d23eac 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt @@ -6,10 +6,22 @@ package heckerpowered.matrix.common.command import com.mojang.brigadier.Command +import com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg +import com.mojang.brigadier.arguments.DoubleArgumentType.getDouble +import heckerpowered.matrix.common.magic.resource.Mana +import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana +import heckerpowered.matrix.common.magic.system.ManaLedger +import heckerpowered.matrix.common.network.ClientboundSyncManaPayload import heckerpowered.matrix.common.persistent.isInfiniteMana +import heckerpowered.matrix.common.persistent.maxMana +import heckerpowered.matrix.common.persistent.mana import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking +import net.minecraft.commands.Commands.argument import net.minecraft.commands.Commands.hasPermission import net.minecraft.commands.Commands.literal +import net.minecraft.commands.arguments.EntityArgument +import net.minecraft.server.level.ServerPlayer import net.minecraft.server.permissions.PermissionCheck import net.minecraft.server.permissions.Permissions @@ -21,14 +33,56 @@ object MatrixCommands { literal("matrix").then( literal("mana") .requires(hasPermission(PermissionCheck.Require(Permissions.COMMANDS_GAMEMASTER))) - .then(literal("infinite")) - .executes { context -> - val player = context.source.playerOrException - player.isInfiniteMana = !player.isInfiniteMana - return@executes Command.SINGLE_SUCCESS - } + .then( + literal("set") + .then( + argument("amount", doubleArg(0.0)) + .executes { context -> + val player = context.source.playerOrException + setMana(player, getDouble(context, "amount").mana) + return@executes Command.SINGLE_SUCCESS + } + .then( + argument("target", EntityArgument.players()) + .executes { context -> + EntityArgument.getPlayers(context, "target").forEach { player -> + setMana(player, getDouble(context, "amount").mana) + } + return@executes Command.SINGLE_SUCCESS + } + ) + ) + ) + .then( + literal("infinite") + .executes { context -> + val player = context.source.playerOrException + player.isInfiniteMana = !player.isInfiniteMana + if (player.isInfiniteMana) { + ManaLedger.setMana(player, player.maxMana) + } + syncMana(player) + return@executes Command.SINGLE_SUCCESS + } + ) ) ) } } -} \ No newline at end of file + + private fun setMana(player: ServerPlayer, amount: Mana) { + ManaLedger.setMana(player, amount) + syncMana(player) + } + + private fun syncMana(player: ServerPlayer) { + ServerPlayNetworking.send( + player, + ClientboundSyncManaPayload( + player.mana.toDouble(), + player.maxMana.toDouble(), + player.isInfiniteMana, + ), + ) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/effect/ModMobEffects.kt b/common/src/main/kotlin/heckerpowered/matrix/common/effect/ModMobEffects.kt index 141b3b70..9f89a64c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/effect/ModMobEffects.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/effect/ModMobEffects.kt @@ -25,10 +25,16 @@ object ModMobEffects { val Absolvrift = register("absolvrift", AbsolvriftEffect) val HealthShrink = register("health_shrink", HealthShrinkEffect) + val IGNITE_EFFECT get() = Ignite + val WITHER_ARMOR_CHARGED_EFFECT get() = WitherArmorCharged + val WITHER_ARMOR_EFFECT get() = WitherArmor + val ANGERED_EFFECT get() = Angered + val BLOOD_PACT_EFFECT get() = BloodPact + private fun register(name: String, effect: MobEffect): Holder { return Registry.registerForHolder(BuiltInRegistries.MOB_EFFECT, Matrix.identifier(name), effect) } fun onInitialize() { } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/ModEnchantments.kt b/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/ModEnchantments.kt index a982ec85..e7c4bd00 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/ModEnchantments.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/ModEnchantments.kt @@ -57,6 +57,9 @@ object ModEnchantments { @JvmField val BloodPact = createId("blood_pact") + @JvmField + val bloodPact = BloodPact + @JvmField val MagicShield = createId("magic_shield") @@ -114,4 +117,4 @@ fun ItemInstance.getEnchantmentLevel(level: Level, enchantment: ResourceKey): Int { val enchantmentHolder = level().getEnchantmentHolder(enchantmentKey) ?: return 0 return EnchantmentHelper.getEnchantmentLevel(enchantmentHolder, this) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt index 1e1a0a52..3954f71d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt @@ -49,7 +49,7 @@ class AttractorEntity(entityType: EntityType, level: Level) : E get() = entityData.get(AttractorEntity.ownerUuid).getOrNull() set(value) = entityData.set(AttractorEntity.ownerUuid, Optional.ofNullable(value)) - var owner: LivingEntity? + var ownerEntity: LivingEntity? get() = super.getOwner() set(value) { ownerUuid = EntityReference.of(value) @@ -129,4 +129,4 @@ class AttractorEntity(entityType: EntityType, level: Level) : E override fun getOwnerReference(): EntityReference? { return this@AttractorEntity.ownerUuid } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt index a5ab0798..26f5bf87 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt @@ -5,65 +5,71 @@ package heckerpowered.matrix.common.entity -import net.minecraft.entity.EntityType -import net.minecraft.entity.attribute.DefaultAttributeContainer -import net.minecraft.entity.attribute.EntityAttribute -import net.minecraft.entity.attribute.EntityAttributes -import net.minecraft.entity.boss.BossBar -import net.minecraft.entity.boss.ServerBossBar -import net.minecraft.entity.damage.DamageSource -import net.minecraft.entity.mob.PathAwareEntity -import net.minecraft.registry.entry.RegistryEntry -import net.minecraft.server.network.ServerPlayerEntity -import net.minecraft.world.World +import net.minecraft.core.Holder +import net.minecraft.server.level.ServerBossEvent +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.BossEvent +import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.Mob.createMobAttributes +import net.minecraft.world.entity.PathfinderMob +import net.minecraft.world.entity.ai.attributes.Attribute +import net.minecraft.world.entity.ai.attributes.AttributeSupplier +import net.minecraft.world.entity.ai.attributes.Attributes +import net.minecraft.world.level.Level +import heckerpowered.matrix.common.magic.channel.ChannelQueue +import heckerpowered.matrix.extension.MatrixLivingEntity +import java.util.UUID -class DevEntity(entityType: EntityType, world: World) : PathAwareEntity(entityType, world) { +class DevEntity(entityType: EntityType, level: Level) : PathfinderMob(entityType, level), MatrixLivingEntity { + override var polarity: Long = 0L + override var healthSpoofValue: Float = 0.0F + override val channelQueues: MutableMap = mutableMapOf() - private val bossBar = ServerBossBar(this.displayName, BossBar.Color.BLUE, BossBar.Style.NOTCHED_20) + private val bossBar = ServerBossEvent(uuid, displayName, BossEvent.BossBarColor.BLUE, BossEvent.BossBarOverlay.NOTCHED_20) - constructor(world: World) : this(ModEntityTypes.devEntity, world) + constructor(level: Level) : this(ModEntityTypes.devEntity, level) companion object { const val HEALTH_SCALE = 10000000.0 - fun createDevAttributes(): DefaultAttributeContainer.Builder { + fun createDevAttributes(): AttributeSupplier.Builder { return createMobAttributes() - .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 35.0) - .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.23) - .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 20.0) - .add(EntityAttributes.GENERIC_ARMOR, 20.0) - .add(EntityAttributes.GENERIC_ARMOR_TOUGHNESS, 2.0) - .add(EntityAttributes.GENERIC_MAX_HEALTH, 1000.0 * HEALTH_SCALE) - .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 1.0) - .add(EntityAttributes.ZOMBIE_SPAWN_REINFORCEMENTS) + .add(Attributes.FOLLOW_RANGE, 35.0) + .add(Attributes.MOVEMENT_SPEED, 0.23) + .add(Attributes.ATTACK_DAMAGE, 20.0) + .add(Attributes.ARMOR, 20.0) + .add(Attributes.ARMOR_TOUGHNESS, 2.0) + .add(Attributes.MAX_HEALTH, 1000.0 * HEALTH_SCALE) + .add(Attributes.KNOCKBACK_RESISTANCE, 1.0) + .add(Attributes.SPAWN_REINFORCEMENTS_CHANCE) } } - override fun damage(source: DamageSource, amount: Float): Boolean { - return super.damage(source, amount) + override fun hurtServer(level: net.minecraft.server.level.ServerLevel, source: DamageSource, damage: Float): Boolean { + return super.hurtServer(level, source, damage) } - override fun getAttributeValue(attribute: RegistryEntry): Double { - if (attribute == EntityAttributes.GENERIC_MAX_HEALTH) { + override fun getAttributeValue(attribute: Holder): Double { + if (attribute == Attributes.MAX_HEALTH) { return 1000.0 * HEALTH_SCALE } return super.getAttributeValue(attribute) } - override fun mobTick() { - super.mobTick() + override fun customServerAiStep(level: net.minecraft.server.level.ServerLevel) { + super.customServerAiStep(level) - bossBar.setPercent(health / maxHealth) + bossBar.progress = health / maxHealth } - override fun onStartedTrackingBy(player: ServerPlayerEntity?) { - super.onStartedTrackingBy(player) + override fun startSeenByPlayer(player: ServerPlayer) { + super.startSeenByPlayer(player) bossBar.addPlayer(player) } - override fun onStoppedTrackingBy(player: ServerPlayerEntity?) { - super.onStoppedTrackingBy(player) + override fun stopSeenByPlayer(player: ServerPlayer) { + super.stopSeenByPlayer(player) bossBar.removePlayer(player) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt index ddc520bd..d875f0ca 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt @@ -7,51 +7,44 @@ package heckerpowered.matrix.common.entity import heckerpowered.matrix.common.entity.ModEntityTypes.FINDER_ARROW_ENTITY import heckerpowered.matrix.common.item.FinderArrowItem -import heckerpowered.matrix.core.squaredDistanceTo -import net.minecraft.core.SectionPos.y -import net.minecraft.core.SectionPos.z -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.effect.StatusEffectInstance -import net.minecraft.entity.effect.StatusEffects -import net.minecraft.entity.projectile.PersistentProjectileEntity -import net.minecraft.item.ItemStack -import net.minecraft.particle.ParticleTypes -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import net.minecraft.util.math.Vec3d -import net.minecraft.world.World -import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom.pos +import net.minecraft.core.BlockPos +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.projectile.arrow.AbstractArrow +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.Level +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 -class FinderArrowEntity : PersistentProjectileEntity { - constructor(world: World, owner: LivingEntity, stack: ItemStack, shotFrom: ItemStack?) : super(FINDER_ARROW_ENTITY, owner, world, stack, shotFrom) - constructor(world: World) : super(FINDER_ARROW_ENTITY, world) +class FinderArrowEntity : AbstractArrow { + constructor(level: Level, owner: LivingEntity, stack: ItemStack, shotFrom: ItemStack?) : super(FINDER_ARROW_ENTITY, owner, level, stack, shotFrom) + constructor(level: Level) : super(FINDER_ARROW_ENTITY, level) + constructor(entityType: EntityType, level: Level) : super(entityType, level) override fun tick() { super.tick() - if (world.isClient && !inGround) { - world.addParticle(ParticleTypes.INSTANT_EFFECT, x, y, z, 0.0, 0.0, 0.0) - } - - if (inGround) { + if (isInGround) { return } - val previousPosition = Vec3d(prevX, prevY, prevZ) - val currentPosition = pos - val searchBox = Box(previousPosition, currentPosition).expand(12.0, 9999.0, 12.0) - world.getOtherEntities(owner, searchBox) + val previousPosition = Vec3(xo, yo, zo) + val currentPosition = position() + val searchBox = AABB(previousPosition, currentPosition).inflate(12.0, 9999.0, 12.0) + level().getEntities(getOwner(), searchBox) { true } .filterIsInstance() .filter { - val blockPos = BlockPos.ofFloored(it.x, it.y, it.z) - this squaredDistanceTo it <= 144 // 144 = 12 * 12 (radius) - || it.world.isSkyVisible(blockPos) + val blockPos = BlockPos.containing(it.position()) + distanceToSqr(it) <= 144 // 144 = 12 * 12 (radius) + || level().canSeeSky(blockPos) } .forEach { - val statusEffectInstance = StatusEffectInstance(StatusEffects.GLOWING, 20 * 5, 0) - it.addStatusEffect(statusEffectInstance, effectCause) + val statusEffectInstance = MobEffectInstance(MobEffects.GLOWING, 20 * 5, 0) + it.addEffect(statusEffectInstance, this) } } - override fun getDefaultItemStack(): ItemStack { + override fun getDefaultPickupItem(): ItemStack { return ItemStack(FinderArrowItem) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt index 51578b02..51f42209 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt @@ -5,19 +5,6 @@ package heckerpowered.matrix.common.entity -import net.minecraft.entity.EntityType -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.data.DataTracker -import net.minecraft.entity.projectile.ProjectileEntity -import net.minecraft.item.ItemStack -import net.minecraft.world.World +import net.minecraft.world.item.ItemStack -class ItemProjectileEntity(entityType: EntityType, world: World, owner: LivingEntity?, var stack: ItemStack) : ProjectileEntity(entityType, world) { - init { - this.owner = owner - } - - override fun initDataTracker(builder: DataTracker.Builder) { - - } -} \ No newline at end of file +class ItemProjectileEntity(var stack: ItemStack) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt index 81f34bf8..25e1c971 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt @@ -6,9 +6,9 @@ package heckerpowered.matrix.common.entity import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.common.effect.ModMobEffects.ARMOR_PENETRATION_EFFECT -import heckerpowered.matrix.common.effect.ModMobEffects.CRIPPLE_MOVEMENT_EFFECT -import heckerpowered.matrix.common.effect.ModMobEffects.EXPOSED_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects.ArmorPenetration +import heckerpowered.matrix.common.effect.ModMobEffects.CrippleMovement +import heckerpowered.matrix.common.effect.ModMobEffects.Exposed import heckerpowered.matrix.common.entity.MagicLightningBolt.LightningType.* import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.ExecutionPolicy @@ -21,6 +21,8 @@ import heckerpowered.matrix.core.extension.damage import net.minecraft.network.protocol.game.ClientboundAddEntityPacket import net.minecraft.server.level.ServerLevel import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects import net.minecraft.world.entity.Entity import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.LightningBolt @@ -58,38 +60,38 @@ class MagicLightningBolt(entityType: EntityType, level: Leve constructor(level: Level) : this(ModEntityTypes.MAGIC_LIGHTNING_ENTITY, level) private fun onStruckByLightning(entity: Entity) { - ++entity.fireTicks - if (entity.fireTicks == 0) { - entity.setOnFireFor(8.0f) + entity.remainingFireTicks = entity.remainingFireTicks + 1 + if (entity.remainingFireTicks == 0) { + entity.igniteForSeconds(8.0f) } - val channeler = this.channeler + val channeler = this.cause val damageSource = if (channeler != null) { - channeler.world.damageSources.create(MatrixDamageTypes.magic, channeler) + channeler.level().damageSources().source(MatrixDamageTypes.magic, channeler) } else { - damageSources.generic() + damageSources().generic() } when (lightningType) { NORMAL -> performNormalStrike(entity) RED -> entity.damage(damageSource, 20.0F) ORANGE -> { if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(ARMOR_PENETRATION_EFFECT, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(ArmorPenetration, 20 * 10, 4)) } entity.damage(damageSource, 5.0F) } YELLOW -> { channeler?.apply { - lastAttackedTicks = Int.MAX_VALUE - swingHand(activeHand) + attackStrengthTicker = Int.MAX_VALUE + swing(usedItemHand) attack(entity) - addCritParticles(entity) - addEnchantedHitParticles(entity) + crit(entity) + magicCrit(entity) } entity.damage(damageSource, 5.0F) if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 20 * 10, 0)) + entity.addEffect(MobEffectInstance(MobEffects.GLOWING, 20 * 10, 0)) } } @@ -97,18 +99,17 @@ class MagicLightningBolt(entityType: EntityType, level: Leve channeler?.heal(2F) entity.damage(damageSource, 5.0F) if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(StatusEffects.POISON, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(MobEffects.POISON, 20 * 10, 4)) } } CYAN -> { if (entity is LivingEntity) { - if (entity.hasStatusEffect(CRIPPLE_MOVEMENT_EFFECT)) { - entity.addStatusEffect(StatusEffectInstance(EXPOSED_EFFECT, 20 * 10, 0)) + if (entity.hasEffect(CrippleMovement)) { + entity.addEffect(MobEffectInstance(Exposed, 20 * 10, 0)) } - val channeler = channeler if (channeler == null) { - entity.addStatusEffect(StatusEffectInstance(CRIPPLE_MOVEMENT_EFFECT, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(CrippleMovement, 20 * 10, 4)) } else { val invocation = MagicInvocation.fromEntity(channeler, entity) val attempt = ExecutionPolicy(costMana = false) @@ -123,7 +124,7 @@ class MagicLightningBolt(entityType: EntityType, level: Leve return } - for (target in entity.world.getOtherEntities(entity, entity.boundingBox.expand(6.0))) { + for (target in entity.level().getEntities(entity, entity.boundingBox.inflate(6.0))) { if (target !is LivingEntity) { continue } @@ -135,12 +136,12 @@ class MagicLightningBolt(entityType: EntityType, level: Leve PURPLE -> { entity.damage(damageSource, 5F) - world.createExplosion(entity, damageSource, damageCalculator, entity.x, entity.y, entity.z, 1.0F, false, World.ExplosionSourceType.MOB) + entity.level().explode(entity, damageSource, damageCalculator, entity.x, entity.y, entity.z, 1.0F, false, Level.ExplosionInteraction.MOB) // TODO: add status effect } BLACK -> { - entity.kill() + (entity.level() as? ServerLevel)?.let(entity::kill) } } } @@ -166,9 +167,9 @@ class MagicLightningBolt(entityType: EntityType, level: Leve private fun performOrangeStrike(entity: Entity) { if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(ARMOR_PENETRATION_EFFECT, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(ArmorPenetration, 20 * 10, 4)) } - entity.damage(damageSource, 5.0F) + entity.damage(damageSource(), 5.0F) } override fun recreateFromPacket(packet: ClientboundAddEntityPacket) { @@ -180,4 +181,4 @@ class MagicLightningBolt(entityType: EntityType, level: Leve lightningType = lightningTypes[lightningTypeOrdinal] } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt index 116a9f4a..8467e69e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt @@ -18,13 +18,14 @@ import net.minecraft.world.entity.MobCategory object ModEntityTypes { val MAGIC_LIGHTNING_ENTITY: EntityType = Registry.register( - Registries.ENTITY_TYPE, Matrix.identifier("magic_lightning"), - EntityType.Builder.create({ entityType, world -> MagicLightningBolt(entityType, world) }, SpawnGroup.MISC) - .disableSaving() - .dimensions(0.0F, 0.0F) - .maxTrackingRange(16) - .trackingTickInterval(Integer.MAX_VALUE) - .build() + BuiltInRegistries.ENTITY_TYPE, + ResourceKey.create(Registries.ENTITY_TYPE, Matrix.identifier("magic_lightning")), + EntityType.Builder.of(::MagicLightningBolt, MobCategory.MISC) + .noSave() + .sized(0.0F, 0.0F) + .clientTrackingRange(16) + .updateInterval(Integer.MAX_VALUE) + .build(ResourceKey.create(Registries.ENTITY_TYPE, Matrix.identifier("magic_lightning"))) ) val attractor = register( @@ -38,22 +39,24 @@ object ModEntityTypes { ) val FINDER_ARROW_ENTITY: EntityType = Registry.register( - Registries.ENTITY_TYPE, Matrix.identifier("finder_arrow"), - EntityType.Builder.create({ entityType, world -> FinderArrowEntity(world) }, SpawnGroup.MISC) - .dimensions(0.5F, 0.5F) + BuiltInRegistries.ENTITY_TYPE, + ResourceKey.create(Registries.ENTITY_TYPE, Matrix.identifier("finder_arrow")), + EntityType.Builder.of({ entityType, level -> FinderArrowEntity(entityType, level) }, MobCategory.MISC) + .sized(0.5F, 0.5F) .eyeHeight(0.13F) - .maxTrackingRange(4) - .trackingTickInterval(20) - .build() + .clientTrackingRange(4) + .updateInterval(20) + .build(ResourceKey.create(Registries.ENTITY_TYPE, Matrix.identifier("finder_arrow"))) ) val devEntity: EntityType = Registry.register( - Registries.ENTITY_TYPE, Matrix.identifier("dev"), - EntityType.Builder.create({ entityType, world -> DevEntity(world) }, SpawnGroup.CREATURE) - .dimensions(0.6f, 1.95f) + BuiltInRegistries.ENTITY_TYPE, + ResourceKey.create(Registries.ENTITY_TYPE, Matrix.identifier("dev")), + EntityType.Builder.of(::DevEntity, MobCategory.CREATURE) + .sized(0.6f, 1.95f) .eyeHeight(1.74F) - .maxTrackingRange(8) - .build() + .clientTrackingRange(8) + .build(ResourceKey.create(Registries.ENTITY_TYPE, Matrix.identifier("dev"))) ) private fun register(name: String, builder: EntityType.Builder): EntityType { @@ -64,4 +67,4 @@ object ModEntityTypes { fun onInitialize() { FabricDefaultAttributeRegistry.register(devEntity, DevEntity.createDevAttributes()) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt index e4b272f4..df592bd7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.AxeItem object CoalAxeItem : AxeItem( ModToolMaterials.coal, 6.5F, -3.15F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalAxe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt index 4abf3089..6b8f4752 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object CoalBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.BOOTS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalBoots).humanoidArmor(ModArmorMaterials.coal, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt index 67956244..973ae01a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object CoalChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.CHESTPLATE) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalChestplate).humanoidArmor(ModArmorMaterials.coal, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt index 01c7447e..c00796eb 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object CoalHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.HELMET) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalHelmet).humanoidArmor(ModArmorMaterials.coal, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt index 815757f4..43bf8336 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.HoeItem object CoalHoeItem : HoeItem( ModToolMaterials.coal, -1.5F, -1.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalHoe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt index 4f4cc246..89e87ed5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.ToolMaterial import net.minecraft.world.item.equipment.ArmorType object CoalLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.LEGGINGS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalLeggings).humanoidArmor(ModArmorMaterials.coal, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt index 4d3ec29f..c0485b9c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt @@ -8,5 +8,5 @@ package heckerpowered.matrix.common.item import net.minecraft.world.item.Item object CoalPickaxeItem : Item( - Properties().pickaxe(ModToolMaterials.coal, 1.0F, -2.8F) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalPickaxe).pickaxe(ModToolMaterials.coal, 1.0F, -2.8F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt index cc3b2a77..26cdb447 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.ShovelItem object CoalShovelItem : ShovelItem( ModToolMaterials.coal, 1.5F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalShovel) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt index 490a3de2..ee4c5552 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt @@ -8,5 +8,5 @@ package heckerpowered.matrix.common.item import net.minecraft.world.item.Item object CoalSwordItem : Item( - Properties().sword(ModToolMaterials.coal,3.0F, -2.4F) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.coalSword).sword(ModToolMaterials.coal,3.0F, -2.4F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt index 601e12c4..86043928 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.AxeItem object EmeraldAxeItem : AxeItem( ModToolMaterials.emerald, 5.0F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldAxe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt index 8cfd9908..ad0532a5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.BOOTS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldBoots).humanoidArmor(ModArmorMaterials.emerald, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt index 071eb868..0b68ce4a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.CHESTPLATE) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldChestplate).humanoidArmor(ModArmorMaterials.emerald, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt index ce915eff..657515d7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.HELMET) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldHelmet).humanoidArmor(ModArmorMaterials.emerald, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt index d81c73d7..18b29143 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.HoeItem object EmeraldHoeItem : HoeItem( ModToolMaterials.emerald, -3.5F, 0.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldHoe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt index fc18ac82..9bf56264 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.LEGGINGS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldLeggings).humanoidArmor(ModArmorMaterials.emerald, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt index af2686ca..ec34f2f1 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt @@ -8,5 +8,5 @@ package heckerpowered.matrix.common.item import net.minecraft.world.item.Item object EmeraldPickaxeItem : Item( - Properties().pickaxe(ModToolMaterials.emerald, 1.0F, -2.8F) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldPickaxe).pickaxe(ModToolMaterials.emerald, 1.0F, -2.8F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt index e67aa1e9..51ec9377 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.ShovelItem object EmeraldShovelItem : ShovelItem( ModToolMaterials.emerald, 1.5F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldShovel) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt index d958a0c2..62eeb82c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt @@ -8,5 +8,5 @@ package heckerpowered.matrix.common.item import net.minecraft.world.item.Item object EmeraldSwordItem : Item( - Properties().sword(ModToolMaterials.emerald,3.0F, -2.4F) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.emeraldSword).sword(ModToolMaterials.emerald,3.0F, -2.4F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt index 63726808..ea51d84f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt @@ -12,7 +12,7 @@ import net.minecraft.world.item.ArrowItem import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level -object FinderArrowItem : ArrowItem(Properties()) { +object FinderArrowItem : ArrowItem(Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.finderArrow)) { override fun createArrow(level: Level, itemStack: ItemStack, owner: LivingEntity, firedFromWeapon: ItemStack?): AbstractArrow { return FinderArrowEntity(level, owner, itemStack.copyWithCount(1), firedFromWeapon) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt index 815d4e23..096080a4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.AxeItem object LapisLazuliAxeItem : AxeItem( ModToolMaterials.lapisLazuli, 6.0F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliAxe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt index ea037bde..179e94e7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object LapisLazuliBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.BOOTS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliBoots).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt index efa7c9d6..13754859 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.ToolMaterial import net.minecraft.world.item.equipment.ArmorType object LapisLazuliChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.CHESTPLATE) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliChestplate).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt index 50eb0537..bd72f40c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object LapisLazuliHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.HELMET) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliHelmet).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt index eb02a1aa..caa7b1f4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.HoeItem object LapisLazuliHoeItem : HoeItem( ModToolMaterials.lapisLazuli, -2.0F, -1.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliHoe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt index a44e7e80..dc88f737 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object LapisLazuliLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.LEGGINGS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliLeggings).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt index 6c6b1002..4a16feba 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt @@ -8,5 +8,5 @@ package heckerpowered.matrix.common.item import net.minecraft.world.item.Item object LapisLazuliPickaxeItem : Item( - Properties().pickaxe(ModToolMaterials.lapisLazuli, 1.0F, -2.8F) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliPickaxe).pickaxe(ModToolMaterials.lapisLazuli, 1.0F, -2.8F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt index df8f5a5a..9608bfb4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt @@ -10,5 +10,5 @@ import net.minecraft.world.item.ShovelItem object LapisLazuliShovelItem : ShovelItem( ModToolMaterials.lapisLazuli, 1.5F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliShovel) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt index 13ecfe84..0b0dc0d6 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt @@ -15,7 +15,7 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack object LapisLazuliSwordItem : Item( - Properties().sword(ModToolMaterials.lapisLazuli, 3.0F, -2.4F) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lapisLazuliSword).sword(ModToolMaterials.lapisLazuli, 3.0F, -2.4F) ) { override fun postHurtEnemy(itemStack: ItemStack, mob: LivingEntity, attacker: LivingEntity) { super.postHurtEnemy(itemStack, mob, attacker) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt index 0bf65651..779e3a45 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt @@ -38,7 +38,7 @@ import java.util.function.Consumer * Lightning Chestplate 1 'Warp Dancer' */ object LightningChestplate1 : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.lightningChestplateBorrowedTime) .humanoidArmor(ModArmorMaterials.lightning, ArmorType.CHESTPLATE) .fireResistant() .rarity(Rarity.EPIC) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt index abdfe368..a4690c4f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt @@ -14,7 +14,7 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.Rarity object MagicTalismanItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.magicTalisman) .fireResistant() .stacksTo(1) .rarity(Rarity.EPIC) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt index a480d84c..f5cc48cc 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt @@ -21,7 +21,7 @@ import net.minecraft.world.level.Level import kotlin.time.Duration.Companion.minutes object MetaBowItem : BowItem( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.metaBow) .durability(3840) .component(shootPerMinute, 3600) ) { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt index d44451b0..43c4e12e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt @@ -24,7 +24,7 @@ import java.util.function.Consumer object RedstoneAxeItem : AxeItem( ModToolMaterials.redstone, 5.0F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneAxe) .component(redstoneSuitPower, 20) .component(redstoneSuitMaxPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt index c2d1b77d..6b0151aa 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt @@ -18,7 +18,7 @@ import net.minecraft.world.item.equipment.ArmorType import java.util.function.Consumer object RedstoneBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.redstone, ArmorType.BOOTS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneBoots).humanoidArmor(ModArmorMaterials.redstone, ArmorType.BOOTS) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt index ccfe0cfd..ec472bd7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt @@ -24,7 +24,7 @@ import java.util.function.Consumer import kotlin.math.ceil object RedstoneChestplateItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneChestplate) .humanoidArmor(ModArmorMaterials.redstone, ArmorType.CHESTPLATE) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt index 23c4f3cf..bdeb1cb4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt @@ -25,7 +25,7 @@ import net.minecraft.world.item.equipment.ArmorType import java.util.function.Consumer object RedstoneHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.redstone, ArmorType.HELMET) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneHelmet).humanoidArmor(ModArmorMaterials.redstone, ArmorType.HELMET) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), EntityUpdateRule, RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt index a26ed39c..fa7be857 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt @@ -23,7 +23,7 @@ import java.util.function.Consumer object RedstoneHoeItem : HoeItem( ModToolMaterials.redstone, -2.0F, -1.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneHoe) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt index e9ea01d5..5058fdc5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt @@ -27,7 +27,7 @@ import net.minecraft.world.item.equipment.ArmorType import java.util.function.Consumer object RedstoneLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.redstone, ArmorType.LEGGINGS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneLeggings).humanoidArmor(ModArmorMaterials.redstone, ArmorType.LEGGINGS) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider, DamageOutcomeRule { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt index 3e478507..3fe1732d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt @@ -22,7 +22,7 @@ import net.minecraft.world.level.block.state.BlockState import java.util.function.Consumer object RedstonePickaxeItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstonePickaxe) .pickaxe(ModToolMaterials.redstone, 1.0F, -2.8F) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt index 2e963975..695c1879 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt @@ -23,7 +23,7 @@ import java.util.function.Consumer object RedstoneShovelItem : ShovelItem( ModToolMaterials.redstone, 1.5F, -3.0F, - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneShovel) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt index f86fa04f..9f038f41 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt @@ -23,7 +23,7 @@ import net.minecraft.world.item.component.TooltipProvider import java.util.function.Consumer object RedstoneSwordItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.redstoneSword) .sword(ModToolMaterials.redstone, 3.0F, -2.4F) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt index c776d9ff..0328a439 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.BOOTS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.stoneBoots).humanoidArmor(ModArmorMaterials.stone, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt index 88e3220a..3293d413 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.CHESTPLATE) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.stoneChestplate).humanoidArmor(ModArmorMaterials.stone, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt index 2f94dd68..3e9e15d4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.HELMET) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.stoneHelmet).humanoidArmor(ModArmorMaterials.stone, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt index b1cf30f4..66484df8 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt @@ -9,5 +9,5 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.LEGGINGS) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.stoneLeggings).humanoidArmor(ModArmorMaterials.stone, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt index 6a8b918a..c7d6a270 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt @@ -28,7 +28,7 @@ import java.util.function.Consumer // TODO: EntityPolarity // TODO: Restrict negative effects object WardenChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.warden, ArmorType.CHESTPLATE) + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wardenChestplate).humanoidArmor(ModArmorMaterials.warden, ArmorType.CHESTPLATE) .fireResistant() .rarity(Rarity.EPIC) ), TooltipProvider, DamageComputationRule, KnockbackRule { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt index 4143d3ff..39c8c0b2 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt @@ -56,8 +56,10 @@ open class WizardHelmet(properties: Properties) : Item( override fun onEquipItem(context: EquipItemContext) { val entity = context.entity as? ServerPlayer ?: return - val stack = context.stack + syncManaBounds(entity, context.stack) + } + fun syncManaBounds(entity: ServerPlayer, stack: ItemStack = entity.wizardHelmetStack) { val item = stack.item val maxMana = if (item is WizardHelmet) item.getMaxMana(entity, stack).mana else .0.mana val account = ManaLedger.account(entity) @@ -170,4 +172,4 @@ fun Item.Properties.maxMana(value: Double): Item.Properties { fun Item.Properties.maxLoad(value: Double): Item.Properties { component(ModComponents.maxLoad, value) return this -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt index bea99769..9765dbaf 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt @@ -11,7 +11,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 1 'Basic' */ object WizardHelmet1 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet1) .rarity(Rarity.COMMON) .maxMana(8.0) .maxLoad(105.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt index 389c89d7..86a55a4c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt @@ -22,7 +22,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity object WizardHelmet10 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet10) .fireResistant() .rarity(Rarity.EPIC) .maxMana(12.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt index adee2cd4..a4eba000 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt @@ -41,7 +41,7 @@ import kotlin.math.floor * Wizard Helmet 13 'Overflux Crown' */ object WizardHelmet13 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet13) .fireResistant() .rarity(Rarity.EPIC) .maxMana(12.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt index a28fe887..7ca03ce5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt @@ -11,7 +11,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 2 'Ruin' */ object WizardHelmet2 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet2) .rarity(Rarity.COMMON) .maxMana(9.0) .maxLoad(110.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt index 327dbe29..9fad257f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt @@ -19,7 +19,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 3 'Blood-forged Ruin' */ object WizardHelmet3 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet3) .rarity(Rarity.UNCOMMON) .maxMana(10.0) .maxLoad(200.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt index 9e47e3b0..09d35d27 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt @@ -19,7 +19,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 4 'Might and Method' */ object WizardHelmet4 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet4) .rarity(Rarity.RARE) .maxMana(11.0) .maxLoad(120.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt index aa1773e4..fc1478a5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt @@ -24,7 +24,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 5 'Axiom of Annihilation' */ object WizardHelmet5 : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmet5) .rarity(Rarity.EPIC) .maxMana(12.0) .maxLoad(125.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt index e42943e2..29a791f3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt @@ -13,7 +13,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity object WizardHelmetHacker : WizardHelmet( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.wizardHelmetHacker) .rarity(Rarity.EPIC) ) { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt index 5a0a2ec8..ea43fceb 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt @@ -9,6 +9,6 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenBootsItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.woodenBoots) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt index 4f7c01d5..20952006 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt @@ -9,6 +9,6 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenChestplateItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.woodenChestplate) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt index 70ab7e04..63b56659 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt @@ -9,6 +9,6 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenHelmetItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.woodenHelmet) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt index 2e8dfc9e..3928b2df 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt @@ -9,6 +9,6 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenLeggingsItem : Item( - Properties() + Properties().setId(heckerpowered.matrix.common.reference.ModItemIds.woodenLeggings) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelEntry.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelEntry.kt index 28658085..a758eb3f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelEntry.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelEntry.kt @@ -10,6 +10,7 @@ import heckerpowered.matrix.common.magic.core.Magic import kotlinx.serialization.Contextual import kotlinx.serialization.Polymorphic import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient @Serializable data class ChannelEntry( @@ -18,4 +19,7 @@ data class ChannelEntry( val channelTime: Long, var currentChannelTime: Long = 0, @Polymorphic val payload: ExecutionPayload = ExecutionPayload(), -) \ No newline at end of file +) { + @Transient + var clientPrediction: Boolean = false +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt index 183f5e65..032e2d4f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt @@ -64,12 +64,12 @@ object ChannelExecutor { ChannelSequenceRenderer .channelSequenceAnimationMap .computeIfAbsent(target) { mutableListOf() } - .add(ChannelAnimation(magic.magic).also { + .add(ChannelAnimation(magic.magic, magic).also { it.channelTime = channelTime - it.currentChannelTime = currentChannelTime + it.currentChannelTime = currentChannelTime.toDouble() it.initialProgressOffset = Minecraft.getInstance().deltaTracker.getGameTimeDeltaPartialTick(true) }) ChannelSequenceRenderer.offsetAnimationMap - .computeIfAbsent(target) { ChannelSequenceRenderer.Companion.OffsetAnimation() } + .computeIfAbsent(target) { ChannelSequenceRenderer.OffsetAnimation() } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ExecutionPolicy.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ExecutionPolicy.kt index 73448a38..b3eb0bc9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ExecutionPolicy.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ExecutionPolicy.kt @@ -48,7 +48,7 @@ open class ExecutionPolicy( if (bypassLock) { ignoredStatuses += MagicAvailableStatus.ChannelQueueLocked } - if (costMana) { + if (!costMana) { ignoredStatuses += MagicAvailableStatus.InsufficientMana } return ignoredStatuses @@ -98,4 +98,4 @@ open class ExecutionPolicy( ServerPlayNetworking.send(caster, ClientboundSyncHealthPayload(caster)) return result } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt index dc769599..cb8d9a1f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt @@ -17,6 +17,7 @@ import heckerpowered.matrix.common.magic.rule.effect.MagicCastPipeline import heckerpowered.matrix.common.magic.rule.effect.MagicChannelPipeline import heckerpowered.matrix.common.magic.rule.resource.CastingResourcePipeline import heckerpowered.matrix.common.persistent.queueSize +import heckerpowered.matrix.core.isInfiniteMana import net.minecraft.core.Holder import net.minecraft.world.Difficulty import net.minecraft.world.effect.MobEffect @@ -178,6 +179,9 @@ abstract class Magic(val definition: MagicDefinition) { * @return true if the required cost can be satisfied; false otherwise. */ protected open fun checkMana(context: MagicCalculationContext): Boolean { + if (context.playerOrNull()?.isInfiniteMana == true) { + return true + } val requiredCost = getCost(context).mana val resourceSet = CastingResourcePipeline.collect(context) return resourceSet.canAfford(context, requiredCost) @@ -236,8 +240,9 @@ abstract class Magic(val definition: MagicDefinition) { // Cost = (BaseCost + MagicResistance) * (1.0 - CostReduction) val baseCost = getBaseCost(context).toDouble() val costReduction = sink.costReduction + val costMultiplier = sink.costMultiplier val magicResistance = sink.magicResistance - return ceil((baseCost + magicResistance) * (1.0 - costReduction)).toLong().coerceAtLeast(0) + return ceil((baseCost + magicResistance) * costMultiplier * (1.0 - costReduction)).toLong().coerceAtLeast(0) } /** @@ -283,4 +288,4 @@ fun LivingEntity.isInvulnerableToEffect(effect: Holder): Boolean { this is EnderDragon -> true else -> false } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/rule/calculation/sink/CostCalculationSink.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/rule/calculation/sink/CostCalculationSink.kt index 33384cec..89f128b5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/rule/calculation/sink/CostCalculationSink.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/rule/calculation/sink/CostCalculationSink.kt @@ -7,5 +7,6 @@ package heckerpowered.matrix.common.magic.rule.calculation.sink class CostCalculationSink : MagicCalculationSink { var costReduction: Double = 0.0 + var costMultiplier: Double = 1.0 var magicResistance: Double = 0.0 -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt index 5a05148a..855f6684 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt @@ -28,7 +28,7 @@ object AttractMagic : Magic( val caster = invocation.caster.entityOrNull() target.level().addFreshEntity(AttractorEntity(target.level()).also { it.setPos(target.position()) - it.owner = caster + it.ownerEntity = caster }) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueuePersistenceRule.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueuePersistenceRule.kt index 5bfab9fa..9724e453 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueuePersistenceRule.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueuePersistenceRule.kt @@ -70,4 +70,4 @@ object ChannelQueuePersistenceRule : LivingPersistenceRule { } } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueueTicker.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueueTicker.kt index beda1183..13bb4de9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueueTicker.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ChannelQueueTicker.kt @@ -7,6 +7,7 @@ package heckerpowered.matrix.common.magic.system import heckerpowered.matrix.common.entity.rule.EntityUpdateContext import heckerpowered.matrix.common.entity.rule.EntityUpdateRule +import heckerpowered.matrix.common.magic.channel.ChannelEntry import heckerpowered.matrix.common.magic.channel.MagicInvocation import heckerpowered.matrix.common.magic.channel.resolveCaster import heckerpowered.matrix.common.magic.channel.tryResolve @@ -27,16 +28,16 @@ object ChannelQueueTicker : EntityUpdateRule { for (queue in entity.channelQueues.values) { val entry = queue.tick() ?: continue - - // Both client and server advance channel queues locally. - // The client uses this for prediction / UI progress only. - // Only the server commits completed channels and runs cast effects. if (entity.level() !is ServerLevel) continue - val target = queue.target - val caster = queue.resolveCaster() - val invocation = MagicInvocation(caster.tryResolve(), target, queue, entry.payload) - entry.magic.cast(invocation) + completeChannel(queue, entry) } } -} \ No newline at end of file + + private fun completeChannel(queue: heckerpowered.matrix.common.magic.channel.ChannelQueue, entry: ChannelEntry) { + val target = queue.target + val caster = queue.resolveCaster() + val invocation = MagicInvocation(caster.tryResolve(), target, queue, entry.payload) + entry.magic.cast(invocation) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt index fab10e8b..4be2aaaa 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt @@ -13,9 +13,12 @@ import net.minecraft.world.entity.LivingEntity object MagicSystem { fun onInitialize() { + Magics.onInitialize() ChannelQueuePersistenceRule.onInitialize() + ManaPersistenceRule.onInitialize() ChannelQueueTicker.onInitialize() ManaRegenerationTicker.onInitialize() + PlayerOverclockState.onInitialize() } @JvmStatic diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt index 88bc6b0f..907d8545 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt @@ -34,6 +34,17 @@ object ManaLedger { return transferMana(account, Authority, amount) } + fun setMana(target: LivingEntity, amount: Mana) { + val clampedAmount = amount.toDouble().coerceAtLeast(.0).mana + val currentMana = mana(target) + val difference = clampedAmount.toDouble() - currentMana.toDouble() + if (difference > .0) { + issueMana(target, difference.mana) + } else if (difference < .0) { + extinguishMana(target, (-difference).mana) + } + } + private fun transferMana(from: LedgerAccount, to: LedgerAccount, amount: Mana): TransactionResult { val ledgerAmount = amount.toLedgerUnits() return from.postTransfer(to, ledgerAmount) @@ -66,4 +77,4 @@ object ManaLedger { .setScale(0, RoundingMode.HALF_UP) .longValueExact() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaPersistenceRule.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaPersistenceRule.kt new file mode 100644 index 00000000..03c30a94 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaPersistenceRule.kt @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.magic.system + +import heckerpowered.matrix.common.entity.rule.LivingLoadContext +import heckerpowered.matrix.common.entity.rule.LivingPersistenceRule +import heckerpowered.matrix.common.entity.rule.LivingSaveContext +import heckerpowered.matrix.common.item.WizardHelmet +import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana +import heckerpowered.matrix.common.rule.RuleRegistry +import heckerpowered.matrix.common.rule.register +import net.minecraft.server.level.ServerPlayer + +object ManaPersistenceRule : LivingPersistenceRule { + private const val MANA_KEY = "matrix_mana" + + init { + RuleRegistry.register(this) + } + + fun onInitialize() { + } + + override fun save(context: LivingSaveContext) { + val player = context.entity as? ServerPlayer ?: return + val mana = ManaLedger.mana(player).toDouble() + if (mana.isFinite()) { + context.output.putDouble(MANA_KEY, mana) + } + } + + override fun load(context: LivingLoadContext) { + val player = context.entity as? ServerPlayer ?: return + val mana = context.input.getDoubleOr(MANA_KEY, .0) + if (!mana.isFinite()) { + return + } + + WizardHelmet.syncManaBounds(player) + ManaLedger.setMana(player, mana.mana) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt index 7002c186..70d9b12b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt @@ -12,6 +12,7 @@ import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana import heckerpowered.matrix.common.magic.rule.calculation.pipeline.CalculationPipeline import heckerpowered.matrix.common.magic.rule.calculation.sink.ManaRegenerationCalculationSink import heckerpowered.matrix.common.magic.system.ManaLedger.toLedgerUnits +import heckerpowered.matrix.common.item.WizardHelmet import heckerpowered.matrix.common.network.ClientboundSyncManaPayload import heckerpowered.matrix.core.isInfiniteMana import heckerpowered.matrix.core.mana @@ -30,6 +31,7 @@ object ManaRegenerationTicker { if (minecraftServer.tickCount % 20 != 0) return for (player in minecraftServer.playerList.players) { + WizardHelmet.syncManaBounds(player) regenerateMana(player) syncMana(player) } @@ -39,6 +41,7 @@ object ManaRegenerationTicker { val account = ManaLedger.account(player) if (player.isInfiniteMana) { val maximum = account.incomingRemainingUnits() ?: return + if (maximum <= 0L) return ManaLedger.Authority.postTransfer(account, maximum) return } @@ -48,10 +51,10 @@ object ManaRegenerationTicker { CalculationPipeline.apply(context, sink) val regenerationAmount = (sink.regeneration * sink.multiplier).mana.toLedgerUnits() - ManaLedger.Authority.postTransfer( - account, - regenerationAmount.coerceTransferUnits(ManaLedger.Authority, account) - ) + val transferAmount = regenerationAmount.coerceTransferUnits(ManaLedger.Authority, account) + if (transferAmount <= 0L) return + + ManaLedger.Authority.postTransfer(account, transferAmount) } private fun syncMana(player: ServerPlayer) { @@ -60,7 +63,8 @@ object ManaRegenerationTicker { ClientboundSyncManaPayload( player.mana.toDouble(), player.maxMana.toDouble(), + player.isInfiniteMana, ), ) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/PlayerOverclockState.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/PlayerOverclockState.kt new file mode 100644 index 00000000..7c4678f6 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/PlayerOverclockState.kt @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.magic.system + +import heckerpowered.matrix.common.magic.core.Magic +import heckerpowered.matrix.common.magic.core.MagicCalculationContext +import heckerpowered.matrix.common.magic.rule.calculation.contributor.MagicCalculationContributor +import heckerpowered.matrix.common.magic.rule.calculation.sink.ChannelTimeCalculationSink +import heckerpowered.matrix.common.magic.rule.calculation.sink.CostCalculationSink +import heckerpowered.matrix.common.magic.rule.calculation.sink.MagicCalculationSink +import heckerpowered.matrix.common.rule.RuleRegistry +import heckerpowered.matrix.common.rule.register +import net.minecraft.server.level.ServerPlayer +import java.util.UUID + +object PlayerOverclockState : MagicCalculationContributor { + const val MIN_RATE = 1.0 + const val MAX_RATE = 10.0 + + private data class Rates( + val mana: Double = MIN_RATE, + val magic: Double = MIN_RATE, + ) + + private val rates = mutableMapOf() + + fun onInitialize() { + RuleRegistry.register(this) + } + + fun set(player: ServerPlayer, mana: Double, magic: Double) { + rates[player.uuid] = Rates( + mana = mana.clampRate(), + magic = magic.clampRate(), + ) + } + + fun mana(player: ServerPlayer): Double { + return rates[player.uuid]?.mana ?: MIN_RATE + } + + fun magic(player: ServerPlayer): Double { + return rates[player.uuid]?.magic ?: MIN_RATE + } + + override fun contribute(magic: Magic, context: MagicCalculationContext, sink: MagicCalculationSink) { + val player = context.playerOrNull() as? ServerPlayer ?: return + when (sink) { + is CostCalculationSink -> sink.costMultiplier *= mana(player) + is ChannelTimeCalculationSink -> sink.channelSpeedBonus += magic(player) - MIN_RATE + } + } + + private fun Double.clampRate(): Double { + return coerceIn(MIN_RATE, MAX_RATE) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt index 1c9d17d9..501be65e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt @@ -12,7 +12,7 @@ import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.ChannelQueue.Companion.getOrCreateChannelQueue import heckerpowered.matrix.common.magic.channel.MagicInvocation import heckerpowered.matrix.common.magic.core.MagicCalculationContext -import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.common.magic.system.Magics import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking.Context import net.minecraft.core.UUIDUtil import net.minecraft.network.codec.ByteBufCodecs @@ -45,7 +45,7 @@ class ClientboundChannelMagicPayload( fun handle(context: Context) { context.client().execute { - val magic = MagicSystem.getMagicByUuid(magicUuid) ?: return@execute + val magic = Magics[magicUuid] ?: return@execute val player = context.player() val entity = player.level().getEntity(entityId) ?: return@execute if (entity !is LivingEntity) { @@ -60,9 +60,18 @@ class ClientboundChannelMagicPayload( val cost = magic.getCost(calculationContext) val entry = ChannelEntry(magic, cost, channelTime, currentChannelTime) - calculationContext.queue!!.enqueue(entry) + val queue = calculationContext.queue!! + val predictedEntry = queue.channelingMagics() + .firstOrNull { it.clientPrediction && it.magic.definition.uuid == magic.definition.uuid } + if (predictedEntry != null) { + predictedEntry.clientPrediction = false + predictedEntry.currentChannelTime = maxOf(predictedEntry.currentChannelTime, currentChannelTime) + return@execute + } + + queue.enqueue(entry) magic.channel(MagicInvocation.fromEntity(player, entity)) ChannelExecutor.performChannelAnimation(entry, entity, channelTime, currentChannelTime) } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundSyncManaPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundSyncManaPayload.kt index a6410f9a..8c63c4b9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundSyncManaPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundSyncManaPayload.kt @@ -17,6 +17,7 @@ import net.minecraft.network.protocol.common.custom.CustomPacketPayload class ClientboundSyncManaPayload( private val mana: Double, private val maxMana: Double, + private val infiniteMana: Boolean, ) : CustomPacketPayload { companion object { val payloadId = Matrix.identifier("sync_mana") @@ -24,6 +25,7 @@ class ClientboundSyncManaPayload( val codec = StreamCodec.composite( ByteBufCodecs.DOUBLE, ClientboundSyncManaPayload::mana, ByteBufCodecs.DOUBLE, ClientboundSyncManaPayload::maxMana, + ByteBufCodecs.BOOL, ClientboundSyncManaPayload::infiniteMana, ::ClientboundSyncManaPayload ) } @@ -39,6 +41,7 @@ class ClientboundSyncManaPayload( context.client().execute { val previousMana = MatrixHud.mana MatrixHud.maxMana = maxMana + MatrixHud.isInfiniteMana = infiniteMana if (mana.isInfinite()) { MatrixHud.mana = mana return@execute @@ -56,4 +59,4 @@ class ClientboundSyncManaPayload( (player.wizardHelmetStack.item as? WizardHelmet)?.onManaChanged(player, previousMana, mana) } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundOverclockPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundOverclockPayload.kt new file mode 100644 index 00000000..0d7a1068 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundOverclockPayload.kt @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.network + +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.common.magic.system.PlayerOverclockState +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.Context +import net.minecraft.network.codec.ByteBufCodecs +import net.minecraft.network.codec.StreamCodec +import net.minecraft.network.protocol.common.custom.CustomPacketPayload + +data class ServerboundOverclockPayload( + private val manaOverclock: Double, + private val magicOverclock: Double, +) : CustomPacketPayload { + companion object { + val payloadId = Matrix.identifier("overclock") + val type = CustomPacketPayload.Type(payloadId) + val codec = StreamCodec.composite( + ByteBufCodecs.DOUBLE, ServerboundOverclockPayload::manaOverclock, + ByteBufCodecs.DOUBLE, ServerboundOverclockPayload::magicOverclock, + ::ServerboundOverclockPayload + ) + } + + override fun type(): CustomPacketPayload.Type { + return type + } + + fun handle(context: Context) { + PlayerOverclockState.set(context.player(), manaOverclock, magicOverclock) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt index c0521c32..7834f61f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt @@ -8,8 +8,8 @@ package heckerpowered.matrix.common.network import heckerpowered.matrix.Matrix import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.MagicInvocation -import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus -import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.common.magic.system.Magics +import heckerpowered.matrix.common.persistent.isInfiniteMana import heckerpowered.matrix.common.persistent.wizardHelmet import heckerpowered.matrix.common.persistent.wizardHelmetStack import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.Context @@ -18,7 +18,7 @@ import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.StreamCodec import net.minecraft.network.protocol.common.custom.CustomPacketPayload import net.minecraft.world.entity.LivingEntity -import java.util.* +import java.util.UUID data class ServerboundUseMagicPayload( private val uuid: UUID, @@ -47,17 +47,17 @@ data class ServerboundUseMagicPayload( } val wizardHelmetStack = player.wizardHelmetStack - val magic = MagicSystem.getMagicByUuid(uuid) ?: return - if (player.wizardHelmet?.hasMagic(wizardHelmetStack, magic) != true) { + val magic = Magics[uuid] ?: return + if (!player.isInfiniteMana && player.wizardHelmet?.hasMagic(player, wizardHelmetStack, magic) != true) { return } val invocation = MagicInvocation.fromEntity(player, targetedEntity) val result = ChannelExecutor.channel(magic, invocation) - if (result != LMagicAvailableStatus.AVAILABLE) { + if (!result.isAvailable) { @Suppress("LoggingStringTemplateAsArgument") Matrix.LOGGER.debug("Magic channel failed: $result") } context.responseSender().sendPacket(ClientboundSyncHealthPayload(player)) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt index 2be5e21f..92bf3575 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt @@ -7,11 +7,12 @@ package heckerpowered.matrix.common.network import heckerpowered.matrix.Matrix import heckerpowered.matrix.core.ServerTimeRatio +import heckerpowered.matrix.core.ServerTimeWarpLease import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.Context import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.StreamCodec import net.minecraft.network.protocol.common.custom.CustomPacketPayload -import net.minecraft.server.dedicated.DedicatedServer +import net.minecraft.server.MinecraftServer import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.Duration.Companion.seconds import kotlin.time.DurationUnit @@ -36,12 +37,29 @@ data class ServerboundWarpPayload( fun handle(context: Context) { val server = context.server() - if (server is DedicatedServer || !server.isSingleplayer) return + if (!canWarpServer(server)) return if (timeScale <= 0) return + if (timeScale >= 1.0) { + ServerTimeWarpLease.clear(server) + ServerTimeRatio.restoreNormalTickDuration(server) + return + } + + ServerTimeWarpLease.refresh(server, timeScale) val newTickDurationNanos = ((1.seconds.toLong(DurationUnit.NANOSECONDS) / 20L) / timeScale).toLong() ServerTimeRatio(server).tickDuration = newTickDurationNanos.nanoseconds // TODO: Player standalone tick } -} \ No newline at end of file + + private fun canWarpServer(server: MinecraftServer): Boolean { + if (!server.isSingleplayer) { + return false + } + val isPublished = runCatching { + server.javaClass.getMethod("isPublished").invoke(server) as? Boolean + }.getOrDefault(false) + return isPublished != true + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/syncher/ModEntityDataSerializers.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/syncher/ModEntityDataSerializers.kt index 677e705b..9986e532 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/syncher/ModEntityDataSerializers.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/syncher/ModEntityDataSerializers.kt @@ -5,9 +5,21 @@ package heckerpowered.matrix.common.network.syncher +import heckerpowered.matrix.Matrix +import net.fabricmc.fabric.api.`object`.builder.v1.entity.FabricEntityDataRegistry import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.syncher.EntityDataSerializer object ModEntityDataSerializers { val double = EntityDataSerializer.forValueType(ByteBufCodecs.DOUBLE) -} \ No newline at end of file + + private var initialized = false + + fun onInitialize() { + if (initialized) { + return + } + FabricEntityDataRegistry.register(Matrix.identifier("double"), double) + initialized = true + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt b/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt index ccf182a6..1833c090 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt @@ -6,9 +6,12 @@ package heckerpowered.matrix.common.recipe import com.mojang.serialization.MapCodec +import heckerpowered.matrix.Matrix import heckerpowered.matrix.common.item.isRedstoneSuit import heckerpowered.matrix.common.item.redstoneSuitMaxPower import heckerpowered.matrix.common.item.redstoneSuitPower +import net.minecraft.core.Registry +import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.network.RegistryFriendlyByteBuf import net.minecraft.network.codec.StreamCodec import net.minecraft.world.item.ItemStack @@ -63,9 +66,13 @@ object RedstoneSuitChargeRecipe : CustomRecipe() { val mapCodec: MapCodec = MapCodec.unit(RedstoneSuitChargeRecipe) val streamCodec: StreamCodec = StreamCodec.unit(RedstoneSuitChargeRecipe) - val serializer: RecipeSerializer = RecipeSerializer(mapCodec, streamCodec) + val recipeSerializer: RecipeSerializer = RecipeSerializer(mapCodec, streamCodec) override fun getSerializer(): RecipeSerializer { - return serializer + return recipeSerializer } -} \ No newline at end of file + + fun onInitialize() { + Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, Matrix.identifier("redstone_suit_charger"), recipeSerializer) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt b/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt index 2e9b3974..25b17552 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt @@ -5,16 +5,12 @@ package heckerpowered.matrix.core -import com.mojang.blaze3d.platform.GlStateManager -import heckerpowered.matrix.client.render.OpenGLExtensions.clearGLError -import heckerpowered.matrix.client.render.recommendMipLevel import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* interface FramebufferExtension { companion object { @JvmStatic - var framebufferColorFormat = GL_RGBA16F + var framebufferColorFormat = 0 fun changeColorFormat(colorFormat: Int, action: () -> T): T { val previousColorFormat = framebufferColorFormat @@ -48,26 +44,8 @@ interface FramebufferExtension { /** * */ - fun Framebuffer.beginWriteLod(mipLevel: Int, attachment: Int = GL_COLOR_ATTACHMENT0, setTextureSize: Boolean = true, setViewport: Boolean = true) { - clearGLError() - - beginWrite(false) - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, colorAttachment, mipLevel) - endWrite() - - beginRead() - val textureWidth = glGetTexLevelParameteri(GL_TEXTURE_2D, mipLevel, GL_TEXTURE_WIDTH) - val textureHeight = glGetTexLevelParameteri(GL_TEXTURE_2D, mipLevel, GL_TEXTURE_HEIGHT) - endRead() - - this.textureWidth = textureWidth - this.textureHeight = textureHeight - - if (setViewport) { - viewportWidth = textureWidth - viewportHeight = textureHeight - GlStateManager._viewport(0, 0, textureWidth, textureHeight) - } + fun Framebuffer.beginWriteLod(mipLevel: Int, attachment: Int = 0, setTextureSize: Boolean = true, setViewport: Boolean = true) { + beginWrite(setViewport) } fun Framebuffer.endWriteLod() { @@ -75,24 +53,11 @@ interface FramebufferExtension { } fun Framebuffer.beginReadLod(mipLevel: Int) { - beginRead() - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, mipLevel) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipLevel) - endRead() } fun Framebuffer.endReadLod() { - beginRead() - val textureWidth = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) - val textureHeight = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT) - - val maxMipLevel = recommendMipLevel(textureWidth, textureHeight) - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxMipLevel) - endRead() } } var useMipmaps: Boolean -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt b/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt index 5914bbbb..746e5460 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt @@ -7,15 +7,24 @@ package heckerpowered.matrix.core import java.util.concurrent.ScheduledFuture import java.util.concurrent.ScheduledThreadPoolExecutor +import java.util.concurrent.ThreadFactory import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger import kotlin.time.Duration import kotlin.time.DurationUnit object ScheduledExecutor { - private val executor = ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()) + private val threadIndex = AtomicInteger() + private val executor = ScheduledThreadPoolExecutor(1, ThreadFactory { task -> + Thread(task, "Matrix scheduled executor ${threadIndex.incrementAndGet()}").apply { + isDaemon = true + } + }).apply { + removeOnCancelPolicy = true + } fun schedule(tickDuration: Duration, task: () -> Unit): ScheduledFuture<*> { val future = executor.scheduleAtFixedRate(task, 0, tickDuration.toLong(DurationUnit.NANOSECONDS), TimeUnit.NANOSECONDS) return future } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/ServerTickTiming.kt b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTickTiming.kt new file mode 100644 index 00000000..302cb2e9 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTickTiming.kt @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.core + +import net.minecraft.server.MinecraftServer +import java.util.WeakHashMap + +object ServerTickTiming { + private data class TickTiming( + var startNanos: Long = 0L, + var endNanos: Long = 0L, + ) + + private val timings = WeakHashMap() + + @JvmStatic + fun update(server: MinecraftServer, startNanos: Long, endNanos: Long) { + synchronized(timings) { + timings.getOrPut(server) { TickTiming() }.also { + it.startNanos = startNanos + it.endNanos = endNanos + } + } + } + + fun startNanos(server: MinecraftServer): Long { + synchronized(timings) { + return timings[server]?.startNanos ?: System.nanoTime() + } + } + + fun endNanos(server: MinecraftServer): Long { + synchronized(timings) { + return timings[server]?.endNanos + ?: (startNanos(server) + server.tickRateManager().nanosecondsPerTick()) + } + } + + fun setEndNanos(server: MinecraftServer, endNanos: Long) { + synchronized(timings) { + timings.getOrPut(server) { TickTiming(startNanos = System.nanoTime()) }.endNanos = endNanos + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt index bfc56ce9..19c7450e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt @@ -5,16 +5,39 @@ package heckerpowered.matrix.core -import heckerpowered.foundation.ui.animation.time.MonotonicTimeline import net.minecraft.server.MinecraftServer import net.minecraft.util.Util +import java.util.concurrent.locks.LockSupport import kotlin.time.Duration import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.DurationUnit -import kotlin.time.TimeMark -import kotlin.time.TimeSource class ServerTimeRatio(private val minecraftServer: MinecraftServer) { + companion object { + private const val NORMAL_TICK_DURATION_NANOS = 50_000_000L + + @JvmStatic + fun restoreNormalTickDuration(minecraftServer: MinecraftServer) { + applyNormalTickDuration(minecraftServer) + if (Thread.currentThread() != minecraftServer.runningThread && !minecraftServer.isStopped) { + runCatching { + minecraftServer.executeIfPossible { + applyNormalTickDuration(minecraftServer) + } + } + } + } + + private fun applyNormalTickDuration(minecraftServer: MinecraftServer) { + minecraftServer.tickRateManager().nanosecondsPerTick = NORMAL_TICK_DURATION_NANOS + val now = Util.getNanos() + minecraftServer.waitingForNextTick = false + minecraftServer.nextTickTimeNanos = now + ServerTickTiming.update(minecraftServer, now, now + NORMAL_TICK_DURATION_NANOS) + LockSupport.unpark(minecraftServer.runningThread) + } + } + var tickDuration: Duration get() = minecraftServer.tickRateManager().nanosecondsPerTick().nanoseconds set(value) { @@ -26,16 +49,17 @@ class ServerTimeRatio(private val minecraftServer: MinecraftServer) { minecraftServer.tickRateManager().nanosecondsPerTick = newTickDurationNanos - val currentTickStartTimeNanos = minecraftServer.tickStartTimeNanos - val currentTickEndTimeNanos = minecraftServer.tickEndTimeNanos - val currentTimeNanos = System.nanoTime() + val currentTickStartTimeNanos = ServerTickTiming.startNanos(minecraftServer) + val currentTickEndTimeNanos = ServerTickTiming.endNanos(minecraftServer) + val currentTimeNanos = Util.getNanos() val timeRange = currentTickStartTimeNanos.toDouble()..currentTickEndTimeNanos.toDouble() val remainingTimeRatio = (1 - currentTimeNanos.toDouble().inverseLerp(timeRange)).coerceIn(.0..1.0) val newCurrentTickEndTime = currentTimeNanos + (newTickDurationNanos * remainingTimeRatio).toLong() - // Not waiting for next tick means wait until `tickStartTimeNanos` + // Not waiting for next tick means wait until the next tick time. minecraftServer.waitingForNextTick = false minecraftServer.nextTickTimeNanos = newCurrentTickEndTime - minecraftServer.tickEndTimeNanos = newCurrentTickEndTime + ServerTickTiming.setEndNanos(minecraftServer, newCurrentTickEndTime) + LockSupport.unpark(minecraftServer.runningThread) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeWarpLease.kt b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeWarpLease.kt new file mode 100644 index 00000000..d2ea36c2 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeWarpLease.kt @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.core + +import net.minecraft.server.MinecraftServer +import java.util.WeakHashMap +import kotlin.time.Duration.Companion.milliseconds + +object ServerTimeWarpLease { + private val leases = WeakHashMap() + private val task by lazy { + ScheduledExecutor.schedule(250.milliseconds, ::expireLeases) + } + + fun refresh(server: MinecraftServer, timeScale: Double) { + task + synchronized(leases) { + if (timeScale >= 1.0) { + leases.remove(server) + } else { + leases[server] = System.nanoTime() + 1_500_000_000L + } + } + } + + @JvmStatic + fun clear(server: MinecraftServer) { + synchronized(leases) { + leases.remove(server) + } + } + + private fun expireLeases() { + val expiredServers = mutableListOf() + val now = System.nanoTime() + synchronized(leases) { + val iterator = leases.entries.iterator() + while (iterator.hasNext()) { + val (server, deadlineNanos) = iterator.next() + if (now >= deadlineNanos) { + iterator.remove() + expiredServers += server + } + } + } + expiredServers.forEach { server -> + runCatching { + ServerTimeRatio.restoreNormalTickDuration(server) + } + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt b/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt index 1b7141ae..b4beb686 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt @@ -5,9 +5,14 @@ package heckerpowered.matrix.core +import net.minecraft.world.entity.Entity import net.minecraft.world.phys.AABB import net.minecraft.world.phys.Vec3 +fun Entity.getLerpedPos(tickDelta: Float): Vec3 { + return getPosition(tickDelta) +} + fun Vec3.toAABB(): AABB { return AABB(this, this) } @@ -42,4 +47,4 @@ operator fun Vec3.times(value: Double): Vec3 { operator fun Vec3.div(value: Double): Vec3 { return Vec3(x / value, y / value, z / value) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/extension/EntityExtension.kt b/common/src/main/kotlin/heckerpowered/matrix/core/extension/EntityExtension.kt index 531abe42..3a7c38f5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/extension/EntityExtension.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/extension/EntityExtension.kt @@ -23,4 +23,8 @@ fun Entity.damage(amount: Float, damageSource: DamageSource): Boolean { val result = hurtServer(level, damageSource, amount) invulnerableTime = previous return result -} \ No newline at end of file +} + +fun Entity.damage(damageSource: DamageSource, amount: Float): Boolean { + return damage(amount, damageSource) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt b/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt index 41213b4e..8143a403 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt @@ -128,17 +128,19 @@ fun Iterable.withinDistance(origin: Entity, maxDistance: Double) fun Level.getEntities(searchBox: AABB): Sequence = sequence { val entityGetter = entityGetter if (entityGetter !is LevelEntityGetterAdapter<*>) { - yieldAll(getEntities(null, searchBox) { true }) + yieldAll(getEntities(null, searchBox) { true }.toList()) return@sequence } val entities = entityGetter.sectionStorage .getEntities(searchBox) .mapNotNull { it as? Entity } + .toList() val dragonParts = dragonParts() .asSequence() .filter { searchBox.intersects(it.boundingBox) } + .toList() yieldAll(entities) yieldAll(dragonParts) @@ -171,6 +173,7 @@ fun EntitySectionStorage.getAccessibleNonEmptySections( val sections = sectionIds .subSet(minSectionKey, maxSectionKey + 1L) + .toList() .asSequence() .filter { sectionKey -> val sectionY = SectionPos.y(sectionKey) @@ -185,4 +188,4 @@ fun EntitySectionStorage.getAccessibleNonEmptySections( } fun EntitySection.getEntities(searchBox: AABB): Sequence = - storage.asSequence().filter { it.boundingBox.intersects(searchBox) } \ No newline at end of file + storage.toList().asSequence().filter { it.boundingBox.intersects(searchBox) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/data/language/ModChineseLangProvider.kt b/common/src/main/kotlin/heckerpowered/matrix/data/language/ModChineseLangProvider.kt index fcfa1373..0327480f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/data/language/ModChineseLangProvider.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/data/language/ModChineseLangProvider.kt @@ -188,6 +188,9 @@ class ModChineseLangProvider( translationBuilder.add(MatrixLanguage.overclockMagic.key, "超频或降频魔法") translationBuilder.add(MatrixLanguage.overclockMana.key, "超频或降频法力") translationBuilder.add(MatrixLanguage.switchClock.key, "切换超频或降频") + translationBuilder.add("matrix.hud.magic_list", "魔法选择") + translationBuilder.add("matrix.hud.selected_magic", "当前魔法") + translationBuilder.add("matrix.hud.target", "目标") translationBuilder.add(MatrixLanguage.systemCrashing.key, "即将发生系统崩溃") translationBuilder.add(MatrixLanguage.magicAvailable.key, "就绪") @@ -198,6 +201,10 @@ class ModChineseLangProvider( translationBuilder.add(MatrixLanguage.magicTargetMissing.key, "目标缺失") translationBuilder.add(MatrixLanguage.magicTargetImmune.key, "目标免疫") translationBuilder.add(MatrixLanguage.magicSculkCatalystIsAlreadyActive.key, "幽匿催发已经激活") + translationBuilder.add("matrix.magic.available_status.insufficient_mana", "可用法力不足") + translationBuilder.add("matrix.magic.available_status.channel_queue_full", "队列已满") + translationBuilder.add("matrix.magic.available_status.channel_queue_locked", "队列已锁定") + translationBuilder.add("matrix.magic.available_status.target_missing", "目标缺失") translationBuilder.add(ArmorPenetrationEffect, "护甲穿透") translationBuilder.add(ManaOverloadEffect, "法力过载") @@ -333,9 +340,13 @@ class ModChineseLangProvider( translationBuilder.add("item.minecraft.lingering_potion.effect.angered", "滞留型狂暴药水") translationBuilder.add("key.categories.matrix", "Matrix") + translationBuilder.add("key.categories.matrix.key_category", "Matrix") + translationBuilder.add("key.category.matrix.key_category", "Matrix") translationBuilder.add("key.matrix.use_magic", "引导魔法") translationBuilder.add("key.matrix.next_magic", "下一个魔法") translationBuilder.add("key.matrix.previous_magic", "上一个魔法") + translationBuilder.add("key.matrix.overclock_magic", "超频或降频魔法") + translationBuilder.add("key.matrix.overclock_mana", "超频或降频法力") translationBuilder.add(MatrixLanguage.manaCostReduced.key, "法力消耗降低") translationBuilder.add(MatrixLanguage.manaCostIncreased.key, "法力消耗增加") @@ -345,4 +356,4 @@ class ModChineseLangProvider( translationBuilder.add(MatrixLanguage.wizardHelmetBloodPactExchangeRate.key, "血之契约兑换效率: ") translationBuilder.add(MatrixLanguage.wizardHelmetManaDeltaDescription.key, "已使用/回复的法力: ") } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/data/language/ModEnglishLangProvider.kt b/common/src/main/kotlin/heckerpowered/matrix/data/language/ModEnglishLangProvider.kt index 78ffd327..18620d5f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/data/language/ModEnglishLangProvider.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/data/language/ModEnglishLangProvider.kt @@ -193,6 +193,9 @@ Untraceable. translationBuilder.add(MatrixLanguage.overclockMagic.key, "Overclock or Underclock Magic") translationBuilder.add(MatrixLanguage.overclockMana.key, "Overclock or Underclock Mana") translationBuilder.add(MatrixLanguage.switchClock.key, "Switch Overclock or Underclock") + translationBuilder.add("matrix.hud.magic_list", "Magic selection") + translationBuilder.add("matrix.hud.selected_magic", "Selected magic") + translationBuilder.add("matrix.hud.target", "Target") translationBuilder.add(MatrixLanguage.systemCrashing.key, "System Crash Imminent") translationBuilder.add(MatrixLanguage.magicAvailable.key, "Ready") @@ -203,6 +206,10 @@ Untraceable. translationBuilder.add(MatrixLanguage.magicTargetMissing.key, "Target Missing") translationBuilder.add(MatrixLanguage.magicTargetImmune.key, "Target Immune") translationBuilder.add(MatrixLanguage.magicSculkCatalystIsAlreadyActive.key, "SCULK CATALYST IS ALREADY ACTIVE") + translationBuilder.add("matrix.magic.available_status.insufficient_mana", "Insufficient Mana") + translationBuilder.add("matrix.magic.available_status.channel_queue_full", "Queue Full") + translationBuilder.add("matrix.magic.available_status.channel_queue_locked", "Queue Locked") + translationBuilder.add("matrix.magic.available_status.target_missing", "Target Missing") translationBuilder.add(ArmorPenetrationEffect, "Armor Penetration") translationBuilder.add(ManaOverloadEffect, "Mana Overload") @@ -338,9 +345,13 @@ Untraceable. translationBuilder.add("item.minecraft.lingering_potion.effect.angered", "Lingering Potion of Angered") translationBuilder.add("key.categories.matrix", "Matrix") + translationBuilder.add("key.categories.matrix.key_category", "Matrix") + translationBuilder.add("key.category.matrix.key_category", "Matrix") translationBuilder.add("key.matrix.use_magic", "Channel magic") translationBuilder.add("key.matrix.next_magic", "Next magic") translationBuilder.add("key.matrix.previous_magic", "Previous magic") + translationBuilder.add("key.matrix.overclock_magic", "Overclock or underclock magic") + translationBuilder.add("key.matrix.overclock_mana", "Overclock or underclock mana") translationBuilder.add(MatrixLanguage.manaCostReduced.key, "Mana cost reduced by") translationBuilder.add(MatrixLanguage.manaCostIncreased.key, "Mana cost increased by") @@ -350,4 +361,4 @@ Untraceable. translationBuilder.add(MatrixLanguage.wizardHelmetBloodPactExchangeRate.key, "Blood Pact Conversion Efficiency: ") translationBuilder.add(MatrixLanguage.wizardHelmetManaDeltaDescription.key, "Spent/Recovered Mana: ") } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/data/tag/ModDamageTypeProvider.kt b/common/src/main/kotlin/heckerpowered/matrix/data/tag/ModDamageTypeProvider.kt index 201eeaf1..f15e7475 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/data/tag/ModDamageTypeProvider.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/data/tag/ModDamageTypeProvider.kt @@ -28,9 +28,9 @@ class ModDamageTypeProvider( override fun addTags(registries: HolderLookup.Provider) { getOrCreateTagBuilder(DamageTypeTags.BYPASSES_SHIELD) - .add(MatrixDamageTypes.magic) + .addOptional(MatrixDamageTypes.magic) getOrCreateTagBuilder(MatrixDamageTypeTags.magic) - .add(MatrixDamageTypes.magic) + .addOptional(MatrixDamageTypes.magic) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/net/minecraft/client/gl/Framebuffer.kt b/common/src/main/kotlin/net/minecraft/client/gl/Framebuffer.kt new file mode 100644 index 00000000..8e068c2f --- /dev/null +++ b/common/src/main/kotlin/net/minecraft/client/gl/Framebuffer.kt @@ -0,0 +1,121 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package net.minecraft.client.gl + +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.resource.RenderTargetDescriptor +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.GpuTexture +import com.mojang.blaze3d.textures.GpuTextureView +import net.minecraft.client.Minecraft +import kotlin.math.roundToInt + +open class Framebuffer( + var textureWidth: Int, + var textureHeight: Int, + val useDepthAttachment: Boolean = false, +) { + var viewportWidth: Int = textureWidth + var viewportHeight: Int = textureHeight + var colorAttachment: Int = 0 + var depthAttachment: Int = 0 + var fbo: Int = 0 + + private var clearColor: Int = 0 + private var backingTarget: RenderTarget? = null + + open val renderTarget: RenderTarget + get() { + val existing = backingTarget + if (existing != null) { + return existing + } + + val allocated = RenderTargetDescriptor( + textureWidth.coerceAtLeast(1), + textureHeight.coerceAtLeast(1), + useDepthAttachment, + clearColor, + ).allocate() + backingTarget = allocated + return allocated + } + + val colorTexture: GpuTexture + get() = renderTarget.colorTexture ?: error("Framebuffer color texture has not been created") + + val colorTextureView: GpuTextureView + get() = renderTarget.colorTextureView ?: error("Framebuffer color texture view has not been created") + + val depthTexture: GpuTexture? + get() = renderTarget.depthTexture + + val depthTextureView: GpuTextureView? + get() = renderTarget.depthTextureView + + fun setClearColor(red: Float, green: Float, blue: Float, alpha: Float) { + clearColor = argb(alpha, red, green, blue) + } + + open fun resize(width: Int, height: Int, getError: Boolean = false) { + val safeWidth = width.coerceAtLeast(1) + val safeHeight = height.coerceAtLeast(1) + textureWidth = safeWidth + textureHeight = safeHeight + viewportWidth = safeWidth + viewportHeight = safeHeight + backingTarget?.resize(safeWidth, safeHeight) + } + + fun clear(getError: Boolean = false) { + val target = renderTarget + val encoder = RenderSystem.getDevice().createCommandEncoder() + val depth = target.depthTexture + if (useDepthAttachment && depth != null) { + encoder.clearColorAndDepthTextures(colorTexture, clearColor, depth, 0.0) + } else { + encoder.clearColorTexture(colorTexture, clearColor) + } + } + + fun beginWrite(setViewport: Boolean = true) { + RenderSystem.outputColorTextureOverride = colorTextureView + RenderSystem.outputDepthTextureOverride = depthTextureView + } + + fun endWrite() { + RenderSystem.outputColorTextureOverride = null + RenderSystem.outputDepthTextureOverride = null + } + + fun draw(width: Int, height: Int, disableBlend: Boolean = false) { + val mainTarget = Minecraft.getInstance().gameRenderer.mainRenderTarget() + renderTarget.blitAndBlendToTexture( + mainTarget.colorTextureView ?: error("Main render target color texture view has not been created"), + mainTarget.depthTextureView ?: error("Main render target depth texture view has not been created"), + ) + } + + fun destroyBuffers() { + backingTarget?.destroyBuffers() + backingTarget = null + } + + private fun argb(alpha: Float, red: Float, green: Float, blue: Float): Int { + val a = (alpha.coerceIn(0.0F, 1.0F) * 255.0F).roundToInt() + val r = (red.coerceIn(0.0F, 1.0F) * 255.0F).roundToInt() + val g = (green.coerceIn(0.0F, 1.0F) * 255.0F).roundToInt() + val b = (blue.coerceIn(0.0F, 1.0F) * 255.0F).roundToInt() + return (a shl 24) or (r shl 16) or (g shl 8) or b + } +} + +open class SimpleFramebuffer( + width: Int, + height: Int, + useDepth: Boolean = false, + getError: Boolean = false, +) : Framebuffer(width, height, useDepth) diff --git a/common/src/main/resources/assets/matrix/items/coal_axe.json b/common/src/main/resources/assets/matrix/items/coal_axe.json new file mode 100644 index 00000000..5eb5ee44 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_boots.json b/common/src/main/resources/assets/matrix/items/coal_boots.json new file mode 100644 index 00000000..f02fce88 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_chestplate.json b/common/src/main/resources/assets/matrix/items/coal_chestplate.json new file mode 100644 index 00000000..d171d24f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_helmet.json b/common/src/main/resources/assets/matrix/items/coal_helmet.json new file mode 100644 index 00000000..30390f59 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_hoe.json b/common/src/main/resources/assets/matrix/items/coal_hoe.json new file mode 100644 index 00000000..6d17daa3 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_leggings.json b/common/src/main/resources/assets/matrix/items/coal_leggings.json new file mode 100644 index 00000000..f3964df4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_pickaxe.json b/common/src/main/resources/assets/matrix/items/coal_pickaxe.json new file mode 100644 index 00000000..440080ec --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_shovel.json b/common/src/main/resources/assets/matrix/items/coal_shovel.json new file mode 100644 index 00000000..bdbac663 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_sword.json b/common/src/main/resources/assets/matrix/items/coal_sword.json new file mode 100644 index 00000000..d1189c81 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_axe.json b/common/src/main/resources/assets/matrix/items/emerald_axe.json new file mode 100644 index 00000000..2720840d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_boots.json b/common/src/main/resources/assets/matrix/items/emerald_boots.json new file mode 100644 index 00000000..5ee9dcca --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_chestplate.json b/common/src/main/resources/assets/matrix/items/emerald_chestplate.json new file mode 100644 index 00000000..b566a6d0 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_helmet.json b/common/src/main/resources/assets/matrix/items/emerald_helmet.json new file mode 100644 index 00000000..18a99fef --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_hoe.json b/common/src/main/resources/assets/matrix/items/emerald_hoe.json new file mode 100644 index 00000000..0f842f7e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_leggings.json b/common/src/main/resources/assets/matrix/items/emerald_leggings.json new file mode 100644 index 00000000..c2c4af6d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_pickaxe.json b/common/src/main/resources/assets/matrix/items/emerald_pickaxe.json new file mode 100644 index 00000000..8240a398 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_shovel.json b/common/src/main/resources/assets/matrix/items/emerald_shovel.json new file mode 100644 index 00000000..730d8d2c --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_sword.json b/common/src/main/resources/assets/matrix/items/emerald_sword.json new file mode 100644 index 00000000..30395703 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/finder_arrow.json b/common/src/main/resources/assets/matrix/items/finder_arrow.json new file mode 100644 index 00000000..f69b2da0 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/finder_arrow.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/finder_arrow" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_axe.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_axe.json new file mode 100644 index 00000000..d6f679f3 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_boots.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_boots.json new file mode 100644 index 00000000..27688da3 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_chestplate.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_chestplate.json new file mode 100644 index 00000000..21812cb9 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_helmet.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_helmet.json new file mode 100644 index 00000000..fbf2c79c --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_hoe.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_hoe.json new file mode 100644 index 00000000..17f48c3f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_leggings.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_leggings.json new file mode 100644 index 00000000..e221e4e5 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_pickaxe.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_pickaxe.json new file mode 100644 index 00000000..6b5d2592 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_shovel.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_shovel.json new file mode 100644 index 00000000..b12ca7eb --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_sword.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_sword.json new file mode 100644 index 00000000..6d386e21 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lightning_chestplate_borrowed_time.json b/common/src/main/resources/assets/matrix/items/lightning_chestplate_borrowed_time.json new file mode 100644 index 00000000..fbd9d442 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lightning_chestplate_borrowed_time.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/warden_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/magic_talisman.json b/common/src/main/resources/assets/matrix/items/magic_talisman.json new file mode 100644 index 00000000..60368d59 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/magic_talisman.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/magic_talisman_icon" + } +} diff --git a/common/src/main/resources/assets/matrix/items/meta_bow.json b/common/src/main/resources/assets/matrix/items/meta_bow.json new file mode 100644 index 00000000..ae7a08af --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/meta_bow.json @@ -0,0 +1,35 @@ +{ + "model": { + "type": "minecraft:condition", + "property": "minecraft:using_item", + "on_false": { + "type": "minecraft:model", + "model": "matrix:item/meta_bow" + }, + "on_true": { + "type": "minecraft:range_dispatch", + "property": "minecraft:use_duration", + "scale": 0.05, + "fallback": { + "type": "minecraft:model", + "model": "matrix:item/meta_bow_pulling_0" + }, + "entries": [ + { + "threshold": 0.65, + "model": { + "type": "minecraft:model", + "model": "matrix:item/meta_bow_pulling_1" + } + }, + { + "threshold": 0.9, + "model": { + "type": "minecraft:model", + "model": "matrix:item/meta_bow_pulling_2" + } + } + ] + } + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_axe.json b/common/src/main/resources/assets/matrix/items/redstone_axe.json new file mode 100644 index 00000000..966c94c5 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_boots.json b/common/src/main/resources/assets/matrix/items/redstone_boots.json new file mode 100644 index 00000000..df03865a --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_chestplate.json b/common/src/main/resources/assets/matrix/items/redstone_chestplate.json new file mode 100644 index 00000000..208f27a6 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_helmet.json b/common/src/main/resources/assets/matrix/items/redstone_helmet.json new file mode 100644 index 00000000..8b7d6752 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_hoe.json b/common/src/main/resources/assets/matrix/items/redstone_hoe.json new file mode 100644 index 00000000..7a1e478d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_leggings.json b/common/src/main/resources/assets/matrix/items/redstone_leggings.json new file mode 100644 index 00000000..ee06827f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_pickaxe.json b/common/src/main/resources/assets/matrix/items/redstone_pickaxe.json new file mode 100644 index 00000000..67871b3e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_shovel.json b/common/src/main/resources/assets/matrix/items/redstone_shovel.json new file mode 100644 index 00000000..93b88639 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_sword.json b/common/src/main/resources/assets/matrix/items/redstone_sword.json new file mode 100644 index 00000000..9c822203 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_boots.json b/common/src/main/resources/assets/matrix/items/stone_boots.json new file mode 100644 index 00000000..2f550b3e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_chestplate.json b/common/src/main/resources/assets/matrix/items/stone_chestplate.json new file mode 100644 index 00000000..665ac9a9 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_helmet.json b/common/src/main/resources/assets/matrix/items/stone_helmet.json new file mode 100644 index 00000000..0eec7a53 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_leggings.json b/common/src/main/resources/assets/matrix/items/stone_leggings.json new file mode 100644 index 00000000..daf7deeb --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/warden_chestplate.json b/common/src/main/resources/assets/matrix/items/warden_chestplate.json new file mode 100644 index 00000000..fbd9d442 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/warden_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/warden_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_1.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_1.json new file mode 100644 index 00000000..e5205c1f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_1.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_basic" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_10.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_10.json new file mode 100644 index 00000000..88940f01 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_10.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_apogee" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_13.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_13.json new file mode 100644 index 00000000..a05c0b45 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_13.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_hacker" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_2.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_2.json new file mode 100644 index 00000000..6bb745c2 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_2.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_doom" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_3.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_3.json new file mode 100644 index 00000000..24bae425 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_3.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_ruin" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_4.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_4.json new file mode 100644 index 00000000..c42fc11c --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_4.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_warp_dancer" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_5.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_5.json new file mode 100644 index 00000000..88940f01 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_5.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_apogee" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_hacker.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_hacker.json new file mode 100644 index 00000000..a05c0b45 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_hacker.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_hacker" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_boots.json b/common/src/main/resources/assets/matrix/items/wooden_boots.json new file mode 100644 index 00000000..884c4647 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_chestplate.json b/common/src/main/resources/assets/matrix/items/wooden_chestplate.json new file mode 100644 index 00000000..acf790bb --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_helmet.json b/common/src/main/resources/assets/matrix/items/wooden_helmet.json new file mode 100644 index 00000000..06dda93e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_leggings.json b/common/src/main/resources/assets/matrix/items/wooden_leggings.json new file mode 100644 index 00000000..72f0c3be --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/magic_talisman_icon.json b/common/src/main/resources/assets/matrix/models/item/magic_talisman_icon.json new file mode 100644 index 00000000..fa396f5b --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/magic_talisman_icon.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/ender_eye" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/meta_bow.json b/common/src/main/resources/assets/matrix/models/item/meta_bow.json index 688e26f6..c10a3405 100644 --- a/common/src/main/resources/assets/matrix/models/item/meta_bow.json +++ b/common/src/main/resources/assets/matrix/models/item/meta_bow.json @@ -1,7 +1,7 @@ { - "parent": "item/generated", + "parent": "minecraft:item/generated", "textures": { - "layer0": "item/bow" + "layer0": "minecraft:item/bow" }, "display": { "thirdperson_righthand": { @@ -78,21 +78,21 @@ "predicate": { "pulling": 1 }, - "model": "item/bow_pulling_0" + "model": "matrix:item/meta_bow_pulling_0" }, { "predicate": { "pulling": 1, "pull": 0.65 }, - "model": "item/bow_pulling_1" + "model": "matrix:item/meta_bow_pulling_1" }, { "predicate": { "pulling": 1, "pull": 0.9 }, - "model": "item/bow_pulling_2" + "model": "matrix:item/meta_bow_pulling_2" } ] } diff --git a/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_0.json b/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_0.json index c3798c87..6b89e7ea 100644 --- a/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_0.json +++ b/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_0.json @@ -1,6 +1,6 @@ { - "parent": "item/bow", + "parent": "minecraft:item/bow", "textures": { - "layer0": "item/bow_pulling_0" + "layer0": "minecraft:item/bow_pulling_0" } } diff --git a/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_1.json b/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_1.json index c840a9da..a883a547 100644 --- a/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_1.json +++ b/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_1.json @@ -1,6 +1,6 @@ { - "parent": "item/bow", + "parent": "minecraft:item/bow", "textures": { - "layer0": "item/bow_pulling_1" + "layer0": "minecraft:item/bow_pulling_1" } } diff --git a/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_2.json b/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_2.json index 90803e34..56393833 100644 --- a/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_2.json +++ b/common/src/main/resources/assets/matrix/models/item/meta_bow_pulling_2.json @@ -1,6 +1,6 @@ { - "parent": "item/bow", + "parent": "minecraft:item/bow", "textures": { - "layer0": "item/bow_pulling_2" + "layer0": "minecraft:item/bow_pulling_2" } } diff --git a/common/src/main/resources/assets/matrix/shaders/core/screenquad_frag_tex_coord.vsh b/common/src/main/resources/assets/matrix/shaders/core/screenquad_frag_tex_coord.vsh new file mode 100644 index 00000000..86ce583d --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/core/screenquad_frag_tex_coord.vsh @@ -0,0 +1,9 @@ +#version 330 + +out vec2 fragTexCoord; + +void main() { + vec2 uv = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2); + gl_Position = vec4(uv * vec2(2, 2) + vec2(-1, -1), 0, 1); + fragTexCoord = uv; +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh index 4bd0efd4..80f59741 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh @@ -1,8 +1,16 @@ #version 150 core uniform sampler2D framebuffer;// Input texture from the previous pass -uniform float threshold;// Brightness threshold (e.g., 0.7) -uniform float intensity = 1.0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define threshold MatrixPostData0.x +#define intensity MatrixPostData0.y in vec2 fragTexCoord;// Texture coordinates from vertex shader diff --git a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh index dc9bf4ef..b7fe1405 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec2 direction; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define direction MatrixPostData0.xy out vec4 fragColor; @@ -21,4 +29,4 @@ void main() { } fragColor = vec4(result, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh index 09e890b1..84c49753 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float filterRadius = 15; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define filterRadius MatrixPostData0.x out vec4 fragColor; @@ -20,4 +28,4 @@ void main() { color /= 16.0; fragColor = color * 1.2; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh index 6cf60a5d..bc39aa6b 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh @@ -3,9 +3,44 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float kernel[49]; -uniform int kernelSize = 48; -uniform vec2 direction = vec2(1, 0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; + vec4 MatrixPostData4; + vec4 MatrixPostData5; + vec4 MatrixPostData6; + vec4 MatrixPostData7; + vec4 MatrixPostData8; + vec4 MatrixPostData9; + vec4 MatrixPostData10; + vec4 MatrixPostData11; + vec4 MatrixPostData12; + vec4 MatrixPostData13; +}; + +#define direction MatrixPostData0.xy +#define kernelSize int(MatrixPostData0.z) + +float kernelAt(int index) { + int block = index / 4; + int component = index - block * 4; + if (block == 0) return MatrixPostData1[component]; + if (block == 1) return MatrixPostData2[component]; + if (block == 2) return MatrixPostData3[component]; + if (block == 3) return MatrixPostData4[component]; + if (block == 4) return MatrixPostData5[component]; + if (block == 5) return MatrixPostData6[component]; + if (block == 6) return MatrixPostData7[component]; + if (block == 7) return MatrixPostData8[component]; + if (block == 8) return MatrixPostData9[component]; + if (block == 9) return MatrixPostData10[component]; + if (block == 10) return MatrixPostData11[component]; + if (block == 11) return MatrixPostData12[component]; + return MatrixPostData13[component]; +} out vec4 fragColor; @@ -15,14 +50,15 @@ void main() { fragColor = originalColor; return; } - vec4 color = originalColor * kernel[0]; + vec4 color = originalColor * kernelAt(0); vec2 offset = direction / vec2(textureSize(framebuffer, 0)); for (int i = 1; i <= kernelSize; ++i) { vec2 subOffset = offset * float(i); - color += texture(framebuffer, fragTexCoord + subOffset) * kernel[i]; - color += texture(framebuffer, fragTexCoord - subOffset) * kernel[i]; + float weight = kernelAt(i); + color += texture(framebuffer, fragTexCoord + subOffset) * weight; + color += texture(framebuffer, fragTexCoord - subOffset) * weight; } fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh index 8bd418fb..fa005efa 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec2 offset = vec2(1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define offset MatrixPostData0.xy out vec4 fragColor; @@ -16,4 +24,4 @@ void main() { color += texture(framebuffer, fragTexCoord + vec2(sampleOffset.x, -sampleOffset.y)); color += texture(framebuffer, fragTexCoord + vec2(-sampleOffset.x, -sampleOffset.y)); fragColor = color / 5; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh index b5610d4d..14939609 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float strength = 1.0; -uniform int samples = 10; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define strength MatrixPostData0.x +#define samples int(MatrixPostData0.y) out vec4 fragColor; @@ -19,4 +27,4 @@ void main() { } fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh index 1c78de26..5f19f728 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float lod = .0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define lod MatrixPostData0.x out vec4 fragColor; @@ -33,4 +41,4 @@ void main() { color /= weight; fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh b/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh index 00bd592f..e2fc15d7 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh @@ -2,16 +2,19 @@ in vec2 fragTexCoord; +uniform sampler2D framebuffer; uniform sampler2D depthAttachment; -uniform mat4 inverseViewMatrix; -uniform mat4 inverseProjectionMatrix; -uniform vec2 resolution; -uniform vec3 playerPosition; +layout(std140) uniform MatrixPostUniforms { + mat4 inverseProjectionMatrix; + mat4 inverseViewMatrix; + vec4 MatrixPostData0; + vec4 MatrixPostData1; +}; -uniform sampler2D noiseTexture; - -uniform float dissolveFactor = 1.0; +#define playerPosition MatrixPostData0.xyz +#define dissolveFactor MatrixPostData0.w +#define resolution MatrixPostData1.xy out vec4 fragColor; @@ -59,27 +62,44 @@ vec3 reconstructWorldNormal(vec2 uv, vec2 texelSize) { return worldNormal; } -vec4 triplanarMapping(vec3 worldPosition, vec3 worldNormal, sampler2D textureSampler, float scale) { - vec3 blendingWeights = abs(worldNormal); - blendingWeights = max(blendingWeights, 0.0001); - blendingWeights /= (blendingWeights.x + blendingWeights.y + blendingWeights.z); - - vec4 colorX = texture(textureSampler, worldPosition.yz * scale); - vec4 colorY = texture(textureSampler, worldPosition.xz * scale); - vec4 colorZ = texture(textureSampler, worldPosition.xy * scale); +float hash13(vec3 p) { + p = fract(p * 0.1031); + p += dot(p, p.yzx + 33.33); + return fract((p.x + p.y) * p.z); +} - return colorX * blendingWeights.x + - colorY * blendingWeights.y + - colorZ * blendingWeights.z; +float valueNoise(vec3 p) { + vec3 i = floor(p); + vec3 f = fract(p); + f = f * f * (3.0 - 2.0 * f); + + float n000 = hash13(i + vec3(0.0, 0.0, 0.0)); + float n100 = hash13(i + vec3(1.0, 0.0, 0.0)); + float n010 = hash13(i + vec3(0.0, 1.0, 0.0)); + float n110 = hash13(i + vec3(1.0, 1.0, 0.0)); + float n001 = hash13(i + vec3(0.0, 0.0, 1.0)); + float n101 = hash13(i + vec3(1.0, 0.0, 1.0)); + float n011 = hash13(i + vec3(0.0, 1.0, 1.0)); + float n111 = hash13(i + vec3(1.0, 1.0, 1.0)); + + float nx00 = mix(n000, n100, f.x); + float nx10 = mix(n010, n110, f.x); + float nx01 = mix(n001, n101, f.x); + float nx11 = mix(n011, n111, f.x); + float nxy0 = mix(nx00, nx10, f.y); + float nxy1 = mix(nx01, nx11, f.y); + return mix(nxy0, nxy1, f.z); } void main() { + vec4 sceneColor = texture(framebuffer, fragTexCoord); float nonLinearDepth = texture(depthAttachment, fragTexCoord).r; vec3 worldPosition = worldAbsolutePosition(fragTexCoord, nonLinearDepth); float dist = length(worldPosition - playerPosition); if (dist > 768.0) { - discard; + fragColor = sceneColor; + return; } vec3 worldNormal = reconstructWorldNormal(fragTexCoord, 1.0 / resolution); @@ -87,7 +107,8 @@ void main() { if (dot(worldNormal, cameraToPixel) > 0.0) { worldNormal = -worldNormal; } - vec4 noise = triplanarMapping(worldPosition, worldNormal, noiseTexture, 1.0F / 128.0F); - float alpha = step(noise.r, dissolveFactor); - fragColor = vec4(vec3(0.1, 0.5, 1.0) * 4, alpha); -} \ No newline at end of file + float noise = valueNoise(worldPosition / 16.0 + worldNormal * 2.0); + float alpha = step(noise, dissolveFactor); + vec3 collapseColor = vec3(0.1, 0.5, 1.0) * 4.0; + fragColor = sceneColor + vec4(collapseColor * alpha, 0.0); +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh b/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh index 04a71738..1be35d54 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh @@ -3,9 +3,17 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float brightness = 1.0; -uniform float saturation = 1.0; -uniform float contrast = 1.0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define brightness MatrixPostData0.x +#define saturation MatrixPostData0.y +#define contrast MatrixPostData0.z out vec4 fragColor; @@ -20,4 +28,4 @@ void main() { vec3 saturationColor = mix(intensityColor, brightnessColor, saturation); vec3 contrastColor = mix(color.rgb, saturationColor, contrast); fragColor = vec4(contrastColor, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh b/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh index 3dfca79b..7d27cd10 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh @@ -3,11 +3,19 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define color MatrixPostData0 out vec4 fragColor; void main() { vec4 framebufferColor = texture(framebuffer, fragTexCoord); fragColor = framebufferColor * color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh b/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh index 9b4fb916..310e7373 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh @@ -5,7 +5,14 @@ in vec2 fragTexCoord; uniform sampler2D primaryFramebuffer; uniform sampler2D secondaryFramebuffer; -uniform vec4 colorMultiplier = vec4(1.0, 1.0, 1.0, 1.0); +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define colorMultiplier MatrixPostData0 out vec4 fragColor; @@ -16,4 +23,4 @@ void main() { // float alpha = (primaryFramebufferColor.a + secondaryFramebufferColor.a) / 2; fragColor = (primaryFramebufferColor + secondaryFramebufferColor) * colorMultiplier; // fragColor.a = alpha; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh b/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh index 421f24cf..f7b6a2f2 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float edgeThreshold = 0.5; -uniform vec4 edgeColor = vec4(1.0, 1.0, .0, 1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define edgeThreshold MatrixPostData0.x +#define edgeColor MatrixPostData1 out vec4 fragColor; diff --git a/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh b/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh index ba357f7a..8e0a571c 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float strength; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define strength MatrixPostData0.x out vec4 fragColor; @@ -30,4 +38,4 @@ void main() { float blendFactor = smoothstep(0.0, 1.0, length(centeredTexCoord) * strength * 2.0); fragColor = mix(original, blurColor, blendFactor); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh b/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh index 676d8ebc..585f8c56 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh @@ -2,11 +2,18 @@ in vec2 fragTexCoord; -uniform float progress = 1.0; -uniform float radius = 0.5; -uniform float thickness = 0.1; -uniform vec2 center = vec2(0.5, 0.5); -uniform vec4 color = vec4(1.0); +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define progress MatrixPostData0.x +#define radius MatrixPostData0.y +#define thickness MatrixPostData0.z +#define center MatrixPostData1.xy +#define color MatrixPostData2 out vec4 fragColor; @@ -41,4 +48,4 @@ void main() { discard; } fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh b/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh index 62267074..1083fa16 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh @@ -3,9 +3,17 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float primaryLevelOfDetail; -uniform float secondaryLevelOfDetail; -uniform float alpha = 0.5; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define primaryLevelOfDetail MatrixPostData0.x +#define secondaryLevelOfDetail MatrixPostData0.y +#define alpha MatrixPostData0.z out vec4 fragColor; @@ -14,4 +22,4 @@ void main() { vec4 secondaryColor = textureLod(framebuffer, fragTexCoord, secondaryLevelOfDetail); vec4 mixColor = mix(primaryColor, secondaryColor, alpha); fragColor = mixColor; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh b/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh index 4a10e49f..93148e53 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh @@ -3,10 +3,18 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float levelOfDetail; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define levelOfDetail MatrixPostData0.x out vec4 fragColor; void main() { fragColor = textureLod(framebuffer, fragTexCoord, levelOfDetail); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh b/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh index 60e34560..671b35cc 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec2 sourceResolution; -uniform vec2 targetResolution; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define sourceResolution MatrixPostData0.xy +#define targetResolution MatrixPostData0.zw out vec4 fragColor; @@ -20,4 +28,4 @@ void main() { color /= 4; fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh b/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh index 1f6a8c15..0ff36c8e 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh @@ -4,9 +4,16 @@ in vec2 fragTexCoord; uniform sampler2D signedDistanceField; -uniform vec2 shadowOffset = vec2(0.0, 0.0); -uniform float shadowSize = 8.0; -uniform vec4 shadowColor = vec4(0.0, 0.0, 0.0, 0.5); +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define shadowOffset MatrixPostData0.xy +#define shadowSize MatrixPostData0.z +#define shadowColor MatrixPostData1 out vec4 fragColor; @@ -23,4 +30,4 @@ void main() { float alpha = smoothstep(shadowSize, 0.0, denormalizedDist); fragColor = vec4(shadowColor.rgb, shadowColor.a * alpha); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh b/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh index 70733d9d..877c947b 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float stepSize; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define stepSize MatrixPostData0.x out vec4 fragColor; @@ -27,4 +35,4 @@ void main() { } fragColor = vec4(bestPos, 0.0, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh b/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh index f2c36823..b90fa3f4 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh @@ -2,15 +2,21 @@ in vec2 fragTexCoord; +uniform sampler2D framebuffer; uniform sampler2D depthAttachment; -uniform mat4 inverseViewMatrix; -uniform mat4 inverseProjectionMatrix; -// User uniforms -uniform vec3 wavePosition; -uniform vec4 waveColor; -uniform float waveSize; -uniform float waveRadius; +layout(std140) uniform MatrixPostUniforms { + mat4 inverseProjectionMatrix; + mat4 inverseViewMatrix; + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; +}; + +#define wavePosition MatrixPostData0.xyz +#define waveRadius MatrixPostData0.w +#define waveColor MatrixPostData1 +#define waveSize MatrixPostData2.x out vec4 fragColor; @@ -42,11 +48,12 @@ vec3 worldAbsolutePosition(vec2 uv, float depth) { } void main() { + vec4 sceneColor = texture(framebuffer, fragTexCoord); float depth = texture(depthAttachment, fragTexCoord).r; vec3 worldPosition = worldAbsolutePosition(fragTexCoord, depth); float dist = length(worldPosition - wavePosition); // dist > waveRadius && dist < (waveRadius + waveSize) float insideWave = step(waveRadius, dist) * step(dist, waveRadius + waveSize); - fragColor = mix(vec4(0.0), waveColor, insideWave); -} \ No newline at end of file + fragColor = sceneColor + waveColor * insideWave; +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh b/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh index c807d6a0..f5e1f171 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float grayscaleIntensity = 0.0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define grayscaleIntensity MatrixPostData0.x out vec4 fragColor; @@ -12,4 +20,4 @@ void main() { float grayscale = dot(framebufferColor.rgb, vec3(0.299, 0.587, 0.114)); vec3 color = mix(framebufferColor.rgb, vec3(grayscale), grayscaleIntensity); fragColor = vec4(color, framebufferColor.a); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh b/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh index cfe8d465..3655283e 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D hdrScene; -uniform float exposure = 1.0; // Set from application. Interpreted as linear scale. -uniform float exposureEv = 0; // Optional: exposure in EV. If unused, set to 0. + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define exposure MatrixPostData0.x +#define exposureEv MatrixPostData0.y out vec4 fragColor; @@ -58,4 +66,4 @@ void main() { vec3 srgbColor = convertLinearToSrgb(mappedLinear); fragColor = vec4(srgbColor, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/textures/item/emerald_axe.png b/common/src/main/resources/assets/matrix/textures/item/emerald_axe.png new file mode 100644 index 00000000..cef77a30 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/item/emerald_axe.png differ diff --git a/common/src/main/resources/assets/matrix/textures/item/emerald_hoe.png b/common/src/main/resources/assets/matrix/textures/item/emerald_hoe.png new file mode 100644 index 00000000..29928d04 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/item/emerald_hoe.png differ diff --git a/common/src/main/resources/assets/matrix/textures/item/emerald_shovel.png b/common/src/main/resources/assets/matrix/textures/item/emerald_shovel.png new file mode 100644 index 00000000..7b482a78 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/item/emerald_shovel.png differ diff --git a/common/src/main/resources/fabric.mod.json b/common/src/main/resources/fabric.mod.json index 85759104..e7151ce5 100644 --- a/common/src/main/resources/fabric.mod.json +++ b/common/src/main/resources/fabric.mod.json @@ -14,7 +14,7 @@ "license": "CC0-1.0", "icon": "assets/matrix/icon.png", "environment": "*", - "accessWidener": "matrix.accesswidener", + "accessWidener": "matrix.classtweaker", "entrypoints": { "main": [ { @@ -30,7 +30,7 @@ ], "fabric-datagen": [ { - "value": "ModDataGenerator", + "value": "heckerpowered.matrix.ModDataGenerator", "adapter": "kotlin" } ] @@ -40,7 +40,7 @@ ], "depends": { "fabricloader": ">=0.15.7", - "minecraft": "~1.21", + "minecraft": ">=26.2-alpha.5", "java": ">=21", "fabric-api": "*", "fabric-language-kotlin": ">=1.9.22" @@ -48,4 +48,4 @@ "suggests": { "another-mod": "*" } -} \ No newline at end of file +} diff --git a/common/src/main/resources/matrix.classtweaker b/common/src/main/resources/matrix.classtweaker index b26561dc..6fbe9663 100644 --- a/common/src/main/resources/matrix.classtweaker +++ b/common/src/main/resources/matrix.classtweaker @@ -3,8 +3,8 @@ classTweaker v1 official # ServerTimeRatio.kt accessible field net/minecraft/server/MinecraftServer waitingForNextTick Z accessible field net/minecraft/server/MinecraftServer nextTickTimeNanos J +accessible field net/minecraft/server/MinecraftServer delayedTasksMaxNextTickTimeNanos J accessible field net/minecraft/world/TickRateManager nanosecondsPerTick J -inject-interface net/minecraft/server/MinecraftServer heckerpowered/matrix/extension/MatrixMinecraftServer inject-interface net/minecraft/world/entity/LivingEntity heckerpowered/matrix/extension/MatrixLivingEntity inject-interface net/minecraft/world/level/Level heckerpowered/matrix/extension/MatrixLevel @@ -40,4 +40,4 @@ accessible field net/minecraft/world/entity/LivingEntity lastHurtByPlayerMemoryT accessible field net/minecraft/world/entity/ai/Brain memories Ljava/util/Map; -inject-interface net/minecraft/world/damagesource/DamageSource heckerpowered/matrix/extension/MatrixDamageSource \ No newline at end of file +inject-interface net/minecraft/world/damagesource/DamageSource heckerpowered/matrix/extension/MatrixDamageSource diff --git a/common/src/main/resources/matrix.mixins.json b/common/src/main/resources/matrix.mixins.json index 2f57e2da..b6232927 100644 --- a/common/src/main/resources/matrix.mixins.json +++ b/common/src/main/resources/matrix.mixins.json @@ -3,37 +3,19 @@ "package": "heckerpowered.matrix.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "CastSpellGoalMixin", "DamageSourceMixin", - "ElderGuardianEntityMixin", - "EndermanEntityMixin", "EntityMixin", - "EntityTrackerEntryMixin", - "FireBeamGoalMixin", - "ItemStackMixin", "LevelMixin", "LivingEntityMixin", - "MinecraftServerMixin", - "PlayerEntityMixin", - "PlayerMixin", - "ServerCommonNetworkHandlerMixin", - "ServerPlayerEntityMixin", - "ServerPlayNetworkHandlerMixin", - "SonicBoomTaskMixin", - "TargetPredicateMixin", - "TridentEntityMixin", - "TridentItemMixin", - "WitchEntityMixin", - "WorldMixin" + "MinecraftServerMixin" ], "client": [ - "FramebufferMixin", - "GameRendererMixin", + "CameraMixin", + "DeltaTrackerTimerMixin", + "GameRendererStandaloneMixin", "KeyboardMixin", - "MinecraftClientMixin", - "MixinInGameHud", - "MouseMixin", - "WorldRendererMixin" + "MinecraftMixin", + "MixinInGameHud" ], "injectors": { "defaultRequire": 1 @@ -41,4 +23,4 @@ "mixinextras": { "minVersion": "0.5.0" } -} \ No newline at end of file +} diff --git a/common/src/test/kotlin/heckerpowered/matrix/test/CodecTest.kt b/common/src/test/kotlin/heckerpowered/matrix/test/CodecTest.kt index 870d3415..bca3be6f 100644 --- a/common/src/test/kotlin/heckerpowered/matrix/test/CodecTest.kt +++ b/common/src/test/kotlin/heckerpowered/matrix/test/CodecTest.kt @@ -15,7 +15,7 @@ import kotlinx.serialization.builtins.serializer import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass -import net.minecraft.util.Rarity +import net.minecraft.world.item.Rarity import org.junit.jupiter.api.assertThrows import kotlin.test.Test import kotlin.test.assertEquals @@ -233,4 +233,4 @@ class CodecTest { val back = NbtCodec.decode(tag) assertEquals("Fireball", back.name) } -} \ No newline at end of file +} diff --git a/ledger/build.gradle.kts b/ledger/build.gradle.kts index f99b1da4..91b8c671 100644 --- a/ledger/build.gradle.kts +++ b/ledger/build.gradle.kts @@ -3,6 +3,8 @@ * Copyright (c) 2026 heckerpowered */ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { kotlin("jvm") } @@ -19,9 +21,20 @@ dependencies { } kotlin { - jvmToolchain(25) + compilerOptions { + jvmTarget = JvmTarget.JVM_25 + } +} + +tasks.withType().configureEach { + options.release = 25 +} + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } tasks.test { useJUnitPlatform() -} \ No newline at end of file +} diff --git a/ledger/src/main/kotlin/heckerpowered/ledger/amount/AmountScale.kt b/ledger/src/main/kotlin/heckerpowered/ledger/amount/AmountScale.kt index 5bf7dd3e..68fd3100 100644 --- a/ledger/src/main/kotlin/heckerpowered/ledger/amount/AmountScale.kt +++ b/ledger/src/main/kotlin/heckerpowered/ledger/amount/AmountScale.kt @@ -18,7 +18,7 @@ import java.math.BigDecimal data class AmountScale( val decimalPlaces: Int, ) { - val scaleFactor = Math.powExact(10L, decimalPlaces) + val scaleFactor = checkedPowerOfTen(decimalPlaces) /** * Creates an [Amount] from whole units. @@ -49,5 +49,17 @@ data class AmountScale( fun of(decimalPlaces: Int): AmountScale { return AmountScale(decimalPlaces) } + + private fun checkedPowerOfTen(exponent: Int): Long { + if (exponent < 0) { + throw ArithmeticException("Negative exponent: $exponent") + } + + var result = 1L + repeat(exponent) { + result = Math.multiplyExact(result, 10L) + } + return result + } } -} \ No newline at end of file +} diff --git a/render-hardware-interface/build.gradle.kts b/render-hardware-interface/build.gradle.kts index f99b1da4..91b8c671 100644 --- a/render-hardware-interface/build.gradle.kts +++ b/render-hardware-interface/build.gradle.kts @@ -3,6 +3,8 @@ * Copyright (c) 2026 heckerpowered */ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { kotlin("jvm") } @@ -19,9 +21,20 @@ dependencies { } kotlin { - jvmToolchain(25) + compilerOptions { + jvmTarget = JvmTarget.JVM_25 + } +} + +tasks.withType().configureEach { + options.release = 25 +} + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } tasks.test { useJUnitPlatform() -} \ No newline at end of file +} diff --git a/render-hardware-interface/src/main/kotlin/heckerpowered/render/api/GraphicsPipelineDescription.kt b/render-hardware-interface/src/main/kotlin/heckerpowered/render/api/GraphicsPipelineDescription.kt new file mode 100644 index 00000000..a842abcf --- /dev/null +++ b/render-hardware-interface/src/main/kotlin/heckerpowered/render/api/GraphicsPipelineDescription.kt @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.render.api + +data class GraphicsPipelineDescription( + val state: GraphicsPipelineState = GraphicsPipelineState(emptyList()), +)