Mod now compiles on 1.20.2

This commit is contained in:
DBotThePony 2023-10-07 22:23:52 +07:00
parent 1f4292012b
commit c32a5bf71b
Signed by: DBot
GPG Key ID: DCC23B5715498507
102 changed files with 1251 additions and 1495 deletions

View File

@ -142,7 +142,6 @@ dependencies {
if (handleDeps) { if (handleDeps) {
val jei_version: String by project val jei_version: String by project
val mekanism_version: String by project
val cosmetic_armor_reworked_id: String by project val cosmetic_armor_reworked_id: String by project
val jade_id: String by project val jade_id: String by project
val configured_id: String by project val configured_id: String by project
@ -174,7 +173,7 @@ dependencies {
// runtimeOnly(fg.deobf("curse.maven:worldedit-225608:${worldedit_fileid}")) // runtimeOnly(fg.deobf("curse.maven:worldedit-225608:${worldedit_fileid}"))
// runtimeOnly(fg.deobf("at.ridgo8.moreoverlays:MoreOverlays-updated:${more_overlays_version}")) // runtimeOnly(fg.deobf("at.ridgo8.moreoverlays:MoreOverlays-updated:${more_overlays_version}"))
compileOnly(fg.deobf("mekanism:Mekanism:${mekanism_version}:all")) compileOnly(fg.deobf("mekanism:Mekanism:1.20.1-10.3.9.homebaked:all"))
// runtimeOnly(fg.deobf("curse.maven:cyclops-core-232758:4392602")) // runtimeOnly(fg.deobf("curse.maven:cyclops-core-232758:4392602"))
// runtimeOnly(fg.deobf("curse.maven:integrated-dynamics-236307:4391535")) // runtimeOnly(fg.deobf("curse.maven:integrated-dynamics-236307:4391535"))
@ -395,21 +394,3 @@ if (project.hasProperty("mavenUser") && project.hasProperty("mavenPassword") &&
} }
} }
} }
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
// publish.dependsOn("reobfJar")
/*
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file://${project.projectDir}/mcmodsrepo"
}
}
}
*/

View File

@ -6,12 +6,11 @@ kotlin.stdlib.default.dependency=false
org.gradle.vfs.watch=true org.gradle.vfs.watch=true
mod_id=overdrive_that_matters mod_id=overdrive_that_matters
mod_version=1.3 mod_version=1.4
use_commit_hash_in_version=true use_commit_hash_in_version=true
mc_version=1.20.2 mc_version=1.20.2
use_parchment=false
jei_mc_version=1.20.2 jei_mc_version=1.20.2
curios_mc_version=1.20 curios_mc_version=1.20
@ -22,7 +21,6 @@ mixin_version=0.8.5
jei_version=16.0.0.28 jei_version=16.0.0.28
jupiter_version=5.9.2 jupiter_version=5.9.2
mekanism_version=1.20.1-10.3.9.homebaked
curios_version=5.2.0-beta.2 curios_version=5.2.0-beta.2
cosmetic_armor_reworked_id=4575609 cosmetic_armor_reworked_id=4575609
ad_astra_id=4594155 ad_astra_id=4594155

View File

@ -508,8 +508,8 @@ object DataGen {
val tagsProvider = TagsProvider(event) val tagsProvider = TagsProvider(event)
val advancementProvider = object : ForgeAdvancementProvider(event.generator.packOutput, event.lookupProvider, event.existingFileHelper, listOf( val advancementProvider = object : ForgeAdvancementProvider(event.generator.packOutput, event.lookupProvider, event.existingFileHelper, listOf(
AdvancementGenerator { registries, saver, existingFileHelper -> AdvancementGenerator { registries, saver, existingFileHelper ->
addAdvancements(saver, existingFileHelper, languageProvider) addAdvancements(saver, languageProvider)
addAndroidAdvancements(saver, existingFileHelper, languageProvider) addAndroidAdvancements(saver, languageProvider)
} }
)) {} )) {}

View File

@ -1,9 +1,11 @@
package ru.dbotthepony.mc.otm.datagen.advancements package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.Advancement import net.minecraft.advancements.Advancement
import net.minecraft.advancements.AdvancementHolder
import net.minecraft.advancements.AdvancementRequirements
import net.minecraft.advancements.AdvancementRewards import net.minecraft.advancements.AdvancementRewards
import net.minecraft.advancements.FrameType import net.minecraft.advancements.FrameType
import net.minecraft.advancements.RequirementsStrategy import net.minecraft.advancements.AdvancementRequirements.Strategy
import net.minecraft.advancements.critereon.InventoryChangeTrigger import net.minecraft.advancements.critereon.InventoryChangeTrigger
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -18,11 +20,11 @@ import ru.dbotthepony.mc.otm.triggers.BlackHoleTrigger
import ru.dbotthepony.mc.otm.triggers.NailedEntityTrigger import ru.dbotthepony.mc.otm.triggers.NailedEntityTrigger
import java.util.function.Consumer import java.util.function.Consumer
fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: ExistingFileHelper, lang: MatteryLanguageProvider) { fun addAdvancements(serializer: Consumer<AdvancementHolder>, lang: MatteryLanguageProvider) {
val translation = lang.MultiBuilder("otm.advancements.regular") val translation = lang.MultiBuilder("otm.advancements.regular")
val root = AdvancementBuilder() val root = AdvancementBuilder()
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.display( .display(
itemStack = ItemStack(MItems.TRITANIUM_INGOT), itemStack = ItemStack(MItems.TRITANIUM_INGOT),
title = translation.add("root", "Overdrive That Matters"), title = translation.add("root", "Overdrive That Matters"),
@ -36,9 +38,9 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
.addCriterion("has_tritanium_ore", criterion(MItemTags.TRITANIUM_ORES)) .addCriterion("has_tritanium_ore", criterion(MItemTags.TRITANIUM_ORES))
.addCriterion("has_tritanium_ore_clump", criterion(MItemTags.TRITANIUM_ORE_CLUMPS)) .addCriterion("has_tritanium_ore_clump", criterion(MItemTags.TRITANIUM_ORE_CLUMPS))
.addCriterion("has_tritanium_ingot", InventoryChangeTrigger.TriggerInstance.hasItems(MItems.TRITANIUM_INGOT)) .addCriterion("has_tritanium_ingot", InventoryChangeTrigger.TriggerInstance.hasItems(MItems.TRITANIUM_INGOT))
.save(serializer, modLocation("regular/root"), existingFileHelper) .save(serializer, modLocation("regular/root"))
addMachineAdvancements(serializer, existingFileHelper, lang, root) addMachineAdvancements(serializer, lang, root)
val crude = AdvancementBuilder() val crude = AdvancementBuilder()
.parent(root) .parent(root)
@ -52,7 +54,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.BATTERY_CRUDE)) .addCriterion("has_item", criterion(MItems.BATTERY_CRUDE))
.save(serializer, modLocation("regular/crude_battery"), existingFileHelper) .save(serializer, modLocation("regular/crude_battery"))
val normal = AdvancementBuilder() val normal = AdvancementBuilder()
.parent(crude) .parent(crude)
@ -66,7 +68,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.BATTERY_NORMAL)) .addCriterion("has_item", criterion(MItems.BATTERY_NORMAL))
.save(serializer, modLocation("regular/normal_battery"), existingFileHelper) .save(serializer, modLocation("regular/normal_battery"))
AdvancementBuilder() AdvancementBuilder()
.parent(normal) .parent(normal)
@ -80,7 +82,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.BATTERY_DENSE)) .addCriterion("has_item", criterion(MItems.BATTERY_DENSE))
.save(serializer, modLocation("regular/dense_battery"), existingFileHelper) .save(serializer, modLocation("regular/dense_battery"))
val capacitor = AdvancementBuilder() val capacitor = AdvancementBuilder()
.parent(normal) .parent(normal)
@ -94,7 +96,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.BATTERY_CAPACITOR)) .addCriterion("has_item", criterion(MItems.BATTERY_CAPACITOR))
.save(serializer, modLocation("regular/capacitor_battery"), existingFileHelper) .save(serializer, modLocation("regular/capacitor_battery"))
AdvancementBuilder() AdvancementBuilder()
.parent(capacitor) .parent(capacitor)
@ -109,7 +111,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("has_item", criterion(MItems.ENERGY_SWORD)) .addCriterion("has_item", criterion(MItems.ENERGY_SWORD))
.save(serializer, modLocation("regular/energy_sword"), existingFileHelper) .save(serializer, modLocation("regular/energy_sword"))
AdvancementBuilder() AdvancementBuilder()
.parent(normal) .parent(normal)
@ -124,10 +126,10 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.rewards(AdvancementRewards.Builder.experience(50)) .rewards(AdvancementRewards.Builder.experience(50))
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("has_item0", criterion(MItems.QUANTUM_BATTERY)) .addCriterion("has_item0", criterion(MItems.QUANTUM_BATTERY))
.addCriterion("has_item1", criterion(MItems.QUANTUM_CAPACITOR)) .addCriterion("has_item1", criterion(MItems.QUANTUM_CAPACITOR))
.save(serializer, modLocation("regular/quantum_battery"), existingFileHelper) .save(serializer, modLocation("regular/quantum_battery"))
val zpm = AdvancementBuilder() val zpm = AdvancementBuilder()
.parent(root) .parent(root)
@ -144,9 +146,9 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
) )
.rewards(AdvancementRewards.Builder.experience(800)) .rewards(AdvancementRewards.Builder.experience(800))
.addCriterion("has_item", criterion(MItems.ZPM_BATTERY)) .addCriterion("has_item", criterion(MItems.ZPM_BATTERY))
.save(serializer, modLocation("regular/zpm_battery"), existingFileHelper) .save(serializer, modLocation("regular/zpm_battery"))
addExopackAdvancements(serializer, existingFileHelper, lang, root, zpm) addExopackAdvancements(serializer, lang, root, zpm)
val blackhole = AdvancementBuilder() val blackhole = AdvancementBuilder()
.parent(root) .parent(root)
@ -160,8 +162,8 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
hidden = true hidden = true
) )
.addCriterion("pulled_by_black_hole", BlackHoleTrigger.instance) .addCriterion("pulled_by_black_hole", BlackHoleTrigger.criterion)
.save(serializer, modLocation("regular/black_hole"), existingFileHelper) .save(serializer, modLocation("regular/black_hole"))
AdvancementBuilder() AdvancementBuilder()
.parent(blackhole) .parent(blackhole)
@ -175,7 +177,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.BLACK_HOLE_SCANNER)) .addCriterion("has_item", criterion(MItems.BLACK_HOLE_SCANNER))
.save(serializer, modLocation("regular/black_hole_scanner"), existingFileHelper) .save(serializer, modLocation("regular/black_hole_scanner"))
AdvancementBuilder() AdvancementBuilder()
.parent(blackhole) .parent(blackhole)
@ -189,7 +191,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.GRAVITATION_STABILIZER)) .addCriterion("has_item", criterion(MItems.GRAVITATION_STABILIZER))
.save(serializer, modLocation("regular/stabilizer"), existingFileHelper) .save(serializer, modLocation("regular/stabilizer"))
AdvancementBuilder() AdvancementBuilder()
.parent(blackhole) .parent(blackhole)
@ -203,11 +205,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_item", criterion(MItems.PORTABLE_GRAVITATION_STABILIZER)) .addCriterion("has_item", criterion(MItems.PORTABLE_GRAVITATION_STABILIZER))
.save(serializer, modLocation("regular/portable_stabilizer"), existingFileHelper) .save(serializer, modLocation("regular/portable_stabilizer"))
val ore = AdvancementBuilder() val ore = AdvancementBuilder()
.parent(root) .parent(root)
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.display( .display(
itemStack = ItemStack(MItems.TRITANIUM_ORE_CLUMP), itemStack = ItemStack(MItems.TRITANIUM_ORE_CLUMP),
title = translation.add("ore", "Blue Metal Discovery") { title = translation.add("ore", "Blue Metal Discovery") {
@ -219,7 +221,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
) )
.addCriterion("has_tritanium_ore", criterion(MItemTags.TRITANIUM_ORES)) .addCriterion("has_tritanium_ore", criterion(MItemTags.TRITANIUM_ORES))
.addCriterion("has_tritanium_ore_clump", criterion(MItemTags.TRITANIUM_ORE_CLUMPS)) .addCriterion("has_tritanium_ore_clump", criterion(MItemTags.TRITANIUM_ORE_CLUMPS))
.save(serializer, modLocation("regular/ore"), existingFileHelper) .save(serializer, modLocation("regular/ore"))
val ingot = AdvancementBuilder() val ingot = AdvancementBuilder()
.parent(ore) .parent(ore)
@ -233,7 +235,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_tritanium_ingot", criterion(MItemTags.TRITANIUM_INGOTS)) .addCriterion("has_tritanium_ingot", criterion(MItemTags.TRITANIUM_INGOTS))
.save(serializer, modLocation("regular/ingot"), existingFileHelper) .save(serializer, modLocation("regular/ingot"))
AdvancementBuilder() AdvancementBuilder()
.parent(ingot) .parent(ingot)
@ -247,7 +249,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
) )
.addCriterion("has_tritanium_pickaxe", criterion(MItems.TRITANIUM_PICKAXE)) .addCriterion("has_tritanium_pickaxe", criterion(MItems.TRITANIUM_PICKAXE))
.save(serializer, modLocation("regular/pickaxe"), existingFileHelper) .save(serializer, modLocation("regular/pickaxe"))
AdvancementBuilder() AdvancementBuilder()
.parent(ingot) .parent(ingot)
@ -262,7 +264,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
hidden = true hidden = true
) )
.addCriterion("hoe", criterion(MItems.TRITANIUM_HOE)) .addCriterion("hoe", criterion(MItems.TRITANIUM_HOE))
.save(serializer, modLocation("regular/hoe"), existingFileHelper) .save(serializer, modLocation("regular/hoe"))
val plate = AdvancementBuilder() val plate = AdvancementBuilder()
.parent(ingot) .parent(ingot)
@ -276,7 +278,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
} }
) )
.addCriterion("has_item", criterion(MItemTags.TRITANIUM_PLATES)) .addCriterion("has_item", criterion(MItemTags.TRITANIUM_PLATES))
.save(serializer, modLocation("regular/plate"), existingFileHelper) .save(serializer, modLocation("regular/plate"))
AdvancementBuilder() AdvancementBuilder()
.parent(plate) .parent(plate)
@ -289,12 +291,12 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Согните немного тритановых пластин вместе с углеродной сеткой в невероятно прочную броню") russian("Согните немного тритановых пластин вместе с углеродной сеткой в невероятно прочную броню")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("has_item0", criterion(MItems.TRITANIUM_HELMET)) .addCriterion("has_item0", criterion(MItems.TRITANIUM_HELMET))
.addCriterion("has_item1", criterion(MItems.TRITANIUM_CHESTPLATE)) .addCriterion("has_item1", criterion(MItems.TRITANIUM_CHESTPLATE))
.addCriterion("has_item2", criterion(MItems.TRITANIUM_PANTS)) .addCriterion("has_item2", criterion(MItems.TRITANIUM_PANTS))
.addCriterion("has_item3", criterion(MItems.TRITANIUM_BOOTS)) .addCriterion("has_item3", criterion(MItems.TRITANIUM_BOOTS))
.save(serializer, modLocation("regular/armor"), existingFileHelper) .save(serializer, modLocation("regular/armor"))
AdvancementBuilder() AdvancementBuilder()
.parent(ingot) .parent(ingot)
@ -307,12 +309,12 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Создайте простую тритановую броню из слитков, просто и эффективно") russian("Создайте простую тритановую броню из слитков, просто и эффективно")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("has_item0", criterion(MItems.SIMPLE_TRITANIUM_HELMET)) .addCriterion("has_item0", criterion(MItems.SIMPLE_TRITANIUM_HELMET))
.addCriterion("has_item1", criterion(MItems.SIMPLE_TRITANIUM_CHESTPLATE)) .addCriterion("has_item1", criterion(MItems.SIMPLE_TRITANIUM_CHESTPLATE))
.addCriterion("has_item2", criterion(MItems.SIMPLE_TRITANIUM_PANTS)) .addCriterion("has_item2", criterion(MItems.SIMPLE_TRITANIUM_PANTS))
.addCriterion("has_item3", criterion(MItems.SIMPLE_TRITANIUM_BOOTS)) .addCriterion("has_item3", criterion(MItems.SIMPLE_TRITANIUM_BOOTS))
.save(serializer, modLocation("regular/simple_armor"), existingFileHelper) .save(serializer, modLocation("regular/simple_armor"))
val glass = AdvancementBuilder() val glass = AdvancementBuilder()
.parent(plate) .parent(plate)
@ -325,11 +327,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("В инструкции указано что оно должно быть пуленепробиваемо.") russian("В инструкции указано что оно должно быть пуленепробиваемо.")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.also { advancement -> .also { advancement ->
MRegistry.INDUSTRIAL_GLASS.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.INDUSTRIAL_GLASS.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/industrial_glass"), existingFileHelper) .save(serializer, modLocation("regular/industrial_glass"))
AdvancementBuilder() AdvancementBuilder()
.parent(glass) .parent(glass)
@ -343,11 +345,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.requirements(RequirementsStrategy.AND) .requirements(Strategy.AND)
.also { advancement -> .also { advancement ->
MRegistry.INDUSTRIAL_GLASS.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.INDUSTRIAL_GLASS.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/industrial_glass2"), existingFileHelper) .save(serializer, modLocation("regular/industrial_glass2"))
val cargoCrate = AdvancementBuilder() val cargoCrate = AdvancementBuilder()
.parent(plate) .parent(plate)
@ -360,11 +362,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Грузовые ящики, будто двойные сундуки, но одинарные.") russian("Грузовые ящики, будто двойные сундуки, но одинарные.")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.also { advancement -> .also { advancement ->
MRegistry.CARGO_CRATES.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.CARGO_CRATES.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/cargo_crate"), existingFileHelper) .save(serializer, modLocation("regular/cargo_crate"))
val cargoCrateInMinecart = AdvancementBuilder() val cargoCrateInMinecart = AdvancementBuilder()
.parent(cargoCrate) .parent(cargoCrate)
@ -377,11 +379,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Сбросьте грузовой ящик в вагонетку и посмотрите, что получится") russian("Сбросьте грузовой ящик в вагонетку и посмотрите, что получится")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.also { advancement -> .also { advancement ->
MItems.CARGO_CRATE_MINECARTS.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.CARGO_CRATE_MINECARTS.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/cargo_crate_minecart"), existingFileHelper) .save(serializer, modLocation("regular/cargo_crate_minecart"))
AdvancementBuilder() AdvancementBuilder()
.parent(cargoCrateInMinecart) .parent(cargoCrateInMinecart)
@ -395,11 +397,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.requirements(RequirementsStrategy.AND) .requirements(Strategy.AND)
.also { advancement -> .also { advancement ->
MItems.CARGO_CRATE_MINECARTS.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.CARGO_CRATE_MINECARTS.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/cargo_crate_minecart2"), existingFileHelper) .save(serializer, modLocation("regular/cargo_crate_minecart2"))
AdvancementBuilder() AdvancementBuilder()
.parent(cargoCrate) .parent(cargoCrate)
@ -413,11 +415,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.requirements(RequirementsStrategy.AND) .requirements(Strategy.AND)
.also { advancement -> .also { advancement ->
MRegistry.CARGO_CRATES.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.CARGO_CRATES.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/cargo_crate2"), existingFileHelper) .save(serializer, modLocation("regular/cargo_crate2"))
val tritaniumBlock = AdvancementBuilder() val tritaniumBlock = AdvancementBuilder()
.parent(ingot) .parent(ingot)
@ -430,7 +432,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Покройте булыжник в тритане, дешёвый, но невероятно прочный материал") russian("Покройте булыжник в тритане, дешёвый, но невероятно прочный материал")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.also { advancement -> .also { advancement ->
MRegistry.TRITANIUM_BLOCK.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_BLOCK.allItems.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
MRegistry.TRITANIUM_STRIPED_BLOCK.flatItems.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_STRIPED_BLOCK.flatItems.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
@ -439,7 +441,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
MItems.TRITANIUM_STRIPED_BLOCK.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.TRITANIUM_STRIPED_BLOCK.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
MItems.TRITANIUM_STRIPED_STAIRS.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.TRITANIUM_STRIPED_STAIRS.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/tritanium_block"), existingFileHelper) .save(serializer, modLocation("regular/tritanium_block"))
AdvancementBuilder() AdvancementBuilder()
.parent(tritaniumBlock) .parent(tritaniumBlock)
@ -452,12 +454,12 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Бледно синяя покраска с жёлтой полоской, я готов поспорить вы знаете чей это дизайн") russian("Бледно синяя покраска с жёлтой полоской, я готов поспорить вы знаете чей это дизайн")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("has_item", criterion(MItems.TRITANIUM_STRIPED_BLOCK)) .addCriterion("has_item", criterion(MItems.TRITANIUM_STRIPED_BLOCK))
.addCriterion("has_item1", criterion(MItems.TRITANIUM_STRIPED_STAIRS)) .addCriterion("has_item1", criterion(MItems.TRITANIUM_STRIPED_STAIRS))
.addCriterion("has_item2", criterion(MItems.TRITANIUM_STRIPED_SLAB)) .addCriterion("has_item2", criterion(MItems.TRITANIUM_STRIPED_SLAB))
.addCriterion("has_item3", criterion(MItems.TRITANIUM_STRIPED_WALL)) .addCriterion("has_item3", criterion(MItems.TRITANIUM_STRIPED_WALL))
.save(serializer, modLocation("regular/striped_tritanium_block"), existingFileHelper) .save(serializer, modLocation("regular/striped_tritanium_block"))
val colorTritaniumBlock = AdvancementBuilder() val colorTritaniumBlock = AdvancementBuilder()
.parent(tritaniumBlock) .parent(tritaniumBlock)
@ -470,7 +472,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Покрасьте тритановый блок для придания ему сказочных оттенков") russian("Покрасьте тритановый блок для придания ему сказочных оттенков")
} }
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.also { advancement -> .also { advancement ->
MRegistry.TRITANIUM_BLOCK.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_BLOCK.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
MRegistry.TRITANIUM_STAIRS.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_STAIRS.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
@ -479,7 +481,7 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
MItems.TRITANIUM_STRIPED_BLOCK.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.TRITANIUM_STRIPED_BLOCK.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
MItems.TRITANIUM_STRIPED_STAIRS.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.TRITANIUM_STRIPED_STAIRS.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/tritanium_block2"), existingFileHelper) .save(serializer, modLocation("regular/tritanium_block2"))
val colorfulTritaniumBlock = AdvancementBuilder() val colorfulTritaniumBlock = AdvancementBuilder()
.parent(colorTritaniumBlock) .parent(colorTritaniumBlock)
@ -494,11 +496,11 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.rewards(AdvancementRewards.Builder.loot(modLocation("tritanium_block3")).addExperience(100)) .rewards(AdvancementRewards.Builder.loot(modLocation("tritanium_block3")).addExperience(100))
.requirements(RequirementsStrategy.AND) .requirements(Strategy.AND)
.also { advancement -> .also { advancement ->
MRegistry.TRITANIUM_BLOCK.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_BLOCK.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/tritanium_block3"), existingFileHelper) .save(serializer, modLocation("regular/tritanium_block3"))
AdvancementBuilder() AdvancementBuilder()
.parent(colorfulTritaniumBlock) .parent(colorfulTritaniumBlock)
@ -513,13 +515,13 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
frameType = FrameType.CHALLENGE frameType = FrameType.CHALLENGE
) )
.rewards(AdvancementRewards.Builder.loot(modLocation("tritanium_block4")).addExperience(400)) .rewards(AdvancementRewards.Builder.loot(modLocation("tritanium_block4")).addExperience(400))
.requirements(RequirementsStrategy.AND) .requirements(Strategy.AND)
.also { advancement -> .also { advancement ->
MRegistry.TRITANIUM_BLOCK.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_BLOCK.items.values.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
MRegistry.TRITANIUM_STRIPED_BLOCK.flatItems.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MRegistry.TRITANIUM_STRIPED_BLOCK.flatItems.forEach { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
MItems.TRITANIUM_STRIPED_BLOCK.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) } MItems.TRITANIUM_STRIPED_BLOCK.also { advancement.addCriterion(it.registryName!!.path, criterion(it)) }
} }
.save(serializer, modLocation("regular/tritanium_block4"), existingFileHelper) .save(serializer, modLocation("regular/tritanium_block4"))
val pill = AdvancementBuilder() val pill = AdvancementBuilder()
.parent(root) .parent(root)
@ -532,12 +534,12 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Найдите одну из этих ваших мистических пилюль") russian("Найдите одну из этих ваших мистических пилюль")
}, },
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("pill1", criterion(MItems.PILL_ANDROID)) .addCriterion("pill1", criterion(MItems.PILL_ANDROID))
.addCriterion("pill2", criterion(MItems.PILL_HEAL)) .addCriterion("pill2", criterion(MItems.PILL_HEAL))
.addCriterion("pill3", criterion(MItems.PILL_HUMANE)) .addCriterion("pill3", criterion(MItems.PILL_HUMANE))
.addCriterion("pill4", criterion(MItems.PILL_OBLIVION)) .addCriterion("pill4", criterion(MItems.PILL_OBLIVION))
.save(serializer, modLocation("regular/pill"), existingFileHelper) .save(serializer, modLocation("regular/pill"))
AdvancementBuilder() AdvancementBuilder()
.parent(pill) .parent(pill)
@ -553,12 +555,12 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
hidden = true hidden = true
) )
.rewards(AdvancementRewards.Builder.experience(200)) .rewards(AdvancementRewards.Builder.experience(200))
.requirements(RequirementsStrategy.AND) .requirements(Strategy.AND)
.addCriterion("pill1", criterion(MItems.PILL_ANDROID)) .addCriterion("pill1", criterion(MItems.PILL_ANDROID))
.addCriterion("pill2", criterion(MItems.PILL_HEAL)) .addCriterion("pill2", criterion(MItems.PILL_HEAL))
.addCriterion("pill3", criterion(MItems.PILL_HUMANE)) .addCriterion("pill3", criterion(MItems.PILL_HUMANE))
.addCriterion("pill4", criterion(MItems.PILL_OBLIVION)) .addCriterion("pill4", criterion(MItems.PILL_OBLIVION))
.save(serializer, modLocation("regular/all_pills"), existingFileHelper) .save(serializer, modLocation("regular/all_pills"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -571,10 +573,10 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Верните капсулу эссенции. Воспоминания...") russian("Верните капсулу эссенции. Воспоминания...")
}, },
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("essence1", criterion(MItems.ESSENCE_CAPSULE)) .addCriterion("essence1", criterion(MItems.ESSENCE_CAPSULE))
.addCriterion("essence2", criterion(MItems.ESSENCE_DRIVE)) .addCriterion("essence2", criterion(MItems.ESSENCE_DRIVE))
.save(serializer, modLocation("regular/essence_capsule"), existingFileHelper) .save(serializer, modLocation("regular/essence_capsule"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -587,6 +589,6 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
russian("Пригвоздите что-либо (или кого-либо)") russian("Пригвоздите что-либо (или кого-либо)")
} }
) )
.addCriterion("damage", NailedEntityTrigger.Instance()) .addCriterion("damage", NailedEntityTrigger.Instance().criterion())
.save(serializer, modLocation("regular/explosive_hammer"), existingFileHelper) .save(serializer, modLocation("regular/explosive_hammer"))
} }

View File

@ -1,9 +1,10 @@
package ru.dbotthepony.mc.otm.datagen.advancements package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.Advancement import net.minecraft.advancements.Advancement
import net.minecraft.advancements.AdvancementHolder
import net.minecraft.advancements.AdvancementRequirements.Strategy
import net.minecraft.advancements.AdvancementRewards import net.minecraft.advancements.AdvancementRewards
import net.minecraft.advancements.FrameType import net.minecraft.advancements.FrameType
import net.minecraft.advancements.RequirementsStrategy
import net.minecraft.advancements.critereon.EntityPredicate import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.advancements.critereon.MinMaxBounds.Doubles import net.minecraft.advancements.critereon.MinMaxBounds.Doubles
@ -30,9 +31,10 @@ import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger
import java.util.*
import java.util.function.Consumer import java.util.function.Consumer
fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper: ExistingFileHelper, lang: MatteryLanguageProvider) { fun addAndroidAdvancements(serializer: Consumer<AdvancementHolder>, lang: MatteryLanguageProvider) {
val translation = lang.MultiBuilder("otm.advancements.android") val translation = lang.MultiBuilder("otm.advancements.android")
val root = AdvancementBuilder() val root = AdvancementBuilder()
@ -48,8 +50,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
announceChat = false, announceChat = false,
background = modLocation("textures/block/decorative/metal_beam_top.png") background = modLocation("textures/block/decorative/metal_beam_top.png")
) )
.addCriterion("became_android", BecomeAndroidTrigger.instance) .addCriterion("became_android", BecomeAndroidTrigger.criterion)
.save(serializer, modLocation("android/root"), existingFileHelper) .save(serializer, modLocation("android/root"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -64,8 +66,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true, hidden = true,
frameType = FrameType.CHALLENGE frameType = FrameType.CHALLENGE
) )
.addCriterion("item", AndroidBatteryTrigger.Instance(ItemPredicate.Builder.item().of(MItems.ZPM_BATTERY).build())) .addCriterion("item", AndroidBatteryTrigger.Instance(ItemPredicate.Builder.item().of(MItems.ZPM_BATTERY).build()).criterion())
.save(serializer, modLocation("android/zpm"), existingFileHelper) .save(serializer, modLocation("android/zpm"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -80,10 +82,10 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true, hidden = true,
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.requirements(RequirementsStrategy.OR) .requirements(Strategy.OR)
.addCriterion("item0", AndroidBatteryTrigger.Instance(ItemPredicate.Builder.item().of(MItems.QUANTUM_BATTERY).build())) .addCriterion("item0", AndroidBatteryTrigger.Instance(ItemPredicate.Builder.item().of(MItems.QUANTUM_BATTERY).build()).criterion())
.addCriterion("item1", AndroidBatteryTrigger.Instance(ItemPredicate.Builder.item().of(MItems.QUANTUM_CAPACITOR).build())) .addCriterion("item1", AndroidBatteryTrigger.Instance(ItemPredicate.Builder.item().of(MItems.QUANTUM_CAPACITOR).build()).criterion())
.save(serializer, modLocation("android/quantum_battery"), existingFileHelper) .save(serializer, modLocation("android/quantum_battery"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -97,8 +99,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
hidden = true, hidden = true,
) )
.addCriterion("became_android", BecomeAndroidSleepTrigger.instance) .addCriterion("became_android", BecomeAndroidSleepTrigger.criterion)
.save(serializer, modLocation("android/become_thru_sleep"), existingFileHelper) .save(serializer, modLocation("android/become_thru_sleep"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -112,8 +114,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
hidden = true, hidden = true,
) )
.addCriterion("became_android", BecomeAndroidDeathTrigger.instance) .addCriterion("became_android", BecomeAndroidDeathTrigger.criterion)
.save(serializer, modLocation("android/become_thru_death"), existingFileHelper) .save(serializer, modLocation("android/become_thru_death"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -128,8 +130,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true, hidden = true,
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("become_humane", BecomeHumaneTrigger.instance) .addCriterion("become_humane", BecomeHumaneTrigger.criterion)
.save(serializer, modLocation("android/become_humane"), existingFileHelper) .save(serializer, modLocation("android/become_humane"))
val attractor = AdvancementBuilder() val attractor = AdvancementBuilder()
.parent(root) .parent(root)
@ -143,7 +145,7 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
) )
.addCriterion("has_item", criterion(MItems.PHANTOM_ATTRACTOR)) .addCriterion("has_item", criterion(MItems.PHANTOM_ATTRACTOR))
.save(serializer, modLocation("regular/phantom_attractor"), existingFileHelper) .save(serializer, modLocation("regular/phantom_attractor"))
val researchAnything = AdvancementBuilder() val researchAnything = AdvancementBuilder()
.parent(root) .parent(root)
@ -156,8 +158,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Исследуйте что либо за андроида") russian("Исследуйте что либо за андроида")
}, },
) )
.addCriterion("research_anything", AndroidResearchTrigger.Instance(null)) .addCriterion("research_anything", AndroidResearchTrigger.Instance(null).criterion())
.save(serializer, modLocation("android/research_anything"), existingFileHelper) .save(serializer, modLocation("android/research_anything"))
AdvancementBuilder() AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -170,8 +172,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Исследуйте воздушные мешки, дабы быть вновь поплавком в воде") russian("Исследуйте воздушные мешки, дабы быть вновь поплавком в воде")
}, },
) )
.addCriterion("air_bags", AndroidResearchTrigger.Instance(modLocation(MNames.AIR_BAGS))) .addCriterion("air_bags", AndroidResearchTrigger.Instance(modLocation(MNames.AIR_BAGS)).criterion())
.save(serializer, modLocation("android/research_air_bags"), existingFileHelper) .save(serializer, modLocation("android/research_air_bags"))
AdvancementBuilder() AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -184,8 +186,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Исследуйте ночное зрение за андроида, дабы видеть во темноте") russian("Исследуйте ночное зрение за андроида, дабы видеть во темноте")
}, },
) )
.addCriterion("night_vision", AndroidResearchTrigger.Instance(modLocation(MNames.NIGHT_VISION))) .addCriterion("night_vision", AndroidResearchTrigger.Instance(modLocation(MNames.NIGHT_VISION)).criterion())
.save(serializer, modLocation("android/research_night_vision"), existingFileHelper) .save(serializer, modLocation("android/research_night_vision"))
val nanobots = AdvancementBuilder() val nanobots = AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -199,8 +201,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
hidden = true hidden = true
) )
.addCriterion("nanobots", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS))) .addCriterion("nanobots", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS)).criterion())
.save(serializer, modLocation("android/research_nanobots"), existingFileHelper) .save(serializer, modLocation("android/research_nanobots"))
val shielding = AdvancementBuilder() val shielding = AdvancementBuilder()
.parent(nanobots) .parent(nanobots)
@ -215,8 +217,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true, hidden = true,
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("damage", NanobotsArmorTrigger.Instance(Doubles.atLeast(10.0))) .addCriterion("damage", NanobotsArmorTrigger.Instance(Doubles.atLeast(10.0)).criterion())
.save(serializer, modLocation("android/nanobots_armor_deflect"), existingFileHelper) .save(serializer, modLocation("android/nanobots_armor_deflect"))
AdvancementBuilder() AdvancementBuilder()
.parent(shielding) .parent(shielding)
@ -231,8 +233,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true, hidden = true,
frameType = FrameType.CHALLENGE frameType = FrameType.CHALLENGE
) )
.addCriterion("damage", NanobotsArmorTrigger.Instance(Doubles.atLeast(20.0))) .addCriterion("damage", NanobotsArmorTrigger.Instance(Doubles.atLeast(20.0)).criterion())
.save(serializer, modLocation("android/nanobots_armor_deflect2"), existingFileHelper) .save(serializer, modLocation("android/nanobots_armor_deflect2"))
AdvancementBuilder() AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -246,8 +248,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("saved", FallDampenersSaveTrigger.instance) .addCriterion("saved", FallDampenersSaveTrigger.criterion)
.save(serializer, modLocation("android/fall_dampeners_save"), existingFileHelper) .save(serializer, modLocation("android/fall_dampeners_save"))
AdvancementBuilder() AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -262,8 +264,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
frameType = FrameType.GOAL, frameType = FrameType.GOAL,
hidden = true hidden = true
) )
.addCriterion("death", EnderTeleporterFallDeathTrigger.instance) .addCriterion("death", EnderTeleporterFallDeathTrigger.criterion)
.save(serializer, modLocation("android/ender_teleport_fall_death"), existingFileHelper) .save(serializer, modLocation("android/ender_teleport_fall_death"))
val regen = AdvancementBuilder() val regen = AdvancementBuilder()
.parent(nanobots) .parent(nanobots)
@ -276,8 +278,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Исследуйте регенерацию наноботов за андроида") russian("Исследуйте регенерацию наноботов за андроида")
}, },
) )
.addCriterion("regen0", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_1))) .addCriterion("regen0", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_1)).criterion())
.save(serializer, modLocation("android/regen"), existingFileHelper) .save(serializer, modLocation("android/regen"))
AdvancementBuilder() AdvancementBuilder()
.parent(regen) .parent(regen)
@ -291,11 +293,11 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL, frameType = FrameType.GOAL,
) )
.addCriterion("regen0", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_1))) .addCriterion("regen0", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_1)).criterion())
.addCriterion("regen1", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_2))) .addCriterion("regen1", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_2)).criterion())
.addCriterion("regen2", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_3))) .addCriterion("regen2", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_3)).criterion())
.addCriterion("regen3", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_4))) .addCriterion("regen3", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_4)).criterion())
.save(serializer, modLocation("android/regen_all"), existingFileHelper) .save(serializer, modLocation("android/regen_all"))
AdvancementBuilder() AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -314,10 +316,10 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
DataGen.researchProvider.generatedView.stream() DataGen.researchProvider.generatedView.stream()
.filter { it.allBlockedBy.isEmpty() && it.allBlocking.isEmpty() } .filter { it.allBlockedBy.isEmpty() && it.allBlocking.isEmpty() }
.forEach { .forEach {
advancement.addCriterion(it.id.toString(), AndroidResearchTrigger.Instance(it)) advancement.addCriterion(it.id.toString(), AndroidResearchTrigger.Instance(it).criterion())
} }
} }
.save(serializer, modLocation("android/research_everything"), existingFileHelper) .save(serializer, modLocation("android/research_everything"))
val shockwave = AdvancementBuilder() val shockwave = AdvancementBuilder()
.parent(researchAnything) .parent(researchAnything)
@ -330,8 +332,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Вызовите ударную волну при приземлении") russian("Вызовите ударную волну при приземлении")
}, },
) )
.addCriterion("shockwave", ShockwaveTrigger.instance) .addCriterion("shockwave", ShockwaveTrigger.criterion)
.save(serializer, modLocation("android/shockwave"), existingFileHelper) .save(serializer, modLocation("android/shockwave"))
AdvancementBuilder() AdvancementBuilder()
.parent(shockwave) .parent(shockwave)
@ -345,8 +347,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("shockwave_warden", ShockwaveDamageMobTrigger.Instance(EntityPredicate.Builder.entity().of(EntityType.WARDEN).build().wrap())) .addCriterion("shockwave_warden", ShockwaveDamageMobTrigger.Instance(Optional.of(EntityPredicate.Builder.entity().of(EntityType.WARDEN).build().wrap())).criterion())
.save(serializer, modLocation("android/shockwave_warden"), existingFileHelper) .save(serializer, modLocation("android/shockwave_warden"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -362,9 +364,9 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true hidden = true
) )
.addCriterion("kill_wither", KillAsAndroidTrigger.Instance( .addCriterion("kill_wither", KillAsAndroidTrigger.Instance(
predicate = EntityPredicate.Builder.entity().of(EntityType.WITHER).build().wrap(), predicate = Optional.of(EntityPredicate.Builder.entity().of(EntityType.WITHER).build().wrap()),
)) ).criterion())
.save(serializer, modLocation("android/wither"), existingFileHelper) .save(serializer, modLocation("android/wither"))
val underwater = AdvancementBuilder() val underwater = AdvancementBuilder()
.parent(root) .parent(root)
@ -379,8 +381,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
frameType = FrameType.GOAL, frameType = FrameType.GOAL,
hidden = true hidden = true
) )
.addCriterion("travel", AndroidTravelUnderwater.Instance(200.0)) .addCriterion("travel", AndroidTravelUnderwater.Instance(200.0).criterion())
.save(serializer, modLocation("android/underwater"), existingFileHelper) .save(serializer, modLocation("android/underwater"))
AdvancementBuilder() AdvancementBuilder()
.parent(underwater) .parent(underwater)
@ -395,8 +397,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
frameType = FrameType.CHALLENGE, frameType = FrameType.CHALLENGE,
hidden = true hidden = true
) )
.addCriterion("travel", AndroidTravelUnderwater.Instance(1046.0)) .addCriterion("travel", AndroidTravelUnderwater.Instance(1046.0).criterion())
.save(serializer, modLocation("android/underwater2"), existingFileHelper) .save(serializer, modLocation("android/underwater2"))
AdvancementBuilder() AdvancementBuilder()
.parent(root) .parent(root)
@ -412,8 +414,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
hidden = true hidden = true
) )
.addCriterion("kill_elder_guardian", KillAsAndroidTrigger.Instance( .addCriterion("kill_elder_guardian", KillAsAndroidTrigger.Instance(
predicate = EntityPredicate.Builder.entity().of(EntityType.ELDER_GUARDIAN).build().wrap(), predicate = Optional.of(EntityPredicate.Builder.entity().of(EntityType.ELDER_GUARDIAN).build().wrap()),
featurePredicate = KillAsAndroidTrigger.Not(KillAsAndroidTrigger.Has(AndroidFeatures.AIR_BAGS.registryName!!)) featurePredicate = KillAsAndroidTrigger.Not(KillAsAndroidTrigger.Has(AndroidFeatures.AIR_BAGS.registryName!!))
)) ).criterion())
.save(serializer, modLocation("android/elder_guardian"), existingFileHelper) .save(serializer, modLocation("android/elder_guardian"))
} }

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.datagen.advancements package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.Advancement import net.minecraft.advancements.Advancement
import net.minecraft.advancements.AdvancementHolder
import net.minecraft.advancements.FrameType import net.minecraft.advancements.FrameType
import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -17,7 +18,7 @@ import ru.dbotthepony.mc.otm.triggers.ExopackObtainedTrigger
import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger
import java.util.function.Consumer import java.util.function.Consumer
fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper: ExistingFileHelper, lang: MatteryLanguageProvider, root: Advancement, zpm: Advancement) { fun addExopackAdvancements(serializer: Consumer<AdvancementHolder>, lang: MatteryLanguageProvider, root: AdvancementHolder, zpm: AdvancementHolder) {
val translation = lang.MultiBuilder("otm.advancements.exopack") val translation = lang.MultiBuilder("otm.advancements.exopack")
AdvancementBuilder() AdvancementBuilder()
@ -33,8 +34,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("zpm_battery", ExopackBatterySlotTrigger.Instance(ItemPredicate.Builder.item().of(MItems.ZPM_BATTERY).build())) .addCriterion("zpm_battery", ExopackBatterySlotTrigger.Instance(ItemPredicate.Builder.item().of(MItems.ZPM_BATTERY).build()).criterion())
.save(serializer, modLocation("exopack/zpm_battery"), existingFileHelper) .save(serializer, modLocation("exopack/zpm_battery"))
val obtained = AdvancementBuilder() val obtained = AdvancementBuilder()
.parent(root) .parent(root)
@ -48,8 +49,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("obtained", ExopackObtainedTrigger.instance) .addCriterion("obtained", ExopackObtainedTrigger.criterion)
.save(serializer, modLocation("exopack/obtained"), existingFileHelper) .save(serializer, modLocation("exopack/obtained"))
AdvancementBuilder() AdvancementBuilder()
.parent(obtained) .parent(obtained)
@ -62,8 +63,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Установите улучшение сетки крафта в ваш Экзопаке, который позволяет создавать предметы, требующие сетку крафта рабочего стола") russian("Установите улучшение сетки крафта в ваш Экзопаке, который позволяет создавать предметы, требующие сетку крафта рабочего стола")
}, },
) )
.addCriterion("crafting", ExopackGainedCraftingTrigger.instance) .addCriterion("crafting", ExopackGainedCraftingTrigger.criterion)
.save(serializer, modLocation("exopack/crafting"), existingFileHelper) .save(serializer, modLocation("exopack/crafting"))
AdvancementBuilder() AdvancementBuilder()
.parent(obtained) .parent(obtained)
@ -76,8 +77,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Установите модуль переплавки в ваш Экзопак, позволяющий переплавлять предметы прямо у вас в инвентаре") russian("Установите модуль переплавки в ваш Экзопак, позволяющий переплавлять предметы прямо у вас в инвентаре")
}, },
) )
.addCriterion("smelting", ExopackGainedSmeltingTrigger.instance) .addCriterion("smelting", ExopackGainedSmeltingTrigger.criterion)
.save(serializer, modLocation("exopack/smelting"), existingFileHelper) .save(serializer, modLocation("exopack/smelting"))
AdvancementBuilder() AdvancementBuilder()
.parent(obtained) .parent(obtained)
@ -90,8 +91,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Получите прямой доступ к содержимому вашего сундука края прямо из Экзопака") russian("Получите прямой доступ к содержимому вашего сундука края прямо из Экзопака")
}, },
) )
.addCriterion("ender_access", ExopackGainedEnderAccessTrigger.instance) .addCriterion("ender_access", ExopackGainedEnderAccessTrigger.criterion)
.save(serializer, modLocation("ender_access/smelting"), existingFileHelper) .save(serializer, modLocation("ender_access/smelting"))
var size = AdvancementBuilder() var size = AdvancementBuilder()
.parent(obtained) .parent(obtained)
@ -104,8 +105,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Улучшите размер инвентаря Экзопака") russian("Улучшите размер инвентаря Экзопака")
}, },
) )
.addCriterion("size0", ExopackSlotsExpandedTrigger.Instance(minTotal = 1)) .addCriterion("size0", ExopackSlotsExpandedTrigger.Instance(minTotal = 1).criterion())
.save(serializer, modLocation("exopack/size0"), existingFileHelper) .save(serializer, modLocation("exopack/size0"))
val size0 = size val size0 = size
@ -120,8 +121,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Достигните 27 слотов хранилища Экзопака") russian("Достигните 27 слотов хранилища Экзопака")
}, },
) )
.addCriterion("size1", ExopackSlotsExpandedTrigger.Instance(minTotal = 27)) .addCriterion("size1", ExopackSlotsExpandedTrigger.Instance(minTotal = 27).criterion())
.save(serializer, modLocation("exopack/size1"), existingFileHelper) .save(serializer, modLocation("exopack/size1"))
size = AdvancementBuilder() size = AdvancementBuilder()
.parent(size) .parent(size)
@ -135,8 +136,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Достигните 54 слотов хранилища Экзопака") russian("Достигните 54 слотов хранилища Экзопака")
}, },
) )
.addCriterion("size2", ExopackSlotsExpandedTrigger.Instance(minTotal = 54)) .addCriterion("size2", ExopackSlotsExpandedTrigger.Instance(minTotal = 54).criterion())
.save(serializer, modLocation("exopack/size2"), existingFileHelper) .save(serializer, modLocation("exopack/size2"))
size = AdvancementBuilder() size = AdvancementBuilder()
.parent(size) .parent(size)
@ -151,8 +152,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("size3", ExopackSlotsExpandedTrigger.Instance(minTotal = 108)) .addCriterion("size3", ExopackSlotsExpandedTrigger.Instance(minTotal = 108).criterion())
.save(serializer, modLocation("exopack/size3"), existingFileHelper) .save(serializer, modLocation("exopack/size3"))
size = AdvancementBuilder() size = AdvancementBuilder()
.parent(size) .parent(size)
@ -167,8 +168,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.CHALLENGE frameType = FrameType.CHALLENGE
) )
.addCriterion("size4", ExopackSlotsExpandedTrigger.Instance(minTotal = 432)) .addCriterion("size4", ExopackSlotsExpandedTrigger.Instance(minTotal = 432).criterion())
.save(serializer, modLocation("exopack/size4"), existingFileHelper) .save(serializer, modLocation("exopack/size4"))
AdvancementBuilder() AdvancementBuilder()
.parent(size) .parent(size)
@ -183,8 +184,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.CHALLENGE frameType = FrameType.CHALLENGE
) )
.addCriterion("size5", ExopackSlotsExpandedTrigger.Instance(minTotal = 1728)) .addCriterion("size5", ExopackSlotsExpandedTrigger.Instance(minTotal = 1728).criterion())
.save(serializer, modLocation("exopack/size5"), existingFileHelper) .save(serializer, modLocation("exopack/size5"))
var once = AdvancementBuilder() var once = AdvancementBuilder()
.parent(size0) .parent(size0)
@ -197,8 +198,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Улучшите хранилище Экзопака модулем на 9 слотов") russian("Улучшите хранилище Экзопака модулем на 9 слотов")
}, },
) )
.addCriterion("once0", ExopackSlotsExpandedTrigger.Instance(minGained = 9)) .addCriterion("once0", ExopackSlotsExpandedTrigger.Instance(minGained = 9).criterion())
.save(serializer, modLocation("exopack/once0"), existingFileHelper) .save(serializer, modLocation("exopack/once0"))
once = AdvancementBuilder() once = AdvancementBuilder()
.parent(once) .parent(once)
@ -211,8 +212,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Улучшите хранилище Экзопака модулем на 27 слотов") russian("Улучшите хранилище Экзопака модулем на 27 слотов")
}, },
) )
.addCriterion("once1", ExopackSlotsExpandedTrigger.Instance(minGained = 27)) .addCriterion("once1", ExopackSlotsExpandedTrigger.Instance(minGained = 27).criterion())
.save(serializer, modLocation("exopack/once1"), existingFileHelper) .save(serializer, modLocation("exopack/once1"))
once = AdvancementBuilder() once = AdvancementBuilder()
.parent(once) .parent(once)
@ -227,8 +228,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("once2", ExopackSlotsExpandedTrigger.Instance(minGained = 54)) .addCriterion("once2", ExopackSlotsExpandedTrigger.Instance(minGained = 54).criterion())
.save(serializer, modLocation("exopack/once2"), existingFileHelper) .save(serializer, modLocation("exopack/once2"))
once = AdvancementBuilder() once = AdvancementBuilder()
.parent(once) .parent(once)
@ -243,8 +244,8 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("once3", ExopackSlotsExpandedTrigger.Instance(minGained = 90)) .addCriterion("once3", ExopackSlotsExpandedTrigger.Instance(minGained = 90).criterion())
.save(serializer, modLocation("exopack/once3"), existingFileHelper) .save(serializer, modLocation("exopack/once3"))
AdvancementBuilder() AdvancementBuilder()
.parent(once) .parent(once)
@ -259,6 +260,6 @@ fun addExopackAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.CHALLENGE frameType = FrameType.CHALLENGE
) )
.addCriterion("once4", ExopackSlotsExpandedTrigger.Instance(minGained = 150)) .addCriterion("once4", ExopackSlotsExpandedTrigger.Instance(minGained = 150).criterion())
.save(serializer, modLocation("exopack/once4"), existingFileHelper) .save(serializer, modLocation("exopack/once4"))
} }

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.datagen.advancements package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.Advancement import net.minecraft.advancements.Advancement
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.CriterionTriggerInstance import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.advancements.DisplayInfo import net.minecraft.advancements.DisplayInfo
import net.minecraft.advancements.FrameType import net.minecraft.advancements.FrameType
@ -57,7 +58,7 @@ fun predicate(tag: TagKey<Item>): ItemPredicate {
return ItemPredicate.Builder.item().of(tag).build() return ItemPredicate.Builder.item().of(tag).build()
} }
fun criterion(tag: TagKey<Item>): CriterionTriggerInstance { fun criterion(tag: TagKey<Item>): Criterion<*> {
return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(tag)) return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(tag))
} }
@ -65,7 +66,7 @@ fun predicate(item: ItemLike): ItemPredicate {
return ItemPredicate.Builder.item().of(item).build() return ItemPredicate.Builder.item().of(item).build()
} }
fun criterion(item: ItemLike): CriterionTriggerInstance { fun criterion(item: ItemLike): Criterion<*> {
return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(item)) return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(item))
} }

View File

@ -1,20 +1,16 @@
package ru.dbotthepony.mc.otm.datagen.advancements package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.Advancement import net.minecraft.advancements.AdvancementHolder
import net.minecraft.advancements.FrameType import net.minecraft.advancements.FrameType
import net.minecraft.advancements.RequirementsStrategy
import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.network.chat.contents.TranslatableContents
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import net.minecraftforge.common.data.ExistingFileHelper
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.key import ru.dbotthepony.mc.otm.core.key
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider
import ru.dbotthepony.mc.otm.datagen.modLocation import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.triggers.TakeItemOutOfReplicatorTrigger import ru.dbotthepony.mc.otm.triggers.TakeItemOutOfReplicatorTrigger
import java.util.function.Consumer import java.util.function.Consumer
@ -27,7 +23,7 @@ private data class CraftEntry(
val russianName: String? = null, val russianName: String? = null,
val russianSuffix: String? = null, val russianSuffix: String? = null,
) { ) {
fun make(serializer: Consumer<Advancement>, existingFileHelper: ExistingFileHelper, parent: Advancement, translation: MatteryLanguageProvider.MultiBuilder): Advancement { fun make(serializer: Consumer<AdvancementHolder>, parent: AdvancementHolder, translation: MatteryLanguageProvider.MultiBuilder): AdvancementHolder {
val path = item.registryName!!.path val path = item.registryName!!.path
val translated = translation.add("$path.desc", "Craft a %s%s") { val translated = translation.add("$path.desc", "Craft a %s%s") {
@ -50,11 +46,11 @@ private data class CraftEntry(
description = TranslatableComponent(translated.contents.key, item.description, translatedSuffix), description = TranslatableComponent(translated.contents.key, item.description, translatedSuffix),
) )
.addCriterion("has_machine", criterion(item)) .addCriterion("has_machine", criterion(item))
.save(serializer, modLocation("machines/$path"), existingFileHelper) .save(serializer, modLocation("machines/$path"))
} }
} }
fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper: ExistingFileHelper, lang: MatteryLanguageProvider, root: Advancement) { fun addMachineAdvancements(serializer: Consumer<AdvancementHolder>, lang: MatteryLanguageProvider, root: AdvancementHolder) {
val translation = lang.MultiBuilder("otm.advancements.machine") val translation = lang.MultiBuilder("otm.advancements.machine")
val chem = AdvancementBuilder() val chem = AdvancementBuilder()
@ -69,7 +65,7 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
) )
.addCriterion("has_machine", criterion(MItems.CHEMICAL_GENERATOR)) .addCriterion("has_machine", criterion(MItems.CHEMICAL_GENERATOR))
.save(serializer, modLocation("machines/chemical_generator"), existingFileHelper) .save(serializer, modLocation("machines/chemical_generator"))
val press = AdvancementBuilder() val press = AdvancementBuilder()
.parent(chem) .parent(chem)
@ -83,10 +79,10 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
) )
.addCriterion("has_machine", criterion(MItems.PLATE_PRESS)) .addCriterion("has_machine", criterion(MItems.PLATE_PRESS))
.save(serializer, modLocation("machines/plate_press"), existingFileHelper) .save(serializer, modLocation("machines/plate_press"))
CraftEntry(MItems.TWIN_PLATE_PRESS, "Twice the Thud", CraftEntry(MItems.TWIN_PLATE_PRESS, "Twice the Thud",
russianName = "Двойной стук").make(serializer, existingFileHelper, press, translation) russianName = "Двойной стук").make(serializer, press, translation)
val scanner = CraftEntry(MItems.MATTER_SCANNER, "Scanning Things that Matter", val scanner = CraftEntry(MItems.MATTER_SCANNER, "Scanning Things that Matter",
russianName = "Сканируем вещи которые материальны") russianName = "Сканируем вещи которые материальны")
@ -114,12 +110,12 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
val reconstructor = CraftEntry(MItems.MATTER_RECONSTRUCTOR, "Flipping Hourglass", val reconstructor = CraftEntry(MItems.MATTER_RECONSTRUCTOR, "Flipping Hourglass",
russianName = "Переворачиваем песочные часы") russianName = "Переворачиваем песочные часы")
decomposer.make(serializer, existingFileHelper, press, translation).also { decomposer.make(serializer, press, translation).also {
pattern.make(serializer, existingFileHelper, it, translation).also { pattern.make(serializer, it, translation).also {
scanner.make(serializer, existingFileHelper, it, translation) scanner.make(serializer, it, translation)
panel.make(serializer, existingFileHelper, it, translation) panel.make(serializer, it, translation)
replicator.make(serializer, existingFileHelper, it, translation).also { replicator.make(serializer, it, translation).also {
AdvancementBuilder() AdvancementBuilder()
.parent(it) .parent(it)
.display( .display(
@ -132,8 +128,8 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
}, },
frameType = FrameType.GOAL frameType = FrameType.GOAL
) )
.addCriterion("replicate_something", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build(), true)) .addCriterion("replicate_something", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build(), true).criterion())
.save(serializer, modLocation("machines/replicate_something"), existingFileHelper) .save(serializer, modLocation("machines/replicate_something"))
AdvancementBuilder() AdvancementBuilder()
.parent(it) .parent(it)
@ -147,20 +143,20 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Наблюдайте неудачный результат репликации, где ваш заказ рассыпался в материальную труху") russian("Наблюдайте неудачный результат репликации, где ваш заказ рассыпался в материальную труху")
}, },
) )
.addCriterion("replicate_failure", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build())) .addCriterion("replicate_failure", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build()).criterion())
.save(serializer, modLocation("machines/replicate_failure"), existingFileHelper) .save(serializer, modLocation("machines/replicate_failure"))
} }
reconstructor.make(serializer, existingFileHelper, it, translation) reconstructor.make(serializer, it, translation)
} }
bottler.make(serializer, existingFileHelper, it, translation) bottler.make(serializer, it, translation)
recycler.make(serializer, existingFileHelper, it, translation) recycler.make(serializer, it, translation)
capacitor.make(serializer, existingFileHelper, it, translation) capacitor.make(serializer, it, translation)
} }
counter.make(serializer, existingFileHelper, press, translation).also { counter.make(serializer, press, translation).also {
battery.make(serializer, existingFileHelper, it, translation) battery.make(serializer, it, translation)
} }
val station = CraftEntry(MItems.ANDROID_STATION, "Android Home Page", val station = CraftEntry(MItems.ANDROID_STATION, "Android Home Page",
@ -171,25 +167,25 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
val charger = CraftEntry(MItems.ANDROID_CHARGER, "Android Home Router", val charger = CraftEntry(MItems.ANDROID_CHARGER, "Android Home Router",
russianName = "Домашняя страница андроидов") russianName = "Домашняя страница андроидов")
station.make(serializer, existingFileHelper, press, translation).also { station.make(serializer, press, translation).also {
charger.make(serializer, existingFileHelper, it, translation) charger.make(serializer, it, translation)
} }
CraftEntry(MItems.COBBLESTONE_GENERATOR, "Cobblestone: Infinity + 1", CraftEntry(MItems.COBBLESTONE_GENERATOR, "Cobblestone: Infinity + 1",
russianName = "Булыжник: бесконечность + 1", russianName = "Булыжник: бесконечность + 1",
russianSuffix = "Смотрите, чтоб он не просыпался во все сундуки", russianSuffix = "Смотрите, чтоб он не просыпался во все сундуки",
englishSuffix = "Watch for not to spill it over all your chests").make(serializer, existingFileHelper, press, translation) englishSuffix = "Watch for not to spill it over all your chests").make(serializer, press, translation)
CraftEntry(MItems.POWERED_FURNACE, "One Big Resistor", CraftEntry(MItems.POWERED_FURNACE, "One Big Resistor",
russianName = "Один большой резистор", russianName = "Один большой резистор",
russianSuffix = "Каждый элемент электрической цепи способен испускать свет и тепло, единожды.", russianSuffix = "Каждый элемент электрической цепи способен испускать свет и тепло, единожды.",
englishSuffix = "Any electrical element can emit light and heat, once.") englishSuffix = "Any electrical element can emit light and heat, once.")
.make(serializer, existingFileHelper, press, translation) .make(serializer, press, translation)
.also { .also {
CraftEntry(MItems.POWERED_BLAST_FURNACE, "Big Microwave Oven", CraftEntry(MItems.POWERED_BLAST_FURNACE, "Big Microwave Oven",
russianName = "Большая микроволновая печь").make(serializer, existingFileHelper, it, translation) russianName = "Большая микроволновая печь").make(serializer, it, translation)
CraftEntry(MItems.POWERED_SMOKER, "Small Microwave Oven", CraftEntry(MItems.POWERED_SMOKER, "Small Microwave Oven",
russianName = "Маленькая микроволновая печь").make(serializer, existingFileHelper, it, translation) russianName = "Маленькая микроволновая печь").make(serializer, it, translation)
} }
} }

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.datagen.recipes
import com.google.common.collect.Lists import com.google.common.collect.Lists
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.SimpleCookingRecipeBuilder import net.minecraft.data.recipes.SimpleCookingRecipeBuilder
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -14,7 +15,7 @@ import ru.dbotthepony.mc.otm.registry.MItems
import java.util.* import java.util.*
import java.util.function.Consumer import java.util.function.Consumer
private fun Consumer<FinishedRecipe>.addRecyclingRecipe(inputs: Collection<ItemLike>, result: Item, name: String) { private fun RecipeOutput.addRecyclingRecipe(inputs: Collection<ItemLike>, result: Item, name: String) {
val inputStacks = inputs.map(::ItemStack) val inputStacks = inputs.map(::ItemStack)
SimpleCookingRecipeBuilder.smelting( SimpleCookingRecipeBuilder.smelting(
@ -28,7 +29,7 @@ private fun Consumer<FinishedRecipe>.addRecyclingRecipe(inputs: Collection<ItemL
).also { r -> inputs.forEach { r.unlockedBy(it) } }.save(this, modLocation("blasting/${name}")) ).also { r -> inputs.forEach { r.unlockedBy(it) } }.save(this, modLocation("blasting/${name}"))
} }
fun addBlastingRecipes(consumer: Consumer<FinishedRecipe>) { fun addBlastingRecipes(consumer: RecipeOutput) {
SimpleCookingRecipeBuilder.blasting(Ingredient.of(MItems.MIRROR_COMPOUND), RecipeCategory.MISC, MItems.MIRROR, 0.1f, 100).unlockedBy(MItems.MIRROR_COMPOUND).save(consumer) SimpleCookingRecipeBuilder.blasting(Ingredient.of(MItems.MIRROR_COMPOUND), RecipeCategory.MISC, MItems.MIRROR, 0.1f, 100).unlockedBy(MItems.MIRROR_COMPOUND).save(consumer)
SimpleCookingRecipeBuilder.smelting(Ingredient.of(MItemTags.TRITANIUM_PLATES), RecipeCategory.MISC, MItems.TRITANIUM_INGOT, 0f, 100).unlockedBy(MItemTags.TRITANIUM_PLATES).save(consumer, modLocation("tritanium_ingot_from_plates")) SimpleCookingRecipeBuilder.smelting(Ingredient.of(MItemTags.TRITANIUM_PLATES), RecipeCategory.MISC, MItems.TRITANIUM_INGOT, 0f, 100).unlockedBy(MItemTags.TRITANIUM_PLATES).save(consumer, modLocation("tritanium_ingot_from_plates"))

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.ShapelessRecipeBuilder import net.minecraft.data.recipes.ShapelessRecipeBuilder
import net.minecraft.tags.ItemTags import net.minecraft.tags.ItemTags
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -19,7 +20,7 @@ import ru.dbotthepony.mc.otm.recipe.ExplosiveHammerPrimingRecipe
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
import java.util.function.Consumer import java.util.function.Consumer
fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) { fun addCraftingTableRecipes(consumer: RecipeOutput) {
val machinesCategory = RecipeCategory.DECORATIONS val machinesCategory = RecipeCategory.DECORATIONS
MatteryRecipe(MRegistry.CARGO_CRATES.item, category = RecipeCategory.DECORATIONS) MatteryRecipe(MRegistry.CARGO_CRATES.item, category = RecipeCategory.DECORATIONS)
@ -407,7 +408,7 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.unlockedBy(MItemTags.TRITANIUM_INGOTS) .unlockedBy(MItemTags.TRITANIUM_INGOTS)
.build(consumer) .build(consumer)
consumer.accept(ExplosiveHammerPrimingRecipe(modLocation("hammer_priming"), Ingredient.of(Tags.Items.NUGGETS_IRON)).finishedRecipe) consumer.accept(ExplosiveHammerPrimingRecipe(Ingredient.of(Tags.Items.NUGGETS_IRON)).toFinished(modLocation("hammer_priming")))
MatteryRecipe(MItems.EXPLOSIVE_HAMMER, category = RecipeCategory.COMBAT) MatteryRecipe(MItems.EXPLOSIVE_HAMMER, category = RecipeCategory.COMBAT)
.rowB(Tags.Items.INGOTS_IRON) .rowB(Tags.Items.INGOTS_IRON)

View File

@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.function.Consumer import java.util.function.Consumer
private fun stairs(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRecipe>) { private fun stairs(base: ItemLike, result: ItemLike, consumer: RecipeOutput) {
MatteryRecipe(result, 4, category = RecipeCategory.BUILDING_BLOCKS) MatteryRecipe(result, 4, category = RecipeCategory.BUILDING_BLOCKS)
.rowA(base) .rowA(base)
.rowAB(base, base) .rowAB(base, base)
@ -24,14 +24,14 @@ private fun stairs(base: ItemLike, result: ItemLike, consumer: Consumer<Finished
.build(consumer, modLocation("decorative/stairs/${base.asItem().registryName!!.path}")) .build(consumer, modLocation("decorative/stairs/${base.asItem().registryName!!.path}"))
} }
private fun slab(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRecipe>) { private fun slab(base: ItemLike, result: ItemLike, consumer: RecipeOutput) {
MatteryRecipe(result, 6, category = RecipeCategory.BUILDING_BLOCKS) MatteryRecipe(result, 6, category = RecipeCategory.BUILDING_BLOCKS)
.row(base, base, base) .row(base, base, base)
.unlockedBy(base) .unlockedBy(base)
.build(consumer, modLocation("decorative/slabs/${base.asItem().registryName!!.path}")) .build(consumer, modLocation("decorative/slabs/${base.asItem().registryName!!.path}"))
} }
private fun wall(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRecipe>) { private fun wall(base: ItemLike, result: ItemLike, consumer: RecipeOutput) {
MatteryRecipe(result, 6, category = RecipeCategory.BUILDING_BLOCKS) MatteryRecipe(result, 6, category = RecipeCategory.BUILDING_BLOCKS)
.row(base, base, base) .row(base, base, base)
.row(base, base, base) .row(base, base, base)
@ -39,29 +39,29 @@ private fun wall(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRe
.build(consumer, modLocation("decorative/walls/${base.asItem().registryName!!.path}")) .build(consumer, modLocation("decorative/walls/${base.asItem().registryName!!.path}"))
} }
private fun cut(base: ItemLike, result: ItemLike, amount: Int, consumer: Consumer<FinishedRecipe>) { private fun cut(base: ItemLike, result: ItemLike, amount: Int, consumer: RecipeOutput) {
SingleItemRecipeBuilder SingleItemRecipeBuilder
.stonecutting(Ingredient.of(base), RecipeCategory.BUILDING_BLOCKS, result, amount) .stonecutting(Ingredient.of(base), RecipeCategory.BUILDING_BLOCKS, result, amount)
.unlockedBy(base) .unlockedBy(base)
.save(consumer, modLocation("stonecutting/${result.asItem().registryName!!.path}_from_${base.asItem().registryName!!.path}")) .save(consumer, modLocation("stonecutting/${result.asItem().registryName!!.path}_from_${base.asItem().registryName!!.path}"))
} }
private fun stairsWithCut(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRecipe>) { private fun stairsWithCut(base: ItemLike, result: ItemLike, consumer: RecipeOutput) {
stairs(base, result, consumer) stairs(base, result, consumer)
cut(base, result, 1, consumer) cut(base, result, 1, consumer)
} }
private fun slabWithCut(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRecipe>) { private fun slabWithCut(base: ItemLike, result: ItemLike, consumer: RecipeOutput) {
slab(base, result, consumer) slab(base, result, consumer)
cut(base, result, 2, consumer) cut(base, result, 2, consumer)
} }
private fun wallWithCut(base: ItemLike, result: ItemLike, consumer: Consumer<FinishedRecipe>) { private fun wallWithCut(base: ItemLike, result: ItemLike, consumer: RecipeOutput) {
wall(base, result, consumer) wall(base, result, consumer)
cut(base, result, 1, consumer) cut(base, result, 1, consumer)
} }
fun addDecorativesRecipes(provider: MatteryRecipeProvider, consumer: Consumer<FinishedRecipe>) { fun addDecorativesRecipes(provider: MatteryRecipeProvider, consumer: RecipeOutput) {
// Напольная плитка // Напольная плитка
for ((color, unrefinedItem) in MRegistry.UNREFINED_FLOOR_TILES.items) { for ((color, unrefinedItem) in MRegistry.UNREFINED_FLOOR_TILES.items) {
MatteryRecipe(unrefinedItem, 24) MatteryRecipe(unrefinedItem, 24)

View File

@ -1,6 +1,6 @@
package ru.dbotthepony.mc.otm.datagen.recipes package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.item.crafting.Ingredient
import net.minecraftforge.common.Tags import net.minecraftforge.common.Tags
@ -10,12 +10,10 @@ import ru.dbotthepony.mc.otm.recipe.IngredientMatrix
import ru.dbotthepony.mc.otm.recipe.MatterEntanglerRecipe import ru.dbotthepony.mc.otm.recipe.MatterEntanglerRecipe
import ru.dbotthepony.mc.otm.registry.MItemTags import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
import java.util.function.Consumer
fun addMatterEntanglerRecipes(consumer: Consumer<FinishedRecipe>) { fun addMatterEntanglerRecipes(consumer: RecipeOutput) {
consumer.accept( consumer.accept(
MatterEntanglerRecipe( MatterEntanglerRecipe(
modLocation("quantum_capacitor"),
IngredientMatrix.of( IngredientMatrix.of(
listOf(Ingredient.of(MItems.ELECTRIC_PARTS), Ingredient.of(MItemTags.GOLD_WIRES), Ingredient.of(MItems.ELECTRIC_PARTS)), listOf(Ingredient.of(MItems.ELECTRIC_PARTS), Ingredient.of(MItemTags.GOLD_WIRES), Ingredient.of(MItems.ELECTRIC_PARTS)),
listOf(Ingredient.of(MItems.BATTERY_CAPACITOR), Ingredient.of(MItems.QUANTUM_TRANSCEIVER), Ingredient.of(MItems.BATTERY_CAPACITOR)), listOf(Ingredient.of(MItems.BATTERY_CAPACITOR), Ingredient.of(MItems.QUANTUM_TRANSCEIVER), Ingredient.of(MItems.BATTERY_CAPACITOR)),
@ -24,12 +22,11 @@ fun addMatterEntanglerRecipes(consumer: Consumer<FinishedRecipe>) {
Decimal(40), Decimal(40),
400.0, 400.0,
ItemStack(MItems.QUANTUM_CAPACITOR, 2) ItemStack(MItems.QUANTUM_CAPACITOR, 2)
).energetic().toFinished() ).energetic().toFinished(modLocation("quantum_capacitor"))
) )
consumer.accept( consumer.accept(
MatterEntanglerRecipe( MatterEntanglerRecipe(
modLocation("quantum_battery"),
IngredientMatrix.of( IngredientMatrix.of(
listOf(Ingredient.of(Tags.Items.STORAGE_BLOCKS_REDSTONE), Ingredient.of(MItemTags.GOLD_WIRES), Ingredient.of(Tags.Items.STORAGE_BLOCKS_REDSTONE)), listOf(Ingredient.of(Tags.Items.STORAGE_BLOCKS_REDSTONE), Ingredient.of(MItemTags.GOLD_WIRES), Ingredient.of(Tags.Items.STORAGE_BLOCKS_REDSTONE)),
listOf(Ingredient.of(MItems.BATTERY_DENSE), Ingredient.of(MItems.QUANTUM_TRANSCEIVER), Ingredient.of(MItems.BATTERY_DENSE)), listOf(Ingredient.of(MItems.BATTERY_DENSE), Ingredient.of(MItems.QUANTUM_TRANSCEIVER), Ingredient.of(MItems.BATTERY_DENSE)),
@ -38,6 +35,6 @@ fun addMatterEntanglerRecipes(consumer: Consumer<FinishedRecipe>) {
Decimal(120), Decimal(120),
600.0, 600.0,
ItemStack(MItems.QUANTUM_BATTERY, 2) ItemStack(MItems.QUANTUM_BATTERY, 2)
).energetic().toFinished() ).energetic().toFinished(modLocation("quantum_battery"))
) )
} }

View File

@ -2,9 +2,12 @@
package ru.dbotthepony.mc.otm.datagen.recipes package ru.dbotthepony.mc.otm.datagen.recipes
import com.google.gson.JsonObject import com.google.gson.JsonObject
import net.minecraft.advancements.Advancement
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.CriterionTriggerInstance import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.ShapedRecipeBuilder import net.minecraft.data.recipes.ShapedRecipeBuilder
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey import net.minecraft.tags.TagKey
@ -13,9 +16,9 @@ import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.item.crafting.RecipeSerializer import net.minecraft.world.item.crafting.RecipeSerializer
import net.minecraft.world.level.ItemLike import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.collect.JsonArrayCollector
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.toJsonStrict
import ru.dbotthepony.mc.otm.datagen.modLocation import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
@ -54,6 +57,18 @@ private data class RecipeRow(
val c: RecipeCell?, val c: RecipeCell?,
) )
private fun RecipeOutput.map(mapper: (FinishedRecipe) -> FinishedRecipe): RecipeOutput {
return object : RecipeOutput {
override fun accept(recipe: FinishedRecipe) {
this@map.accept(mapper(recipe))
}
override fun advancement(): Advancement.Builder {
return this@map.advancement()
}
}
}
/** /**
* [ShapedRecipeBuilder] that doesn't suck * [ShapedRecipeBuilder] that doesn't suck
*/ */
@ -62,11 +77,11 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
private val rows = arrayOfNulls<RecipeRow>(3) private val rows = arrayOfNulls<RecipeRow>(3)
private var index = 0 private var index = 0
private val unlockedBy = ArrayList<Pair<String, CriterionTriggerInstance>>().also { private val unlockedBy = ArrayList<Pair<String, Criterion<*>>>().also {
it.add("has_result" to has(result)) it.add("has_result" to has(result))
} }
fun unlockedBy(name: String, trigger: CriterionTriggerInstance): MatteryRecipe { fun unlockedBy(name: String, trigger: Criterion<*>): MatteryRecipe {
unlockedBy.add(name to trigger) unlockedBy.add(name to trigger)
return this return this
} }
@ -163,55 +178,55 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
return this return this
} }
private fun filter(consumer: Consumer<FinishedRecipe>): Consumer<FinishedRecipe> { private fun filter(): (FinishedRecipe) -> FinishedRecipe {
if (upgradeSource != null) { if (upgradeSource != null) {
check(copyPaths.isNotEmpty()) { "Defined upgrade recipe without nbt migration operations" } check(copyPaths.isNotEmpty()) { "Defined upgrade recipe without nbt migration operations" }
return Consumer { return {
consumer.accept(object : FinishedRecipe by it { object : FinishedRecipe by it {
override fun serializeRecipeData(pJson: JsonObject) { override fun serializeRecipeData(pJson: JsonObject) {
it.serializeRecipeData(pJson) it.serializeRecipeData(pJson)
pJson["copyPaths"] = copyPaths.stream().map { it.serialize() }.collect(JsonArrayCollector) pJson["copyPaths"] = UpgradeRecipe.COPY_PATHS_CODEC.toJsonStrict(copyPaths)
pJson["source"] = upgradeSource!!.toString() pJson["source"] = upgradeSource!!.toString()
} }
override fun getType(): RecipeSerializer<*> { override fun type(): RecipeSerializer<*> {
return UpgradeRecipe.Companion return UpgradeRecipe.CODEC
} }
}) }
} }
} }
return consumer return { it }
} }
fun build(consumer: Consumer<FinishedRecipe>, name: String? = null) { fun build(consumer: RecipeOutput, name: String? = null) {
val builder = buildRegular() val builder = buildRegular()
if (name != null) { if (name != null) {
builder.save(filter(consumer), modLocation( builder.save(consumer.map(filter()), modLocation(
if (result.asItem().registryName!!.namespace == OverdriveThatMatters.MOD_ID) if (result.asItem().registryName!!.namespace == OverdriveThatMatters.MOD_ID)
"${result.asItem().registryName!!.path}_$name" "${result.asItem().registryName!!.path}_$name"
else else
"${result.asItem().registryName!!.namespace}_${result.asItem().registryName!!.path}_$name" "${result.asItem().registryName!!.namespace}_${result.asItem().registryName!!.path}_$name"
)) ))
} else { } else {
builder.save(filter(consumer)) builder.save(consumer.map(filter()))
} }
} }
fun build(consumer: Consumer<FinishedRecipe>, name: ResourceLocation) { fun build(consumer: RecipeOutput, name: ResourceLocation) {
buildRegular().save(filter(consumer), name) buildRegular().save(consumer.map(filter()), name)
} }
fun buildEnergetic(consumer: Consumer<FinishedRecipe>, name: String? = null) { fun buildEnergetic(consumer: RecipeOutput, name: String? = null) {
build({ build(consumer.map {
consumer.accept(object : FinishedRecipe by it { object : FinishedRecipe by it {
override fun getType(): RecipeSerializer<*> { override fun type(): RecipeSerializer<*> {
return EnergyContainerRecipe.Companion return EnergyContainerRecipe.Companion
} }
}) }
}, name) }, name)
} }

View File

@ -1,5 +1,8 @@
package ru.dbotthepony.mc.otm.datagen.recipes package ru.dbotthepony.mc.otm.datagen.recipes
import com.google.common.collect.ImmutableList
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.ContextAwarePredicate import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.InventoryChangeTrigger import net.minecraft.advancements.critereon.InventoryChangeTrigger
@ -8,6 +11,7 @@ import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.data.DataGenerator import net.minecraft.data.DataGenerator
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeBuilder import net.minecraft.data.recipes.RecipeBuilder
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.RecipeProvider import net.minecraft.data.recipes.RecipeProvider
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.ItemTags import net.minecraft.tags.ItemTags
@ -20,32 +24,32 @@ import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.modLocation import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
import java.util.LinkedList import java.util.*
import java.util.function.Consumer import java.util.function.Consumer
import java.util.stream.Stream import java.util.stream.Stream
private typealias RecipeBuilderCallback = (MatteryRecipeProvider, consumer: Consumer<FinishedRecipe>) -> Unit private typealias RecipeBuilderCallback = (MatteryRecipeProvider, consumer: RecipeOutput) -> Unit
fun has(p_176521_: MinMaxBounds.Ints, p_176522_: ItemLike): InventoryChangeTrigger.TriggerInstance { fun has(p_176521_: MinMaxBounds.Ints, p_176522_: ItemLike): Criterion<InventoryChangeTrigger.TriggerInstance> {
return inventoryTrigger(ItemPredicate.Builder.item().of(p_176522_).withCount(p_176521_).build()) return inventoryTrigger(ItemPredicate.Builder.item().of(p_176522_).withCount(p_176521_).build())
} }
fun has(p_125978_: ItemLike): InventoryChangeTrigger.TriggerInstance { fun has(p_125978_: ItemLike): Criterion<InventoryChangeTrigger.TriggerInstance> {
return inventoryTrigger(ItemPredicate.Builder.item().of(p_125978_).build()) return inventoryTrigger(ItemPredicate.Builder.item().of(p_125978_).build())
} }
fun has(p_125976_: TagKey<Item>): InventoryChangeTrigger.TriggerInstance { fun has(p_125976_: TagKey<Item>): Criterion<InventoryChangeTrigger.TriggerInstance> {
return inventoryTrigger(ItemPredicate.Builder.item().of(p_125976_).build()) return inventoryTrigger(ItemPredicate.Builder.item().of(p_125976_).build())
} }
fun inventoryTrigger(vararg p_126012_: ItemPredicate): InventoryChangeTrigger.TriggerInstance { fun inventoryTrigger(vararg p_126012_: ItemPredicate): Criterion<InventoryChangeTrigger.TriggerInstance> {
return InventoryChangeTrigger.TriggerInstance( return CriteriaTriggers.INVENTORY_CHANGED.createCriterion(InventoryChangeTrigger.TriggerInstance(
ContextAwarePredicate.ANY, Optional.empty(),
MinMaxBounds.Ints.ANY, MinMaxBounds.Ints.ANY,
MinMaxBounds.Ints.ANY, MinMaxBounds.Ints.ANY,
MinMaxBounds.Ints.ANY, MinMaxBounds.Ints.ANY,
p_126012_ ImmutableList.copyOf(p_126012_)
) ))
} }
fun <T : RecipeBuilder> T.unlockedBy(item: ItemLike): T { fun <T : RecipeBuilder> T.unlockedBy(item: ItemLike): T {
@ -75,7 +79,7 @@ class MatteryRecipeProvider(generatorIn: DataGenerator) : RecipeProvider(generat
return this return this
} }
override fun buildRecipes(callback: Consumer<FinishedRecipe>) { override fun buildRecipes(callback: RecipeOutput) {
for (lambda in callbacks) { for (lambda in callbacks) {
lambda(this, callback) lambda(this, callback)
} }
@ -84,19 +88,18 @@ class MatteryRecipeProvider(generatorIn: DataGenerator) : RecipeProvider(generat
fun plate(id: String, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) { fun plate(id: String, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) {
exec { _, consumer -> exec { _, consumer ->
consumer.accept(PlatePressRecipe( consumer.accept(PlatePressRecipe(
modLocation("plates/$id"),
Ingredient.of(ItemTags.create(ResourceLocation("forge", "ingots/$id"))), Ingredient.of(ItemTags.create(ResourceLocation("forge", "ingots/$id"))),
Ingredient.of(ItemTags.create(ResourceLocation("forge", "plates/$id"))), Ingredient.of(ItemTags.create(ResourceLocation("forge", "plates/$id"))),
count, count,
workTicks, workTicks,
experience = experience experience = experience
).toFinished()) ).toFinished(modLocation("plates/$id")))
} }
} }
fun plate(id: String, ingredient: Ingredient, result: Ingredient, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) { fun plate(id: String, ingredient: Ingredient, result: Ingredient, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) {
exec { it, callback -> exec { it, callback ->
callback.accept(PlatePressRecipe(modLocation("plate_$id"), ingredient, result, count, workTicks, experience = experience).toFinished()) callback.accept(PlatePressRecipe(ingredient, result, count, workTicks, experience = experience).toFinished(modLocation("plate_$id")))
} }
} }
} }

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.SimpleCookingRecipeBuilder import net.minecraft.data.recipes.SimpleCookingRecipeBuilder
import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.item.crafting.Ingredient
import ru.dbotthepony.mc.otm.datagen.modLocation import ru.dbotthepony.mc.otm.datagen.modLocation
@ -9,7 +10,7 @@ import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
import java.util.function.Consumer import java.util.function.Consumer
fun addOreSmeltingRecipes(consumer: Consumer<FinishedRecipe>) { fun addOreSmeltingRecipes(consumer: RecipeOutput) {
SimpleCookingRecipeBuilder.smelting(Ingredient.of(MItemTags.TRITANIUM_ORES), RecipeCategory.MISC, MItems.TRITANIUM_INGOT, 1f, 200).unlockedBy(MItemTags.TRITANIUM_ORES).save(consumer, modLocation("smelting/tritanium_ingot_from_ore_block")) SimpleCookingRecipeBuilder.smelting(Ingredient.of(MItemTags.TRITANIUM_ORES), RecipeCategory.MISC, MItems.TRITANIUM_INGOT, 1f, 200).unlockedBy(MItemTags.TRITANIUM_ORES).save(consumer, modLocation("smelting/tritanium_ingot_from_ore_block"))
SimpleCookingRecipeBuilder.blasting(Ingredient.of(MItemTags.TRITANIUM_ORES), RecipeCategory.MISC, MItems.TRITANIUM_INGOT, 1f, 100).unlockedBy(MItemTags.TRITANIUM_ORES).save(consumer, modLocation("blasting/tritanium_ingot_from_ore_block")) SimpleCookingRecipeBuilder.blasting(Ingredient.of(MItemTags.TRITANIUM_ORES), RecipeCategory.MISC, MItems.TRITANIUM_INGOT, 1f, 100).unlockedBy(MItemTags.TRITANIUM_ORES).save(consumer, modLocation("blasting/tritanium_ingot_from_ore_block"))

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.datagen.recipes package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -16,20 +17,19 @@ import java.util.function.Consumer
private val Item.recipeName get() = registryName!!.namespace + "/" + registryName!!.path private val Item.recipeName get() = registryName!!.namespace + "/" + registryName!!.path
private fun generate(consumer: Consumer<FinishedRecipe>, items: Map<out DyeColor?, Item>, amount: Int = 1) { private fun generate(consumer: RecipeOutput, items: Map<out DyeColor?, Item>, amount: Int = 1) {
for ((targetColor, targetItem) in items) { for ((targetColor, targetItem) in items) {
if (targetColor == null) continue if (targetColor == null) continue
consumer.accept(PainterRecipe( consumer.accept(PainterRecipe(
modLocation("painter/" + targetItem.recipeName),
Ingredient.of(items.entries.stream().filter { it.key != null && it.key != targetColor }.map { ItemStack(it.value) }), Ingredient.of(items.entries.stream().filter { it.key != null && it.key != targetColor }.map { ItemStack(it.value) }),
ItemStack(targetItem), ItemStack(targetItem),
mapOf(targetColor to amount) mapOf(targetColor to amount)
).toFinished()) ).toFinished(modLocation("painter/" + targetItem.recipeName)))
} }
} }
private fun generate(consumer: Consumer<FinishedRecipe>, default: Item, items: Map<out DyeColor?, Item>, amount: Int = 1, cleaning: Boolean = true) { private fun generate(consumer: RecipeOutput, default: Item, items: Map<out DyeColor?, Item>, amount: Int = 1, cleaning: Boolean = true) {
generate(consumer, items) generate(consumer, items)
if (cleaning) if (cleaning)
@ -39,37 +39,34 @@ private fun generate(consumer: Consumer<FinishedRecipe>, default: Item, items: M
if (k1 == null) continue if (k1 == null) continue
consumer.accept(PainterRecipe( consumer.accept(PainterRecipe(
modLocation("painter/" + default.recipeName + "/" + v1.recipeName),
Ingredient.of(default), Ingredient.of(default),
ItemStack(v1), ItemStack(v1),
mapOf(k1 to amount) mapOf(k1 to amount)
).toFinished()) ).toFinished(modLocation("painter/" + default.recipeName + "/" + v1.recipeName)))
} }
} }
private fun cleaning(consumer: Consumer<FinishedRecipe>, to: Item, from: Map<out DyeColor?, Item>) { private fun cleaning(consumer: RecipeOutput, to: Item, from: Map<out DyeColor?, Item>) {
consumer.accept(PainterRecipe( consumer.accept(PainterRecipe(
modLocation("painter/cleaning/" + to.recipeName),
Ingredient.of(from.entries.stream().filter { it.key != null }.map { ItemStack(it.value) }), Ingredient.of(from.entries.stream().filter { it.key != null }.map { ItemStack(it.value) }),
ItemStack(to), ItemStack(to),
setOf() setOf()
).toFinished()) ).toFinished(modLocation("painter/cleaning/" + to.recipeName)))
} }
private fun striped(consumer: Consumer<FinishedRecipe>, name: String, items: List<Pair<Item, Pair<DyeColor, DyeColor>>>, base: Map<DyeColor, Item>) { private fun striped(consumer: RecipeOutput, name: String, items: List<Pair<Item, Pair<DyeColor, DyeColor>>>, base: Map<DyeColor, Item>) {
for ((stripeItem, colors) in items) { for ((stripeItem, colors) in items) {
val (baseColor, stripe) = colors val (baseColor, stripe) = colors
consumer.accept(PainterRecipe( consumer.accept(PainterRecipe(
modLocation("painter/stripes_$name/${baseColor.getName()}/${stripe.getName()}"),
Ingredient.of(base[baseColor]), Ingredient.of(base[baseColor]),
ItemStack(stripeItem), ItemStack(stripeItem),
setOf(stripe) setOf(stripe)
).toFinished()) ).toFinished(modLocation("painter/stripes_$name/${baseColor.getName()}/${stripe.getName()}")))
} }
} }
fun addPainterRecipes(consumer: Consumer<FinishedRecipe>) { fun addPainterRecipes(consumer: RecipeOutput) {
generate(consumer, mapOf( generate(consumer, mapOf(
DyeColor.WHITE to Items.WHITE_WOOL, DyeColor.WHITE to Items.WHITE_WOOL,
DyeColor.ORANGE to Items.ORANGE_WOOL, DyeColor.ORANGE to Items.ORANGE_WOOL,

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.ShapelessRecipeBuilder import net.minecraft.data.recipes.ShapelessRecipeBuilder
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -14,8 +15,8 @@ import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.function.Consumer import java.util.function.Consumer
fun addShapelessRecipes(consumer: Consumer<FinishedRecipe>) { fun addShapelessRecipes(consumer: RecipeOutput) {
for (color in DyeColor.values()) { for (color in DyeColor.entries) {
ShapelessRecipeBuilder(RecipeCategory.TRANSPORTATION, MItems.CARGO_CRATE_MINECARTS[color]!!, 1) ShapelessRecipeBuilder(RecipeCategory.TRANSPORTATION, MItems.CARGO_CRATE_MINECARTS[color]!!, 1)
.requires(Items.MINECART) .requires(Items.MINECART)
.requires(MRegistry.CARGO_CRATES.items[color]!!) .requires(MRegistry.CARGO_CRATES.items[color]!!)

View File

@ -0,0 +1,23 @@
package ru.dbotthepony.mc.otm.mixin;
import net.minecraft.client.gui.GuiGraphics;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import static ru.dbotthepony.mc.otm.client.render.RenderHelperKt.popScissorRect;
import static ru.dbotthepony.mc.otm.client.render.RenderHelperKt.pushScissorRect;
// because scissor stack fucking sucks.
// mostly because it is not a stack at all.
@Mixin(GuiGraphics.class)
public abstract class GuiGraphicsMixin {
@Overwrite
public void enableScissor(int x0, int y0, int x1, int y1) {
pushScissorRect(x0, y0, x1 - x0, y1 - y0);
}
@Overwrite
public void disableScissor() {
popScissorRect();
}
}

View File

@ -13,7 +13,7 @@ import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener
import net.minecraft.util.profiling.ProfilerFiller import net.minecraft.util.profiling.ProfilerFiller
import net.minecraftforge.event.AddReloadListenerEvent import net.minecraftforge.event.AddReloadListenerEvent
import net.minecraftforge.event.OnDatapackSyncEvent import net.minecraftforge.event.OnDatapackSyncEvent
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.MINECRAFT_SERVER import ru.dbotthepony.mc.otm.MINECRAFT_SERVER
@ -27,11 +27,8 @@ import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.toNetwork import ru.dbotthepony.mc.otm.core.toNetwork
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.enqueueWork
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.onceServer import ru.dbotthepony.mc.otm.onceServer
import java.util.LinkedList import java.util.LinkedList
import java.util.function.Supplier
object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_android_research"), Iterable<AndroidResearchType> { object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_android_research"), Iterable<AndroidResearchType> {
const val DIRECTORY = "otm_android_research" const val DIRECTORY = "otm_android_research"
@ -114,7 +111,7 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s
LOGGER.debug("Constructed android research registry packet, ${buff.writerIndex()} bytes in size") LOGGER.debug("Constructed android research registry packet, ${buff.writerIndex()} bytes in size")
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
if (NULLABLE_MINECRAFT_SERVER is IntegratedServer) { if (NULLABLE_MINECRAFT_SERVER is IntegratedServer) {

View File

@ -25,7 +25,6 @@ import ru.dbotthepony.mc.otm.core.collect.ListSet
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.isActuallyEmpty import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.data.ComponentCodec import ru.dbotthepony.mc.otm.data.ComponentCodec
import ru.dbotthepony.mc.otm.data.IngredientCodec
import ru.dbotthepony.mc.otm.data.JsonElementCodec import ru.dbotthepony.mc.otm.data.JsonElementCodec
import ru.dbotthepony.mc.otm.isClient import ru.dbotthepony.mc.otm.isClient
import java.util.Optional import java.util.Optional
@ -393,7 +392,7 @@ class AndroidResearchType(
ListCodec( ListCodec(
RecordCodecBuilder.create<Pair<Ingredient, Int>> { RecordCodecBuilder.create<Pair<Ingredient, Int>> {
it.group( it.group(
IngredientCodec.fieldOf("item").forGetter { it.first }, Ingredient.CODEC.fieldOf("item").forGetter { it.first },
Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter { it.second } Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter { it.second }
).apply(it, ::Pair) ).apply(it, ::Pair)
} }

View File

@ -5,7 +5,7 @@ import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.item.ItemEntity import net.minecraft.world.entity.item.ItemEntity
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import ru.dbotthepony.mc.otm.config.AndroidConfig import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
@ -21,12 +21,10 @@ import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.core.math.times import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.UUID import java.util.UUID
import java.util.WeakHashMap import java.util.WeakHashMap
import java.util.function.Predicate import java.util.function.Predicate
import java.util.function.Supplier
private data class SharedItemEntityData(val owner: UUID? = null, val age: Int = 0, val lifespan: Int = 0, val hasPickupDelay: Boolean = true) { private data class SharedItemEntityData(val owner: UUID? = null, val age: Int = 0, val lifespan: Int = 0, val hasPickupDelay: Boolean = true) {
companion object { companion object {
@ -46,8 +44,7 @@ class ItemEntityDataPacket(val itemUUID: Int, val owner: UUID? = null, val age:
buff.writeBoolean(hasPickupDelay) buff.writeBoolean(hasPickupDelay)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
val level = minecraft.player?.level() as ClientLevel? ?: return val level = minecraft.player?.level() as ClientLevel? ?: return
val entity = level.getEntity(itemUUID) as ItemEntity? ?: return val entity = level.getEntity(itemUUID) as ItemEntity? ?: return
datatable[entity] = SharedItemEntityData(owner, age, lifespan, hasPickupDelay) datatable[entity] = SharedItemEntityData(owner, age, lifespan, hasPickupDelay)

View File

@ -1,23 +1,17 @@
package ru.dbotthepony.mc.otm.android.feature package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraft.world.level.Level
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.network.PacketDistributor.TargetPoint
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.ResearchIcons import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.plus
@ -25,9 +19,6 @@ import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket
import ru.dbotthepony.mc.otm.network.enqueueWork
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MSoundEvents import ru.dbotthepony.mc.otm.registry.MSoundEvents
import java.util.function.Supplier import java.util.function.Supplier
@ -37,29 +28,25 @@ object TriggerJumpBoostPacket : MatteryPacket {
// no op // no op
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val mattery = context.sender?.matteryPlayer ?: return
context.enqueueWork { if (!mattery.isAndroid)
val mattery = context.sender?.matteryPlayer ?: return@enqueueWork return
if (!mattery.isAndroid) val feature = mattery.getFeature(AndroidFeatures.JUMP_BOOST) ?: return
return@enqueueWork
val feature = mattery.getFeature(AndroidFeatures.JUMP_BOOST) ?: return@enqueueWork if (feature.isActive && feature.cooldown <= 4 && mattery.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, false)) {
feature.putOnCooldown()
if (feature.isActive && feature.cooldown <= 4 && mattery.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, false)) { context.sender?.let {
feature.putOnCooldown() it.level().playSound(
it, it,
MSoundEvents.ANDROID_JUMP_BOOST, SoundSource.PLAYERS,
1f, 1f
)
context.sender?.let { GenericNetworkChannel.makeSmoke(it, it.x, it.y, it.z)
it.level().playSound(
it, it,
MSoundEvents.ANDROID_JUMP_BOOST, SoundSource.PLAYERS,
1f, 1f
)
GenericNetworkChannel.makeSmoke(it, it.x, it.y, it.z)
}
} }
} }
} }

View File

@ -1,54 +1,41 @@
package ru.dbotthepony.mc.otm.android.feature package ru.dbotthepony.mc.otm.android.feature
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.monster.warden.Warden import net.minecraft.world.entity.monster.warden.Warden
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.ResearchIcons import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.damageType
import ru.dbotthepony.mc.otm.core.math.getEllipsoidBlockPositions
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
import ru.dbotthepony.mc.otm.core.getExplosionResistance import ru.dbotthepony.mc.otm.core.getExplosionResistance
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.getEllipsoidBlockPositions
import ru.dbotthepony.mc.otm.core.math.minus import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.core.math.roundToIntVector import ru.dbotthepony.mc.otm.core.math.roundToIntVector
import ru.dbotthepony.mc.otm.core.math.times import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.ShiftPressedCond
import ru.dbotthepony.mc.otm.core.damageType
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import ru.dbotthepony.mc.otm.network.ShockwaveEffectPacket import ru.dbotthepony.mc.otm.network.ShockwaveEffectPacket
import ru.dbotthepony.mc.otm.network.enqueueWork
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender
import ru.dbotthepony.mc.otm.onceServer import ru.dbotthepony.mc.otm.onceServer
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MDamageTypes import ru.dbotthepony.mc.otm.registry.MDamageTypes
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.MSoundEvents import ru.dbotthepony.mc.otm.registry.MSoundEvents
import ru.dbotthepony.mc.otm.registry.MatteryDamageSource import ru.dbotthepony.mc.otm.registry.MatteryDamageSource
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger
import java.util.function.Supplier
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -57,15 +44,12 @@ object TriggerShockwavePacket : MatteryPacket {
// no op // no op
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) ?: return
context.enqueueWork {
val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) as ShockwaveFeature? ?: return@enqueueWork
if (!shockwave.isOnCooldown && shockwave.isActive && shockwave.airTicks > 0) { if (!shockwave.isOnCooldown && shockwave.isActive && shockwave.airTicks > 0) {
onceServer { // delay by one tick so player update its position as well onceServer { // delay by one tick so player update its position as well
shockwave.shockwave() shockwave.shockwave()
}
} }
} }
} }

View File

@ -667,12 +667,11 @@ class ExplosionQueue(private val level: ServerLevel) : SavedData() {
@JvmStatic @JvmStatic
fun queueForLevel(level: ServerLevel): ExplosionQueue { fun queueForLevel(level: ServerLevel): ExplosionQueue {
return level.dataStorage.computeIfAbsent( return level.dataStorage.computeIfAbsent(
{ Factory({ ExplosionQueue(level) }, {
val factory = ExplosionQueue(level) val factory = ExplosionQueue(level)
factory.load(it) factory.load(it)
factory factory
}, }, TODO()),
{ ExplosionQueue(level) },
"otm_blackhole_explosion_queue" "otm_blackhole_explosion_queue"
) )
} }

View File

@ -77,7 +77,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
.recipeManager .recipeManager
.byType(MRecipes.MATTER_ENTANGLER) .byType(MRecipes.MATTER_ENTANGLER)
.values .values
.any { it.preemptivelyMatches(shadow, level!!) } .any { it.value.preemptivelyMatches(shadow, level!!) }
} }
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
@ -139,9 +139,9 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
.recipeManager .recipeManager
.byType(MRecipes.MATTER_ENTANGLER) .byType(MRecipes.MATTER_ENTANGLER)
.values .values
.firstOrNull { it.matches(inputs, level!!) } ?: return JobContainer.noItem() .firstOrNull { it.value.matches(inputs, level!!) } ?: return JobContainer.noItem()
val result = recipe.assemble(inputs, level!!.registryAccess()) val result = recipe.value.assemble(inputs, level!!.registryAccess())
inputs.forEach { it.shrink(1) } inputs.forEach { it.shrink(1) }
inputs.setChanged() inputs.setChanged()
@ -149,8 +149,8 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
return JobContainer.success( return JobContainer.success(
Job( Job(
result, result,
recipe.matter, recipe.value.matter,
recipe.ticks * MachinesConfig.MATTER_ENTANGLER.workTimeMultiplier recipe.value.ticks * MachinesConfig.MATTER_ENTANGLER.workTimeMultiplier
) )
) )
} }

View File

@ -230,7 +230,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
if (craftingRecipe != null && craftingRecipe.matches(craftingGrid, level)) return true if (craftingRecipe != null && craftingRecipe.matches(craftingGrid, level)) return true
if (justCheckForRecipeChange) return false if (justCheckForRecipeChange) return false
craftingRecipe = server.recipeManager.getRecipeFor(RecipeType.CRAFTING, craftingGrid, level).orElse(null) craftingRecipe = server.recipeManager.getRecipeFor(RecipeType.CRAFTING, craftingGrid, level).orElse(null)?.value
Arrays.fill(craftingGridTuples, null) Arrays.fill(craftingGridTuples, null)
val poweredView = poweredView val poweredView = poweredView

View File

@ -92,8 +92,8 @@ class PlatePressBlockEntity(
.byType(MRecipes.PLATE_PRESS) .byType(MRecipes.PLATE_PRESS)
.values .values
.iterator() .iterator()
.filter { it.matches(inputContainer, id) } .filter { it.value.matches(inputContainer, id) }
.maybe() ?: return JobContainer.noItem() .maybe()?.value ?: return JobContainer.noItem()
val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems) val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems)

View File

@ -108,12 +108,12 @@ class PoweredFurnaceBlockEntity(
val level = level as? ServerLevel ?: return JobContainer.failure() val level = level as? ServerLevel ?: return JobContainer.failure()
return level.recipeManager.getRecipeFor(recipeType as RecipeType<AbstractCookingRecipe>, inputs[id], level).map { return level.recipeManager.getRecipeFor(recipeType as RecipeType<AbstractCookingRecipe>, inputs[id], level).map {
val output = it.assemble(inputs[id], level.registryAccess()) val output = it.value.assemble(inputs[id], level.registryAccess())
val toProcess = inputs[id][0].count.coerceAtMost(upgrades.processingItems + 1) val toProcess = inputs[id][0].count.coerceAtMost(upgrades.processingItems + 1)
inputs[id][0].shrink(toProcess) inputs[id][0].shrink(toProcess)
JobContainer.success(ItemJob( JobContainer.success(ItemJob(
output.copyWithCount(toProcess), it.cookingTime * config.workTimeMultiplier, config.energyConsumption * toProcess, it.experience * toProcess output.copyWithCount(toProcess), it.value.cookingTime * config.workTimeMultiplier, config.energyConsumption * toProcess, it.value.experience * toProcess
)) ))
}.orElse(JobContainer.noItem()) }.orElse(JobContainer.noItem())
} }

View File

@ -520,10 +520,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return JobContainer.noItem() return JobContainer.noItem()
} else { } else {
val actual = recipe.get() val actual = recipe.get()
val item = actual.assemble(input, level.registryAccess()) val item = actual.value.assemble(input, level.registryAccess())
input[0].shrink(1) input[0].shrink(1)
input.setChanged(0) input.setChanged(0)
return JobContainer.success(ItemJob(item, actual.cookingTime.toDouble(), ExopackConfig.FURNACE_POWER_CONSUMPTION, actual.experience)) return JobContainer.success(ItemJob(item, actual.value.cookingTime.toDouble(), ExopackConfig.FURNACE_POWER_CONSUMPTION, actual.value.experience))
} }
} }
@ -531,7 +531,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
super.onJobTick(status) super.onJobTick(status)
if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) { if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) {
MatteryPlayerNetworkChannel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with { ply as ServerPlayer }, ExopackSmokePacket(ply.uuid)) MatteryPlayerNetworkChannel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(ply as ServerPlayer), ExopackSmokePacket(ply.uuid))
} }
} }

View File

@ -217,7 +217,7 @@ fun onMouseScrolled(event: MouseScrolled.Pre) {
for (widget in screen.renderables) { for (widget in screen.renderables) {
if (widget is Panel2Widget<*, *>) { if (widget is Panel2Widget<*, *>) {
if (widget.panel.mouseScrolledChecked(event.mouseX, event.mouseY, event.scrollDelta)) { if (widget.panel.mouseScrolledChecked(event.mouseX, event.mouseY, event.deltaX)) {
event.isCanceled = true event.isCanceled = true
return return
} }
@ -226,7 +226,7 @@ fun onMouseScrolled(event: MouseScrolled.Pre) {
val slot = screen.slotUnderMouse val slot = screen.slotUnderMouse
if (slot != null && (slot.container == minecraft.player?.inventory && slot.containerSlot in 9 .. 35 || slot.container == minecraft.player?.matteryPlayer?.exopackContainer)) { if (slot != null && (slot.container == minecraft.player?.inventory && slot.containerSlot in 9 .. 35 || slot.container == minecraft.player?.matteryPlayer?.exopackContainer)) {
widget.panel.mouseScrolledInner(event.mouseX, event.mouseY, event.scrollDelta) widget.panel.mouseScrolledInner(event.mouseX, event.mouseY, event.deltaX)
event.isCanceled = true event.isCanceled = true
return return
} }

View File

@ -54,7 +54,6 @@ import java.util.*
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
import kotlin.collections.List import kotlin.collections.List
import kotlin.collections.MutableSet import kotlin.collections.MutableSet
import kotlin.collections.indices
import kotlin.collections.isNotEmpty import kotlin.collections.isNotEmpty
import kotlin.collections.withIndex import kotlin.collections.withIndex
@ -565,9 +564,9 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
return super.mouseReleased(p_97812_, p_97813_, p_97814_) return super.mouseReleased(p_97812_, p_97813_, p_97814_)
} }
override fun mouseScrolled(p_94686_: Double, p_94687_: Double, p_94688_: Double): Boolean { override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
for (panel in panels) { for (panel in panels) {
if (panel.mouseScrolledChecked(p_94686_, p_94687_, p_94688_)) { if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) {
return true return true
} }
} }
@ -648,7 +647,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
val mouseYf = mouseY.toFloat() val mouseYf = mouseY.toFloat()
// dark background // dark background
this.renderBackground(graphics) this.renderBackground(graphics, mouseX, mouseY, partialTick)
super.hoveredSlot = null super.hoveredSlot = null
var hovered = false var hovered = false

View File

@ -123,8 +123,8 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
buttons.forEach { it.remove() } buttons.forEach { it.remove() }
buttons.clear() buttons.clear()
for (recipe in menu.possibleRecipes.sortedWith(CreativeMenuItemComparator.map { it.output.item })) { for (recipe in menu.possibleRecipes.sortedWith(CreativeMenuItemComparator.map { it.value.output.item })) {
object : LargeRectangleButtonPanel<PainterScreen>(this@PainterScreen, canvas.canvas, icon = ItemStackIcon(recipe.output, 14f, 14f).fixed()) { object : LargeRectangleButtonPanel<PainterScreen>(this@PainterScreen, canvas.canvas, icon = ItemStackIcon(recipe.value.output, 14f, 14f).fixed()) {
init { init {
buttons.add(this) buttons.add(this)
dockRight = 1f dockRight = 1f
@ -132,13 +132,13 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
} }
override var isDisabled: Boolean override var isDisabled: Boolean
get() = !recipe.canCraft(menu.dyeStoredDirect) get() = !recipe.value.canCraft(menu.dyeStoredDirect)
set(value) {} set(value) {}
override fun innerRenderTooltips(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { override fun innerRenderTooltips(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
val list = getTooltipFromItem(minecraft!!, recipe.output) val list = getTooltipFromItem(minecraft!!, recipe.value.output)
recipe.dyes.forEach { recipe.value.dyes.forEach {
val (dye, amount) = it val (dye, amount) = it
if (amount == 1) if (amount == 1)

View File

@ -108,8 +108,8 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return this@EditablePanel.mouseDragged(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_) return this@EditablePanel.mouseDragged(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_)
} }
override fun mouseScrolled(p_94734_: Double, p_94735_: Double, p_94736_: Double): Boolean { override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
return this@EditablePanel.mouseScrolled(p_94734_, p_94735_, p_94736_) return this@EditablePanel.mouseScrolled(mouseX, mouseY, scrollY)
} }
override fun keyPressed(p_94745_: Int, p_94746_: Int, p_94747_: Int): Boolean { override fun keyPressed(p_94745_: Int, p_94746_: Int, p_94747_: Int): Boolean {

View File

@ -169,14 +169,16 @@ class EntityRendererPanel<out S : Screen> @JvmOverloads constructor(
return return
} }
val renderX = width.toInt() / 2 val renderX = this.width.toInt() / 2
val renderY = (height * 0.9f).toInt() val renderY = (this.height * 0.9f).toInt()
InventoryScreen.renderEntityInInventoryFollowsMouse( InventoryScreen.renderEntityInInventoryFollowsMouse(
graphics, graphics,
renderX, renderX,
renderY, renderY,
this.width.toInt(), this.height.toInt(),
renderScale, renderScale,
0f,
absoluteX.toInt() + renderX - mouseX, absoluteX.toInt() + renderX - mouseX,
absoluteY + height * 0.15f - mouseY, absoluteY + height * 0.15f - mouseY,
entity entity

View File

@ -46,8 +46,8 @@ class Panel2Widget<out S: Screen, out P : EditablePanel<S>>(
return panel.mouseDraggedChecked(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_) return panel.mouseDraggedChecked(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_)
} }
override fun mouseScrolled(p_94734_: Double, p_94735_: Double, p_94736_: Double): Boolean { override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
return panel.mouseScrolledChecked(p_94734_, p_94735_, p_94736_) return panel.mouseScrolledChecked(mouseX, mouseY, scrollY)
} }
override fun keyPressed(p_94745_: Int, p_94746_: Int, p_94747_: Int): Boolean { override fun keyPressed(p_94745_: Int, p_94746_: Int, p_94747_: Int): Boolean {

View File

@ -33,11 +33,6 @@ open class EditBoxPanel<out S : Screen>(
new_widget.value = old_widget.value new_widget.value = old_widget.value
} }
override fun tickInner() {
super.tickInner()
widget?.tick()
}
override fun configureNew(widget: EditBox, recreation: Boolean) { override fun configureNew(widget: EditBox, recreation: Boolean) {
widget.isFocused = isFocusedThis widget.isFocused = isFocusedThis
} }

View File

@ -36,7 +36,8 @@ fun onCuriosSlotModifiersUpdated(event: SlotModifiersUpdatedEvent) {
} }
fun openCuriosScreen(carriedStack: ItemStack = ItemStack.EMPTY) { fun openCuriosScreen(carriedStack: ItemStack = ItemStack.EMPTY) {
if (FMLEnvironment.dist.isClient) NetworkHandler.INSTANCE.send(PacketDistributor.SERVER.noArg(), CPacketOpenCurios(carriedStack)) TODO()
// if (FMLEnvironment.dist.isClient) NetworkHandler.INSTANCE.send(PacketDistributor.SERVER.noArg(), CPacketOpenCurios(carriedStack))
} }
private fun Player.getCuriosSlotsImpl(): List<PlayerSlot<Slot, Slot>> { private fun Player.getCuriosSlotsImpl(): List<PlayerSlot<Slot, Slot>> {

View File

@ -14,14 +14,15 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.MenuType
import net.minecraft.world.inventory.Slot import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.crafting.CraftingRecipe import net.minecraft.world.item.crafting.CraftingRecipe
import net.minecraft.world.item.crafting.RecipeHolder
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.toImmutableList import ru.dbotthepony.mc.otm.core.toImmutableList
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandlerHelper) : IRecipeTransferHandler<ExopackInventoryMenu, CraftingRecipe> { class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandlerHelper) : IRecipeTransferHandler<ExopackInventoryMenu, RecipeHolder<CraftingRecipe>> {
private val transfer = helper.createUnregisteredRecipeTransferHandler(object : IRecipeTransferInfo<ExopackInventoryMenu, CraftingRecipe> { private val transfer = helper.createUnregisteredRecipeTransferHandler(object : IRecipeTransferInfo<ExopackInventoryMenu, RecipeHolder<CraftingRecipe>> {
override fun getContainerClass(): Class<out ExopackInventoryMenu> { override fun getContainerClass(): Class<out ExopackInventoryMenu> {
return ExopackInventoryMenu::class.java return ExopackInventoryMenu::class.java
} }
@ -30,24 +31,24 @@ class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandler
return Optional.empty() return Optional.empty()
} }
override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<CraftingRecipe> { override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<RecipeHolder<CraftingRecipe>> {
return RecipeTypes.CRAFTING return RecipeTypes.CRAFTING
} }
override fun canHandle(container: ExopackInventoryMenu, recipe: CraftingRecipe): Boolean { override fun canHandle(container: ExopackInventoryMenu, recipe: RecipeHolder<CraftingRecipe>): Boolean {
return true return true
} }
override fun getRecipeSlots( override fun getRecipeSlots(
container: ExopackInventoryMenu, container: ExopackInventoryMenu,
recipe: CraftingRecipe recipe: RecipeHolder<CraftingRecipe>
): List<Slot> { ): List<Slot> {
return container.craftingSlots return container.craftingSlots
} }
override fun getInventorySlots( override fun getInventorySlots(
container: ExopackInventoryMenu, container: ExopackInventoryMenu,
recipe: CraftingRecipe recipe: RecipeHolder<CraftingRecipe>
): List<Slot> { ): List<Slot> {
return container.playerInventorySlots return container.playerInventorySlots
} }
@ -61,7 +62,7 @@ class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandler
return Optional.empty() return Optional.empty()
} }
override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<CraftingRecipe> { override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<RecipeHolder<CraftingRecipe>> {
return RecipeTypes.CRAFTING return RecipeTypes.CRAFTING
} }
@ -88,7 +89,7 @@ class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandler
override fun transferRecipe( override fun transferRecipe(
container: ExopackInventoryMenu, container: ExopackInventoryMenu,
recipe: CraftingRecipe, recipe: RecipeHolder<CraftingRecipe>,
recipeSlots: IRecipeSlotsView, recipeSlots: IRecipeSlotsView,
player: Player, player: Player,
maxTransfer: Boolean, maxTransfer: Boolean,

View File

@ -87,9 +87,9 @@ class JEIPlugin : IModPlugin {
override fun registerRecipes(registration: IRecipeRegistration) { override fun registerRecipes(registration: IRecipeRegistration) {
val level = minecraft.level ?: throw NullPointerException("No ClientLevel. OLOLOLOLOLOLO") val level = minecraft.level ?: throw NullPointerException("No ClientLevel. OLOLOLOLOLOLO")
registration.addRecipes(PlatePressRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PLATE_PRESS).filter { !it.isIncomplete }) registration.addRecipes(PlatePressRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PLATE_PRESS).filter { !it.value.isIncomplete }.map { it.value })
registration.addRecipes(PainterRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PAINTER).filter { !it.isIncomplete }) registration.addRecipes(PainterRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PAINTER).filter { !it.value.isIncomplete }.map { it.value })
registration.addRecipes(MatterEntanglerRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.MATTER_ENTANGLER).filter { !it.isIncomplete }) registration.addRecipes(MatterEntanglerRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.MATTER_ENTANGLER).filter { !it.value.isIncomplete }.map { it.value })
} }
override fun registerRecipeTransferHandlers(registration: IRecipeTransferRegistration) { override fun registerRecipeTransferHandlers(registration: IRecipeTransferRegistration) {

View File

@ -13,15 +13,13 @@ import net.minecraft.world.inventory.InventoryMenu
import net.minecraft.world.inventory.Slot import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender
import java.util.* import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
@ -226,8 +224,7 @@ class InventoryScrollPacket(val scroll: Int) : MatteryPacket {
}.scroll = scroll }.scroll = scroll
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
play(context.sender ?: throw IllegalStateException("Illegal side")) play(context.sender ?: throw IllegalStateException("Illegal side"))
} }

View File

@ -2,23 +2,14 @@ package ru.dbotthepony.mc.otm.container
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag import net.minecraft.nbt.ListTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.tags.TagKey import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.network.NetworkEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import java.util.Arrays import java.util.*
import java.util.LinkedList
import java.util.function.Consumer import java.util.function.Consumer
import java.util.function.Supplier
class ItemFilter( class ItemFilter(
val size: Int, val size: Int,

View File

@ -206,8 +206,8 @@ fun FriendlyByteBuf.readItemType(): Item {
return ForgeRegistries.ITEMS.getValue(readInt()) ?: Items.AIR return ForgeRegistries.ITEMS.getValue(readInt()) ?: Items.AIR
} }
fun InputStream.readItemType(sizeLimit: NbtAccounter? = null): Item { fun InputStream.readItemType(): Item {
return ForgeRegistries.ITEMS.getValue(readVarIntLE(sizeLimit)) ?: Items.AIR return ForgeRegistries.ITEMS.getValue(readVarIntLE()) ?: Items.AIR
} }
operator fun <T : Comparable<T>> StateHolder<*, *>.get(property: Property<T>): T { operator fun <T : Comparable<T>> StateHolder<*, *>.get(property: Property<T>): T {

View File

@ -699,10 +699,9 @@ class Decimal private constructor(val mag: BigInteger, marker: Nothing?) : Numbe
fun FriendlyByteBuf.readDecimal() = Decimal.read(this) fun FriendlyByteBuf.readDecimal() = Decimal.read(this)
fun FriendlyByteBuf.writeDecimal(value: Decimal) = value.write(this) fun FriendlyByteBuf.writeDecimal(value: Decimal) = value.write(this)
fun InputStream.readDecimal(sizeLimit: NbtAccounter = NbtAccounter(512L)): Decimal { fun InputStream.readDecimal(): Decimal {
val size = readVarIntLE(sizeLimit) val size = readVarIntLE()
require(size >= 0) { "Negative payload size: $size" } require(size >= 0) { "Negative payload size: $size" }
sizeLimit.accountBytes(size.toLong())
val bytes = ByteArray(size) val bytes = ByteArray(size)
read(bytes) read(bytes)
return Decimal.fromByteArray(bytes) return Decimal.fromByteArray(bytes)

View File

@ -117,13 +117,13 @@ fun CompoundTag.putJson(key: String, json: JsonElement) {
putByteArray(key, bytes.array.copyOfRange(0, bytes.length)) putByteArray(key, bytes.array.copyOfRange(0, bytes.length))
} }
fun CompoundTag.getJson(key: String, sizeLimit: NbtAccounter = NbtAccounter.UNLIMITED): JsonElement? { fun CompoundTag.getJson(key: String, sizeLimit: NbtAccounter = NbtAccounter(1 shl 18, 512)): JsonElement? {
val bytes = getByteArray(key) val bytes = getByteArray(key)
if (bytes.isEmpty()) if (bytes.isEmpty())
return null return null
return FastByteArrayInputStream(bytes).readBinaryJson(sizeLimit) return FastByteArrayInputStream(bytes).readBinaryJson()
} }
fun CompoundTag.getBoolean(index: String, orElse: Boolean): Boolean { fun CompoundTag.getBoolean(index: String, orElse: Boolean): Boolean {

View File

@ -19,7 +19,7 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
override fun write(stream: OutputStream, element: JsonElement) { override fun write(stream: OutputStream, element: JsonElement) {
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return JsonNull.INSTANCE return JsonNull.INSTANCE
} }
}, },
@ -29,8 +29,7 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
stream.writeDouble(element.asDouble) stream.writeDouble(element.asDouble)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
accounter.accountBytes(8L)
return JsonPrimitive(stream.readDouble()) return JsonPrimitive(stream.readDouble())
} }
}, },
@ -40,8 +39,7 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
stream.write(if (element.asBoolean) 1 else 0) stream.write(if (element.asBoolean) 1 else 0)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
accounter.accountBytes(1L)
return JsonPrimitive(stream.read() > 0) return JsonPrimitive(stream.read() > 0)
} }
}, },
@ -56,8 +54,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
throw IllegalArgumentException("Unknown number type: ${it::class.qualifiedName}") throw IllegalArgumentException("Unknown number type: ${it::class.qualifiedName}")
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return JsonPrimitive(stream.readVarLongLE(accounter)) return JsonPrimitive(stream.readVarLongLE())
} }
}, },
@ -66,8 +64,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
stream.writeBinaryString(element.asString) stream.writeBinaryString(element.asString)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return JsonPrimitive(stream.readBinaryString(accounter)) return JsonPrimitive(stream.readBinaryString())
} }
}, },
@ -76,8 +74,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, OutputStream::writeBinaryJson) writeArray(stream, element, OutputStream::writeBinaryJson)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return readArray(stream, accounter, InputStream::readBinaryJson) return readArray(stream, InputStream::readBinaryJson)
} }
}, },
@ -92,8 +90,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
} }
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
val count = stream.readVarIntLE(accounter) val count = stream.readVarIntLE()
if (count == 0) return JsonObject() if (count == 0) return JsonObject()
if (count < 0) throw JsonSyntaxException("Tried to read json object with $count elements in it") if (count < 0) throw JsonSyntaxException("Tried to read json object with $count elements in it")
@ -102,13 +100,13 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
for (i in 0 until count) { for (i in 0 until count) {
val key = try { val key = try {
stream.readBinaryString(accounter) stream.readBinaryString()
} catch(err: Throwable) { } catch(err: Throwable) {
throw JsonSyntaxException("Reading json object at $i", err) throw JsonSyntaxException("Reading json object at $i", err)
} }
try { try {
build.add(key, stream.readBinaryJson(accounter)) build.add(key, stream.readBinaryJson())
} catch(err: Throwable) { } catch(err: Throwable) {
throw JsonSyntaxException("Reading json object at $i with name $key", err) throw JsonSyntaxException("Reading json object at $i with name $key", err)
} }
@ -123,8 +121,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, DOUBLE::write) writeArray(stream, element, DOUBLE::write)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return readArray(stream, accounter, DOUBLE::read) return readArray(stream, DOUBLE::read)
} }
}, },
@ -133,8 +131,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, INT::write) writeArray(stream, element, INT::write)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return readArray(stream, accounter, INT::read) return readArray(stream, INT::read)
} }
}, },
@ -143,8 +141,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, BOOLEAN::write) writeArray(stream, element, BOOLEAN::write)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return readArray(stream, accounter, BOOLEAN::read) return readArray(stream, BOOLEAN::read)
} }
}, },
@ -153,8 +151,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, NULL::write) writeArray(stream, element, NULL::write)
} }
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement { override fun read(stream: InputStream): JsonElement {
return readArray(stream, accounter, NULL::read) return readArray(stream, NULL::read)
} }
}; };
@ -167,26 +165,25 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
} }
} }
protected fun readArray(stream: InputStream, accounter: NbtAccounter, reader: (InputStream, NbtAccounter) -> JsonElement): JsonArray { protected fun readArray(stream: InputStream, reader: (InputStream) -> JsonElement): JsonArray {
val count = stream.readVarIntLE(accounter) val count = stream.readVarIntLE()
if (count == 0) return JsonArray() if (count == 0) return JsonArray()
if (count < 0) throw JsonSyntaxException("Tried to read json array with $count elements in it") if (count < 0) throw JsonSyntaxException("Tried to read json array with $count elements in it")
return JsonArray(count).also { return JsonArray(count).also {
for (i in 0 until count) it.add(reader.invoke(stream, accounter)) for (i in 0 until count) it.add(reader.invoke(stream))
} }
} }
abstract fun write(stream: OutputStream, element: JsonElement) abstract fun write(stream: OutputStream, element: JsonElement)
abstract fun read(stream: InputStream, accounter: NbtAccounter): JsonElement abstract fun read(stream: InputStream): JsonElement
companion object { companion object {
val cached: ImmutableList<BinaryElementType> = ImmutableList.of( val cached: ImmutableList<BinaryElementType> = ImmutableList.of(
NULL, DOUBLE, BOOLEAN, INT, STRING, OBJECT, NULL, DOUBLE, BOOLEAN, INT, STRING, OBJECT,
DOUBLE_ARRAY, INT_ARRAY, BOOLEAN_ARRAY, ARRAY) DOUBLE_ARRAY, INT_ARRAY, BOOLEAN_ARRAY, ARRAY)
val ordered: ImmutableList<BinaryElementType> = ImmutableList.copyOf(values())
} }
} }
@ -208,9 +205,8 @@ fun OutputStream.writeBinaryJson(element: JsonElement) {
/** /**
* Reads json in binary form from stream * Reads json in binary form from stream
*/ */
fun InputStream.readBinaryJson(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): JsonElement { fun InputStream.readBinaryJson(): JsonElement {
sizeLimit.accountBytes(1L)
val id = read() - 1 val id = read() - 1
val reader = BinaryElementType.ordered.getOrNull(id) ?: throw JsonParseException("Unknown element type ${id + 1}") val reader = BinaryElementType.entries.getOrNull(id) ?: throw JsonParseException("Unknown element type ${id + 1}")
return reader.read(this, sizeLimit) return reader.read(this)
} }

View File

@ -12,8 +12,8 @@ import net.minecraft.nbt.NbtAccounter
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
fun FriendlyByteBuf.readBinaryJson(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18)): JsonElement { fun FriendlyByteBuf.readBinaryJson(): JsonElement {
return ByteBufInputStream(this).readBinaryJson(sizeLimit) return ByteBufInputStream(this).readBinaryJson()
} }
fun FriendlyByteBuf.writeBinaryJson(value: JsonElement) { fun FriendlyByteBuf.writeBinaryJson(value: JsonElement) {
@ -25,13 +25,13 @@ fun <S> FriendlyByteBuf.writeBinaryJsonWithCodec(codec: Codec<S>, value: S) {
.get().map({ it }, { throw EncoderException("Failed to encode input data: ${it.message()}") })) .get().map({ it }, { throw EncoderException("Failed to encode input data: ${it.message()}") }))
} }
fun <S> FriendlyByteBuf.readBinaryJsonWithCodec(codec: Codec<S>, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18)): S { fun <S> FriendlyByteBuf.readBinaryJsonWithCodec(codec: Codec<S>): S {
return codec.decode(JsonOps.INSTANCE, readBinaryJson(sizeLimit)) return codec.decode(JsonOps.INSTANCE, readBinaryJson())
.get().map({ it.first }, { throw DecoderException("Failed to decode data from network: ${it.message()}") }) .get().map({ it.first }, { throw DecoderException("Failed to decode data from network: ${it.message()}") })
} }
fun <S> FriendlyByteBuf.readBinaryJsonWithCodecIndirect(codec: Codec<S>, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18)): DataResult<S> { fun <S> FriendlyByteBuf.readBinaryJsonWithCodecIndirect(codec: Codec<S>): DataResult<S> {
return codec.decode(JsonOps.INSTANCE, readBinaryJson(sizeLimit)).map { it.first } return codec.decode(JsonOps.INSTANCE, readBinaryJson()).map { it.first }
} }
fun FriendlyByteBuf.readBinaryComponent(): Component { fun FriendlyByteBuf.readBinaryComponent(): Component {

View File

@ -30,9 +30,9 @@ fun OutputStream.writeNbt(value: CompoundTag) {
} }
} }
fun InputStream.readNbt(accounter: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): CompoundTag { fun InputStream.readNbt(): CompoundTag {
return try { return try {
NbtIo.read(if (this is DataInputStream) this else DataInputStream(this), accounter) NbtIo.read(if (this is DataInputStream) this else DataInputStream(this))
} catch (ioexception: IOException) { } catch (ioexception: IOException) {
throw EncoderException(ioexception) throw EncoderException(ioexception)
} }
@ -62,19 +62,16 @@ fun OutputStream.writeItem(itemStack: ItemStack, limitedTag: Boolean = true) {
} }
} }
fun InputStream.readItem(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): ItemStack { fun InputStream.readItem(): ItemStack {
sizeLimit.accountBytes(1L)
if (read() == 0) { if (read() == 0) {
return ItemStack.EMPTY return ItemStack.EMPTY
} }
sizeLimit.accountBytes(9L)
val item = (ForgeRegistries.ITEMS as ForgeRegistry<Item>).getValue(readInt()) val item = (ForgeRegistries.ITEMS as ForgeRegistry<Item>).getValue(readInt())
val itemStack = ItemStack(item, readInt()) val itemStack = ItemStack(item, readInt())
if (read() != 0) { if (read() != 0) {
itemStack.readShareTag(readNbt(sizeLimit)) itemStack.readShareTag(readNbt())
} }
return itemStack return itemStack
@ -99,7 +96,7 @@ fun OutputStream.writeFluidStack(value: FluidStack) {
} }
} }
fun InputStream.readFluidStack(sizeLimit: NbtAccounter = NbtAccounter(1L shl 14 /* 16 KiB */)): FluidStack { fun InputStream.readFluidStack(): FluidStack {
if (read() == 0) { if (read() == 0) {
return FluidStack.EMPTY return FluidStack.EMPTY
} else { } else {
@ -108,7 +105,7 @@ fun InputStream.readFluidStack(sizeLimit: NbtAccounter = NbtAccounter(1L shl 14
val amount = readInt() val amount = readInt()
if (read() > 0) { if (read() > 0) {
return FluidStack(fluid, amount, readNbt(sizeLimit)) return FluidStack(fluid, amount, readNbt())
} else { } else {
return FluidStack(fluid, amount) return FluidStack(fluid, amount)
} }
@ -122,11 +119,10 @@ fun OutputStream.writeBigDecimal(value: BigDecimal) {
write(bytes) write(bytes)
} }
fun InputStream.readBigDecimal(sizeLimit: NbtAccounter = NbtAccounter(512L)): BigDecimal { fun InputStream.readBigDecimal(): BigDecimal {
val scale = readInt() val scale = readInt()
val size = readVarIntLE(sizeLimit) val size = readVarIntLE()
require(size >= 0) { "Negative payload size: $size" } require(size >= 0) { "Negative payload size: $size" }
sizeLimit.accountBytes(size.toLong() + 4L)
val bytes = ByteArray(size) val bytes = ByteArray(size)
read(bytes) read(bytes)
return BigDecimal(BigInteger(bytes), scale) return BigDecimal(BigInteger(bytes), scale)
@ -215,8 +211,7 @@ fun InputStream.readFloat() = Float.fromBits(readInt())
fun OutputStream.writeDouble(value: Double) = writeLong(value.toBits()) fun OutputStream.writeDouble(value: Double) = writeLong(value.toBits())
fun InputStream.readDouble() = Double.fromBits(readLong()) fun InputStream.readDouble() = Double.fromBits(readLong())
fun InputStream.readVarIntLE(sizeLimit: NbtAccounter? = null): Int { fun InputStream.readVarIntLE(): Int {
sizeLimit?.accountBytes(1L)
val readFirst = read() val readFirst = read()
if (readFirst < 0) { if (readFirst < 0) {
@ -234,7 +229,6 @@ fun InputStream.readVarIntLE(sizeLimit: NbtAccounter? = null): Int {
while (nextBit != 0) { while (nextBit != 0) {
result = result or (read shl i) result = result or (read shl i)
sizeLimit?.accountBytes(1L)
read = read() read = read()
if (read < 0) { if (read < 0) {
@ -314,10 +308,9 @@ fun OutputStream.writeVarLongLE(value: Long) {
} }
} }
fun InputStream.readBinaryString(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): String { fun InputStream.readBinaryString(): String {
val size = readVarIntLE() val size = readVarIntLE()
require(size >= 0) { "Negative payload size: $size" } require(size >= 0) { "Negative payload size: $size" }
sizeLimit.accountBytes(size.toLong())
val bytes = ByteArray(size) val bytes = ByteArray(size)
read(bytes) read(bytes)
return bytes.decodeToString() return bytes.decodeToString()
@ -329,8 +322,8 @@ fun OutputStream.writeBinaryString(input: String) {
write(bytes) write(bytes)
} }
fun InputStream.readResourceLocation(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): ResourceLocation { fun InputStream.readResourceLocation(): ResourceLocation {
return ResourceLocation(readBinaryString(sizeLimit), readBinaryString(sizeLimit)) return ResourceLocation(readBinaryString(), readBinaryString())
} }
fun OutputStream.writeResourceLocation(value: ResourceLocation) { fun OutputStream.writeResourceLocation(value: ResourceLocation) {

View File

@ -32,7 +32,7 @@ import kotlin.reflect.KClass
* Also provides [copy] and [compare] methods * Also provides [copy] and [compare] methods
*/ */
interface IStreamCodec<V> { interface IStreamCodec<V> {
fun read(stream: DataInputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): V fun read(stream: DataInputStream): V
fun write(stream: DataOutputStream, value: V) fun write(stream: DataOutputStream, value: V)
/** /**
@ -51,7 +51,7 @@ interface IStreamCodec<V> {
} }
class StreamCodec<V>( class StreamCodec<V>(
private val reader: (stream: DataInputStream, sizeLimit: NbtAccounter) -> V, private val reader: (stream: DataInputStream) -> V,
private val writer: (stream: DataOutputStream, value: V) -> Unit, private val writer: (stream: DataOutputStream, value: V) -> Unit,
private val copier: ((value: V) -> V) = { it }, private val copier: ((value: V) -> V) = { it },
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b } private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
@ -62,12 +62,11 @@ class StreamCodec<V>(
writer: (stream: DataOutputStream, value: V) -> Unit, writer: (stream: DataOutputStream, value: V) -> Unit,
copier: ((value: V) -> V) = { it }, copier: ((value: V) -> V) = { it },
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b } comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : this({ stream, sizeLimit -> sizeLimit.accountBytes(payloadSize); reader.invoke(stream) }, writer, copier, comparator) ) : this({ stream -> reader.invoke(stream) }, writer, copier, comparator)
val nullable = object : IStreamCodec<V?> { val nullable = object : IStreamCodec<V?> {
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V? { override fun read(stream: DataInputStream): V? {
sizeLimit.accountBytes(1L) return if (stream.read() == 0) null else reader.invoke(stream)
return if (stream.read() == 0) null else reader.invoke(stream, sizeLimit)
} }
override fun write(stream: DataOutputStream, value: V?) { override fun write(stream: DataOutputStream, value: V?) {
@ -88,8 +87,8 @@ class StreamCodec<V>(
} }
} }
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V { override fun read(stream: DataInputStream): V {
return reader.invoke(stream, sizeLimit) return reader.invoke(stream)
} }
override fun write(stream: DataOutputStream, value: V) { override fun write(stream: DataOutputStream, value: V) {
@ -106,8 +105,8 @@ class StreamCodec<V>(
} }
class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStreamCodec<E>, val collectionFactory: (Int) -> C) : IStreamCodec<C> { class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStreamCodec<E>, val collectionFactory: (Int) -> C) : IStreamCodec<C> {
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): C { override fun read(stream: DataInputStream): C {
val size = stream.readVarIntLE(sizeLimit) val size = stream.readVarIntLE()
if (size <= 0) { if (size <= 0) {
return collectionFactory.invoke(0) return collectionFactory.invoke(0)
@ -116,7 +115,7 @@ class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStre
val collection = collectionFactory.invoke(size) val collection = collectionFactory.invoke(size)
for (i in 0 until size) { for (i in 0 until size) {
collection.add(elementCodec.read(stream, sizeLimit)) collection.add(elementCodec.read(stream))
} }
return collection return collection
@ -134,7 +133,7 @@ class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStre
} }
} }
val NullValueCodec = StreamCodec({ _, _ -> null }, { _, _ -> }) val NullValueCodec = StreamCodec({ _ -> null }, { _, _ -> })
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean) { a, b -> a == b } val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean) { a, b -> a == b }
val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) }) { a, b -> a == b } val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) }) { a, b -> a == b }
val ShortValueCodec = StreamCodec(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) }) { a, b -> a == b } val ShortValueCodec = StreamCodec(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) }) { a, b -> a == b }
@ -147,18 +146,18 @@ val FluidStackValueCodec = StreamCodec(DataInputStream::readFluidStack, DataOutp
val ItemValueCodec = StreamCodec(DataInputStream::readItemType, DataOutputStream::writeItemType) { a, b -> a === b } val ItemValueCodec = StreamCodec(DataInputStream::readItemType, DataOutputStream::writeItemType) { a, b -> a === b }
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal) val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal) val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
val UUIDValueCodec = StreamCodec({ s, a -> a.accountBytes(8L); UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) }) val UUIDValueCodec = StreamCodec({ s -> UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
val VarIntValueCodec = StreamCodec(DataInputStream::readVarIntLE, DataOutputStream::writeVarIntLE) { a, b -> a == b } val VarIntValueCodec = StreamCodec(DataInputStream::readVarIntLE, DataOutputStream::writeVarIntLE) { a, b -> a == b }
val VarLongValueCodec = StreamCodec(DataInputStream::readVarLongLE, DataOutputStream::writeVarLongLE) { a, b -> a == b } val VarLongValueCodec = StreamCodec(DataInputStream::readVarLongLE, DataOutputStream::writeVarLongLE) { a, b -> a == b }
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString) val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
val ResourceLocationValueCodec = StreamCodec(DataInputStream::readResourceLocation, DataOutputStream::writeResourceLocation) val ResourceLocationValueCodec = StreamCodec(DataInputStream::readResourceLocation, DataOutputStream::writeResourceLocation)
val RGBCodec: StreamCodec<RGBAColor> = StreamCodec( val RGBCodec: StreamCodec<RGBAColor> = StreamCodec(
{ s, a -> a.accountBytes(12L); RGBAColor(s.readFloat(), s.readFloat(), s.readFloat()) }, { s -> RGBAColor(s.readFloat(), s.readFloat(), s.readFloat()) },
{ s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue) }) { s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue) })
val RGBACodec: StreamCodec<RGBAColor> = StreamCodec( val RGBACodec: StreamCodec<RGBAColor> = StreamCodec(
{ s, a -> a.accountBytes(16L); RGBAColor(s.readFloat(), s.readFloat(), s.readFloat(), s.readFloat()) }, { s -> RGBAColor(s.readFloat(), s.readFloat(), s.readFloat(), s.readFloat()) },
{ s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) }) { s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) })
class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>) : IStreamCodec<V>, Codec<V> { class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>) : IStreamCodec<V>, Codec<V> {
@ -168,8 +167,8 @@ class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>) : IStreamCodec<V>, Codec<
for (v in values) put(v.name, v) for (v in values) put(v.name, v)
} }
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V { override fun read(stream: DataInputStream): V {
val id = stream.readVarIntLE(sizeLimit) val id = stream.readVarIntLE()
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id") return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
} }

View File

@ -8,6 +8,9 @@ import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps import com.mojang.serialization.JsonOps
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled
import net.minecraft.advancements.AdvancementHolder
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
@ -21,7 +24,15 @@ import ru.dbotthepony.mc.otm.core.util.readBinaryJsonWithCodecIndirect
import ru.dbotthepony.mc.otm.core.util.writeBinaryJsonWithCodec import ru.dbotthepony.mc.otm.core.util.writeBinaryJsonWithCodec
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
import kotlin.concurrent.getOrSet import kotlin.concurrent.getOrSet
import kotlin.reflect.KProperty
/**
* 1.20.2: Mojang FINALLY moved json IO of recipes to codecs
*
* ...but they forgot to do the same for Networking them, Ingredient does not have codec for network.
*
* Mojang.... Mojang never changes.
*/
class Codec2RecipeSerializer<S : Recipe<*>>( class Codec2RecipeSerializer<S : Recipe<*>>(
val empty: S?, val empty: S?,
codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>, codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>,
@ -29,15 +40,45 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
constructor(supplier: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(null, supplier) constructor(supplier: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(null, supplier)
private class CurrentContext { private class CurrentContext {
val idStack = ArrayDeque<ResourceLocation>()
var isNetwork = 0 var isNetwork = 0
} }
inner class Context { inner class Context {
val id: ResourceLocation
get() = checkNotNull(context.idStack.lastOrNull()) { "Not currently deserializing recipe" }
val ingredients: Codec<Ingredient> get() = ActualIngredientCodec val ingredients: Codec<Ingredient> get() = ActualIngredientCodec
fun <P : Recipe<*>> wrap(serializer: RecipeSerializer<P>): Codec<P> {
return object : Codec<P> {
override fun <T : Any?> encode(input: P, ops: DynamicOps<T>, prefix: T): DataResult<T> {
if (context.isNetwork > 0) {
val parent = Unpooled.buffer()
val buff = FriendlyByteBuf(parent)
serializer.toNetwork(buff, input)
return DataResult.success(ops.createByteList(parent.nioBuffer()))
} else {
return serializer.codec().encode(input, ops, prefix)
}
}
override fun <T : Any?> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<P, T>> {
if (context.isNetwork > 0) {
return ops.getByteBuffer(input).flatMap {
val parent = Unpooled.buffer()
val buff = FriendlyByteBuf(parent)
parent.writeBytes(it)
parent.setIndex(0, 0)
val read = serializer.fromNetwork(buff)
if (read == null)
DataResult.error { "Unable to read parent recipe from network" }
else
DataResult.success(Pair(read, ops.empty()))
}
} else {
return serializer.codec().decode(ops, input)
}
}
}
}
} }
private val codec = codec.invoke(Context()) private val codec = codec.invoke(Context())
@ -56,45 +97,30 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
} }
} }
override fun fromJson(id: ResourceLocation, data: JsonObject): S { override fun codec(): Codec<S> {
try { return this
context.idStack.addLast(id)
return decode(JsonOps.INSTANCE, data).get().map(
{ it.first },
{ empty ?: throw JsonSyntaxException("Failed to deserialize recipe from JSON: ${it.message()}") }
)
} finally {
context.idStack.removeLast()
}
} }
override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): S? { override fun fromNetwork(data: FriendlyByteBuf): S? {
try { try {
context.idStack.addLast(id)
context.isNetwork++ context.isNetwork++
return data.readBinaryJsonWithCodecIndirect(this) return data.readBinaryJsonWithCodecIndirect(this)
.resultOrPartial { LOGGER.error("Failed to read recipe $id from network: $it") }.orElse(null) .resultOrPartial { LOGGER.error("Failed to read recipe from network: $it") }.orElse(null)
} finally { } finally {
context.isNetwork-- context.isNetwork--
context.idStack.removeLast()
} }
} }
override fun toNetwork(data: FriendlyByteBuf, recipe: S) { override fun toNetwork(data: FriendlyByteBuf, recipe: S) {
try { try {
context.idStack.addLast(recipe.id)
context.isNetwork++ context.isNetwork++
data.writeBinaryJsonWithCodec(this, recipe) data.writeBinaryJsonWithCodec(this, recipe)
} finally { } finally {
context.isNetwork-- context.isNetwork--
context.idStack.removeLast()
} }
} }
fun toFinished(recipe: S): FinishedRecipe { fun toFinished(recipe: S, id: ResourceLocation): FinishedRecipe {
return object : FinishedRecipe { return object : FinishedRecipe {
override fun serializeRecipeData(p_125967_: JsonObject) { override fun serializeRecipeData(p_125967_: JsonObject) {
encode(recipe, JsonOps.INSTANCE, p_125967_).get().map( encode(recipe, JsonOps.INSTANCE, p_125967_).get().map(
@ -111,19 +137,15 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
) )
} }
override fun getId(): ResourceLocation { override fun id(): ResourceLocation {
return recipe.id return id
} }
override fun getType(): RecipeSerializer<*> { override fun type(): RecipeSerializer<*> {
return this@Codec2RecipeSerializer return this@Codec2RecipeSerializer
} }
override fun serializeAdvancement(): JsonObject? { override fun advancement(): AdvancementHolder? {
return null
}
override fun getAdvancementId(): ResourceLocation? {
return null return null
} }
} }
@ -134,7 +156,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) { return if (context.isNetwork > 0) {
networkIngredientCodec.encode(input, ops, prefix) networkIngredientCodec.encode(input, ops, prefix)
} else { } else {
IngredientCodec.encode(input, ops, prefix) Ingredient.CODEC.encode(input, ops, prefix)
} }
} }
@ -142,7 +164,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) { return if (context.isNetwork > 0) {
networkIngredientCodec.decode(ops, input) networkIngredientCodec.decode(ops, input)
} else { } else {
IngredientCodec.decode(ops, input) Ingredient.CODEC.decode(ops, input)
} }
} }
} }
@ -156,8 +178,14 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
* since RecipeSerializers are expected to be stateless. [Codec2RecipeSerializer], however, is stateful (threading PoV). * since RecipeSerializers are expected to be stateless. [Codec2RecipeSerializer], however, is stateful (threading PoV).
* To make it stateless, [ThreadLocal] is used. * To make it stateless, [ThreadLocal] is used.
*/ */
private val contextHolder = ThreadLocal<CurrentContext>() private val context by object : ThreadLocal<CurrentContext>() {
private val context: CurrentContext override fun initialValue(): CurrentContext {
get() = contextHolder.getOrSet { CurrentContext() } return CurrentContext()
}
}
} }
} }
private operator fun <T> ThreadLocal<T>.getValue(companion: Codec2RecipeSerializer.Companion, property: KProperty<*>): T {
return get()
}

View File

@ -1,37 +0,0 @@
package ru.dbotthepony.mc.otm.data
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSyntaxException
import com.mojang.serialization.Codec
import net.minecraft.world.level.storage.loot.Serializer
import ru.dbotthepony.mc.otm.core.fromJsonStrict
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.toJsonStrict
class Codec2Serializer<T : Any>(val codec: Codec<T>, val embed: Boolean = true) : Serializer<T> {
override fun serialize(data: JsonObject, value: T, context: JsonSerializationContext) {
if (embed) {
val result = codec.toJsonStrict(value, data)
if (result !is JsonObject) {
throw RuntimeException("Expected JsonObject from codec, got ${result::class.qualifiedName}")
}
val keys = ArrayList(data.keySet())
for (k in keys) data.remove(k)
for ((k, v) in result.entrySet()) data[k] = v
} else {
data["value"] = codec.toJsonStrict(value)
}
}
override fun deserialize(data: JsonObject, context: JsonDeserializationContext): T {
if (embed) {
return codec.fromJsonStrict(data)
} else {
return codec.fromJsonStrict(data["value"] ?: throw JsonSyntaxException("Missing 'value' element"))
}
}
}

View File

@ -0,0 +1,100 @@
package ru.dbotthepony.mc.otm.data
import com.google.gson.JsonObject
import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps
import com.mojang.serialization.MapCodec
import com.mojang.serialization.MapLike
import com.mojang.serialization.RecordBuilder
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.EntityPredicate
import ru.dbotthepony.mc.otm.core.fromJsonStrict
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.toJsonStrict
import java.util.Optional
import java.util.stream.Stream
class Codec2TriggerSerializer<S : Any>(supplier: (Codec2TriggerSerializer<S>.Context) -> Codec<S>) : Codec<S> {
private val codec = supplier.invoke(Context())
override fun <T : Any> encode(input: S, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return codec.encode(input, ops, prefix)
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<S, T>> {
return codec.decode(ops, input)
}
fun fromJson(element: JsonObject, player: Optional<ContextAwarePredicate>, context: DeserializationContext): S {
try {
Companion.context.get().addLast(ThreadContext(player, context))
return codec.fromJsonStrict(element)
} finally {
Companion.context.get().removeLast()
}
}
fun toJson(value: S): JsonObject {
return codec.toJsonStrict(value) as JsonObject
}
inner class Context {
val playerPredicate: MapCodec<Optional<ContextAwarePredicate>>
get() = CAPPredicate
val awareContextCodec: Codec<ContextAwarePredicate>
get() = ActualCAPPredicate
}
private data class ThreadContext(val player: Optional<ContextAwarePredicate>, val context: DeserializationContext)
private object ActualCAPPredicate : Codec<ContextAwarePredicate> {
override fun <T : Any> encode(input: ContextAwarePredicate, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return try {
DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson()))
} catch (err: Exception) {
DataResult.error { "Failed to serialize ContextAwarePredicate: " + err.message }
}
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<ContextAwarePredicate, T>> {
val context = context.get().lastOrNull() ?: return DataResult.error { "Not current deserializing trigger instance" }
return try {
DataResult.success(Pair(EntityPredicate.fromJson(JsonObject().also { it["a"] = ops.convertTo(JsonOps.INSTANCE, input) }, "a", context.context).get(), ops.empty()))
} catch (err: Exception) {
DataResult.error { "Failed to deserialize ContextAwarePredicate: " + err.message }
}
}
}
private object CAPPredicate : MapCodec<Optional<ContextAwarePredicate>>() {
override fun <T : Any> keys(ops: DynamicOps<T>): Stream<T> {
return Stream.of(ops.createString("player"))
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: MapLike<T>): DataResult<Optional<ContextAwarePredicate>> {
return DataResult.success(context.get().lastOrNull()?.player ?: return DataResult.error { "Not currently deserializing trigger instance" })
}
override fun <T : Any> encode(input: Optional<ContextAwarePredicate>, ops: DynamicOps<T>, prefix: RecordBuilder<T>): RecordBuilder<T> {
if (input.isPresent) {
return prefix.add("player", JsonOps.INSTANCE.convertTo(ops, input.get().toJson()))
} else {
return prefix
}
}
}
companion object {
private val context = object : ThreadLocal<ArrayDeque<ThreadContext>>() {
override fun initialValue(): ArrayDeque<ThreadContext> {
return ArrayDeque()
}
}
}
}

View File

@ -1,9 +1,30 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data
import com.mojang.serialization.Codec import com.mojang.serialization.Codec
import com.mojang.serialization.Dynamic
import com.mojang.serialization.JsonOps
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.critereon.DamagePredicate
import net.minecraft.advancements.critereon.DamageSourcePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.MinMaxBounds
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
private val dealtReceived: Codec<Pair<MinMaxBounds.Doubles, MinMaxBounds.Doubles>> = RecordCodecBuilder.create {
it.group(
MinMaxBounds.Doubles.CODEC.fieldOf("dealt").forGetter { it.first },
MinMaxBounds.Doubles.CODEC.fieldOf("taken").forGetter { it.second },
).apply(it, ::Pair)
}
val DamagePredicateCodec: Codec<DamagePredicate> = RecordCodecBuilder.create {
it.group(
dealtReceived.fieldOf("damage").forGetter { it.dealtDamage to it.takenDamage },
Codec.BOOL.optionalFieldOf("blocked").forGetter { it.blocked },
EntityPredicate.CODEC.optionalFieldOf("source_entity").forGetter { it.sourceEntity },
DamageSourcePredicate.CODEC.optionalFieldOf("type").forGetter { it.type },
).apply(it) { damage, blocked, source, type -> DamagePredicate(damage.first, damage.second, source, blocked, type) }
}
fun <V, T1> simpleCodec(factory: (T1) -> V, field1: KProperty1<V, T1>, codec1: Codec<T1>): Codec<V> { fun <V, T1> simpleCodec(factory: (T1) -> V, field1: KProperty1<V, T1>, codec1: Codec<T1>): Codec<V> {
return RecordCodecBuilder.create { return RecordCodecBuilder.create {

View File

@ -1,23 +0,0 @@
package ru.dbotthepony.mc.otm.data
import com.google.gson.JsonSyntaxException
import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps
import net.minecraft.world.item.crafting.Ingredient
object IngredientCodec : Codec<Ingredient> {
override fun <T : Any> encode(input: Ingredient, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson()))
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Ingredient, T>> {
try {
return DataResult.success(Pair(Ingredient.fromJson(ops.convertTo(JsonOps.INSTANCE, input)), ops.empty()))
} catch (err: JsonSyntaxException) {
return DataResult.error { "Error decoding Ingredient: ${err.message}" }
}
}
}

View File

@ -1,27 +0,0 @@
package ru.dbotthepony.mc.otm.data
import com.google.gson.JsonObject
import com.google.gson.JsonParseException
import com.google.gson.JsonSyntaxException
import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps
import net.minecraft.advancements.critereon.ItemPredicate
object ItemPredicateCodec : Codec<ItemPredicate> {
override fun <T : Any> encode(input: ItemPredicate, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.serializeToJson().let { if (it is JsonObject) it.getRidOfNulls() else it }))
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<ItemPredicate, T>> {
return try {
DataResult.success(Pair(ItemPredicate.fromJson(ops.convertTo(JsonOps.INSTANCE, input)), ops.empty()))
} catch (err: JsonSyntaxException) {
DataResult.error { "Failed to deserialize ItemPredicate: ${err.message}" }
} catch (err: JsonParseException) {
DataResult.error { "Failed to deserialize ItemPredicate: ${err.message}" }
}
}
}

View File

@ -5,7 +5,6 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.registry.MLootItemConditions import ru.dbotthepony.mc.otm.registry.MLootItemConditions
/** /**
@ -29,6 +28,12 @@ data class ChanceCondition(val chance: Double) : LootItemCondition, LootItemCond
} }
companion object { companion object {
val SERIALIZER = Codec2Serializer<ChanceCondition>(RecordCodecBuilder.create { it.group(Codec.doubleRange(0.0, 1.0).fieldOf("chance").forGetter(ChanceCondition::chance)).apply(it, ::ChanceCondition) }) val CODEC: Codec<ChanceCondition> by lazy {
RecordCodecBuilder.create {
it.group(
Codec.doubleRange(0.0, 1.0).fieldOf("chance").forGetter(ChanceCondition::chance)
).apply(it, ::ChanceCondition)
}
}
} }
} }

View File

@ -7,7 +7,6 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.data.get import ru.dbotthepony.mc.otm.data.get
import ru.dbotthepony.mc.otm.registry.MLootItemConditions import ru.dbotthepony.mc.otm.registry.MLootItemConditions
@ -49,7 +48,7 @@ data class ChanceWithPlaytimeCondition(
} }
companion object { companion object {
val SERIALIZER = Codec2Serializer<ChanceWithPlaytimeCondition>( val CODEC: Codec<ChanceWithPlaytimeCondition> by lazy {
RecordCodecBuilder.create { RecordCodecBuilder.create {
it.group( it.group(
Codec.INT.optionalFieldOf("minPlaytime", 0).forGetter(ChanceWithPlaytimeCondition::minPlaytime), Codec.INT.optionalFieldOf("minPlaytime", 0).forGetter(ChanceWithPlaytimeCondition::minPlaytime),
@ -58,6 +57,6 @@ data class ChanceWithPlaytimeCondition(
Codec.DOUBLE.fieldOf("maxProbability").forGetter(ChanceWithPlaytimeCondition::maxProbability), Codec.DOUBLE.fieldOf("maxProbability").forGetter(ChanceWithPlaytimeCondition::maxProbability),
).apply(it, ::ChanceWithPlaytimeCondition) ).apply(it, ::ChanceWithPlaytimeCondition)
} }
) }
} }
} }

View File

@ -1,10 +1,6 @@
package ru.dbotthepony.mc.otm.data.condition package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject
import com.google.gson.JsonSerializationContext
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.Serializer
import net.minecraft.world.level.storage.loot.parameters.LootContextParams import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
@ -13,7 +9,7 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.data.get import ru.dbotthepony.mc.otm.data.get
import ru.dbotthepony.mc.otm.registry.MLootItemConditions import ru.dbotthepony.mc.otm.registry.MLootItemConditions
object HasExoPackCondition : LootItemCondition, Serializer<HasExoPackCondition>, LootItemCondition.Builder { object HasExoPackCondition : LootItemCondition, LootItemCondition.Builder {
override fun test(t: LootContext): Boolean { override fun test(t: LootContext): Boolean {
t[LootContextParams.LAST_DAMAGE_PLAYER]?.matteryPlayer?.let { t[LootContextParams.LAST_DAMAGE_PLAYER]?.matteryPlayer?.let {
return it.hasExopack return it.hasExopack
@ -26,13 +22,6 @@ object HasExoPackCondition : LootItemCondition, Serializer<HasExoPackCondition>,
return MLootItemConditions.HAS_EXOPACK return MLootItemConditions.HAS_EXOPACK
} }
override fun serialize(p_79325_: JsonObject, p_79326_: HasExoPackCondition, p_79327_: JsonSerializationContext) {
}
override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): HasExoPackCondition {
return this
}
override fun build(): LootItemCondition { override fun build(): LootItemCondition {
return this return this
} }

View File

@ -9,7 +9,6 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import ru.dbotthepony.mc.otm.capability.items import ru.dbotthepony.mc.otm.capability.items
import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.data.get import ru.dbotthepony.mc.otm.data.get
import ru.dbotthepony.mc.otm.registry.MLootItemConditions import ru.dbotthepony.mc.otm.registry.MLootItemConditions
@ -58,7 +57,7 @@ data class ItemInInventoryCondition(
} }
companion object { companion object {
val SERIALIZER = Codec2Serializer<ItemInInventoryCondition>( val CODEC: Codec<ItemInInventoryCondition> by lazy {
RecordCodecBuilder.create { RecordCodecBuilder.create {
it.group( it.group(
ItemStack.CODEC.fieldOf("item").forGetter(ItemInInventoryCondition::item), ItemStack.CODEC.fieldOf("item").forGetter(ItemInInventoryCondition::item),
@ -67,6 +66,6 @@ data class ItemInInventoryCondition(
Codec.BOOL.optionalFieldOf("matchCosmetics", false).forGetter(ItemInInventoryCondition::matchCosmetics), Codec.BOOL.optionalFieldOf("matchCosmetics", false).forGetter(ItemInInventoryCondition::matchCosmetics),
).apply(it, ::ItemInInventoryCondition) ).apply(it, ::ItemInInventoryCondition)
} }
) }
} }
} }

View File

@ -1,10 +1,6 @@
package ru.dbotthepony.mc.otm.data.condition package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject
import com.google.gson.JsonSerializationContext
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.Serializer
import net.minecraft.world.level.storage.loot.parameters.LootContextParams import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
@ -13,7 +9,7 @@ import net.minecraftforge.common.util.FakePlayer
import ru.dbotthepony.mc.otm.data.get import ru.dbotthepony.mc.otm.data.get
import ru.dbotthepony.mc.otm.registry.MLootItemConditions import ru.dbotthepony.mc.otm.registry.MLootItemConditions
object KilledByRealPlayer : LootItemCondition, Serializer<KilledByRealPlayer>, LootItemCondition.Builder { object KilledByRealPlayer : LootItemCondition, LootItemCondition.Builder {
override fun test(t: LootContext): Boolean { override fun test(t: LootContext): Boolean {
return t.hasParam(LootContextParams.LAST_DAMAGE_PLAYER) && t[LootContextParams.LAST_DAMAGE_PLAYER] !is FakePlayer return t.hasParam(LootContextParams.LAST_DAMAGE_PLAYER) && t[LootContextParams.LAST_DAMAGE_PLAYER] !is FakePlayer
} }
@ -22,13 +18,6 @@ object KilledByRealPlayer : LootItemCondition, Serializer<KilledByRealPlayer>, L
return MLootItemConditions.KILLED_BY_REAL_PLAYER return MLootItemConditions.KILLED_BY_REAL_PLAYER
} }
override fun serialize(p_79325_: JsonObject, p_79326_: KilledByRealPlayer, p_79327_: JsonSerializationContext) {
}
override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): KilledByRealPlayer {
return this
}
override fun build(): LootItemCondition { override fun build(): LootItemCondition {
return this return this
} }

View File

@ -1,11 +1,7 @@
package ru.dbotthepony.mc.otm.data.condition package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject
import com.google.gson.JsonSerializationContext
import net.minecraft.world.entity.OwnableEntity import net.minecraft.world.entity.OwnableEntity
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.Serializer
import net.minecraft.world.level.storage.loot.parameters.LootContextParams import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
@ -15,7 +11,7 @@ import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.data.get import ru.dbotthepony.mc.otm.data.get
import ru.dbotthepony.mc.otm.registry.MLootItemConditions import ru.dbotthepony.mc.otm.registry.MLootItemConditions
object KilledByRealPlayerOrIndirectly : LootItemCondition, Serializer<KilledByRealPlayerOrIndirectly>, LootItemCondition.Builder { object KilledByRealPlayerOrIndirectly : LootItemCondition, LootItemCondition.Builder {
override fun test(t: LootContext): Boolean { override fun test(t: LootContext): Boolean {
if (t.hasParam(LootContextParams.LAST_DAMAGE_PLAYER) && t[LootContextParams.LAST_DAMAGE_PLAYER] !is FakePlayer) { if (t.hasParam(LootContextParams.LAST_DAMAGE_PLAYER) && t[LootContextParams.LAST_DAMAGE_PLAYER] !is FakePlayer) {
return true return true
@ -43,13 +39,6 @@ object KilledByRealPlayerOrIndirectly : LootItemCondition, Serializer<KilledByRe
return MLootItemConditions.KILLED_BY_REAL_PLAYER_OR_INDIRECTLY return MLootItemConditions.KILLED_BY_REAL_PLAYER_OR_INDIRECTLY
} }
override fun serialize(p_79325_: JsonObject, p_79326_: KilledByRealPlayerOrIndirectly, p_79327_: JsonSerializationContext) {
}
override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): KilledByRealPlayerOrIndirectly {
return this
}
override fun build(): LootItemCondition { override fun build(): LootItemCondition {
return this return this
} }

View File

@ -1,28 +1,23 @@
package ru.dbotthepony.mc.otm.data.loot package ru.dbotthepony.mc.otm.data.loot
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.gson.JsonArray import com.mojang.serialization.Codec
import com.google.gson.JsonDeserializationContext import com.mojang.serialization.codecs.RecordCodecBuilder
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.item.BlockItem import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.Serializer
import net.minecraft.world.level.storage.loot.functions.LootItemFunction import net.minecraft.world.level.storage.loot.functions.LootItemFunction
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType
import net.minecraft.world.level.storage.loot.parameters.LootContextParams import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.core.nbt.getJson
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.stream import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.core.collect.stream
import ru.dbotthepony.mc.otm.core.nbt.getJson
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
import java.util.Optional
import java.util.stream.Stream import java.util.stream.Stream
class CopyTileNbtFunction(filter: Stream<out String> = Stream.empty()) : LootItemFunction, LootItemFunction.Builder { class CopyTileNbtFunction(filter: Stream<out String> = Stream.empty()) : LootItemFunction, LootItemFunction.Builder {
@ -77,20 +72,16 @@ class CopyTileNbtFunction(filter: Stream<out String> = Stream.empty()) : LootIte
return this return this
} }
companion object : Serializer<CopyTileNbtFunction> { companion object {
override fun serialize( val CODEC: Codec<CopyTileNbtFunction> by lazy {
pJson: JsonObject, RecordCodecBuilder.create {
pValue: CopyTileNbtFunction, it.group(
pSerializationContext: JsonSerializationContext Codec.STRING.listOf()
) { .optionalFieldOf("filter")
pJson["filter"] = JsonArray().also { for (v in pValue.filter) it.add(v) } .xmap({ it.orElseGet { listOf() } }, { if (it.isEmpty()) Optional.empty() else Optional.of(it) })
} .forGetter(CopyTileNbtFunction::filter),
).apply(it, ::CopyTileNbtFunction)
override fun deserialize( }
pJson: JsonObject,
pSerializationContext: JsonDeserializationContext
): CopyTileNbtFunction {
return CopyTileNbtFunction((pJson["filter"] as? JsonArray)?.stream()?.filter { it is JsonPrimitive }?.map { it.asString!! } ?: Stream.empty())
} }
} }
} }

View File

@ -1,24 +1,16 @@
package ru.dbotthepony.mc.otm.data.loot package ru.dbotthepony.mc.otm.data.loot
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.gson.*
import com.mojang.serialization.Codec import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.Dynamic
import com.mojang.serialization.JsonOps
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import it.unimi.dsi.fastutil.objects.ObjectArrayList import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.Deserializers
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.LootPool import net.minecraft.world.level.storage.loot.LootPool
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.common.loot.IGlobalLootModifier import net.minecraftforge.common.loot.IGlobalLootModifier
import net.minecraftforge.common.loot.LootModifier import net.minecraftforge.common.loot.LootModifier
import java.util.Arrays import java.util.*
import java.util.Deque
import java.util.stream.Stream import java.util.stream.Stream
class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<LootPool>) : LootModifier(conditions) { class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<LootPool>) : LootModifier(conditions) {
@ -39,53 +31,11 @@ class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<L
return CODEC return CODEC
} }
// TODO: remove reflection once Forge implement a way to provide lootpool deserialization context in non-reflective way
companion object { companion object {
private val lootPoolCodec: Codec<List<LootPool>>
private val forgeHooksLootContext by lazy {
val field = ForgeHooks::class.java.getDeclaredField("lootContext")
field.isAccessible = true
field
}
private val lootTableContextConstructor by lazy {
val clazz = ForgeHooks::class.java.declaredClasses.firstOrNull { it.name.contains("LootTableContext") } ?: throw NoSuchElementException("Unable to find ForgeHooks\$LootTableContext!")
val constructor = clazz.getDeclaredConstructor(ResourceLocation::class.java, Boolean::class.java)
constructor.isAccessible = true
constructor
}
init {
val serializer = Deserializers.createLootTableSerializer().create()
val notExistingLocation = ResourceLocation("null", "null")
lootPoolCodec = Codec.list(Codec.PASSTHROUGH.flatXmap({
val dequeueHolder = forgeHooksLootContext.get(null) as ThreadLocal<Deque<Any>>
val deque = dequeueHolder.get() ?: java.util.ArrayDeque()
dequeueHolder.set(deque)
try {
deque.push(lootTableContextConstructor.newInstance(notExistingLocation, true))
DataResult.success(serializer.fromJson(it.convert(JsonOps.INSTANCE).value, LootPool::class.java))
} catch(err: JsonSyntaxException) {
DataResult.error { err.message }
} finally {
deque.pop()
}
}, {
try {
DataResult.success(Dynamic(JsonOps.INSTANCE, serializer.toJsonTree(it)))
} catch(err: JsonSyntaxException) {
DataResult.error { err.message }
}
}))
}
val CODEC: Codec<LootPoolAppender> = val CODEC: Codec<LootPoolAppender> =
RecordCodecBuilder.create { RecordCodecBuilder.create {
codecStart(it).and( codecStart(it).and(
lootPoolCodec.fieldOf("pools").forGetter(LootPoolAppender::pools) LootPool.CODEC.listOf().fieldOf("pools").forGetter(LootPoolAppender::pools)
).apply(it, ::LootPoolAppender) ).apply(it, ::LootPoolAppender)
} }
} }

View File

@ -107,7 +107,7 @@ class FluidCapsuleItem(val capacity: IntSupplier) : Item(Properties().stacksTo(6
actionResult.result actionResult.result
} else { } else {
val state = level.getBlockState(hitPos) val state = level.getBlockState(hitPos)
val placePos = if (state.block is LiquidBlockContainer && (state.block as LiquidBlockContainer).canPlaceLiquid(level, hitPos, state, fluid.fluid)) hitPos else nextPos val placePos = if (state.block is LiquidBlockContainer && (state.block as LiquidBlockContainer).canPlaceLiquid(player, level, hitPos, state, fluid.fluid)) hitPos else nextPos
val actionResult = FluidUtil.tryPlaceFluid(player, level, hand, placePos, targetItem, fluid) val actionResult = FluidUtil.tryPlaceFluid(player, level, hand, placePos, targetItem, fluid)
if (!actionResult.isSuccess) return InteractionResultHolder.pass(item) if (!actionResult.isSuccess) return InteractionResultHolder.pass(item)

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.mc.otm.item package ru.dbotthepony.mc.otm.item
import net.minecraft.core.BlockSource
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.dispenser.BlockSource
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior import net.minecraft.core.dispenser.DefaultDispenseItemBehavior
import net.minecraft.core.dispenser.DispenseItemBehavior import net.minecraft.core.dispenser.DispenseItemBehavior
import net.minecraft.tags.BlockTags import net.minecraft.tags.BlockTags
@ -67,11 +67,11 @@ class MinecartCargoCrateItem(val color: DyeColor?) : Item(Properties().stacksTo(
private val default = DefaultDispenseItemBehavior() private val default = DefaultDispenseItemBehavior()
override fun dispense(blockSource: BlockSource, itemStack: ItemStack): ItemStack { override fun dispense(blockSource: BlockSource, itemStack: ItemStack): ItemStack {
val direction = blockSource.blockState.getValue(DispenserBlock.FACING) val direction = blockSource.state.getValue(DispenserBlock.FACING)
val level: Level = blockSource.level val level: Level = blockSource.level
val x = blockSource.x() + direction.stepX.toDouble() * 1.125 val x = blockSource.pos.x + direction.stepX.toDouble() * 1.125
val y = floor(blockSource.y()) + direction.stepY.toDouble() val y = blockSource.pos.y + direction.stepY.toDouble()
val z = blockSource.z() + direction.stepZ.toDouble() * 1.125 val z = blockSource.pos.z + direction.stepZ.toDouble() * 1.125
val blockpos = blockSource.pos.relative(direction) val blockpos = blockSource.pos.relative(direction)
val blockstate = level.getBlockState(blockpos) val blockstate = level.getBlockState(blockpos)
val railshape = val railshape =

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.item package ru.dbotthepony.mc.otm.item
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
@ -23,7 +24,6 @@ import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.math.set
import ru.dbotthepony.mc.otm.core.nbt.mapPresent import ru.dbotthepony.mc.otm.core.nbt.mapPresent
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.data.DecimalProvider import ru.dbotthepony.mc.otm.data.DecimalProvider
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
import java.util.Optional import java.util.Optional
@ -119,17 +119,15 @@ class ProceduralBatteryItem : Item(Properties().stacksTo(1)) {
} }
companion object { companion object {
val SERIALIZER by lazy { val CODEC: Codec<Randomizer> by lazy {
Codec2Serializer<Randomizer>( RecordCodecBuilder.create {
RecordCodecBuilder.create { it.group(
it.group( DecimalProvider.CODEC.fieldOf("maxBatteryLevel").forGetter(Randomizer::maxBatteryLevel),
DecimalProvider.CODEC.fieldOf("maxBatteryLevel").forGetter(Randomizer::maxBatteryLevel), DecimalProvider.CODEC.optionalFieldOf("batteryLevel").forGetter(Randomizer::batteryLevel),
DecimalProvider.CODEC.optionalFieldOf("batteryLevel").forGetter(Randomizer::batteryLevel), DecimalProvider.CODEC.fieldOf("maxInput").forGetter(Randomizer::maxInput),
DecimalProvider.CODEC.fieldOf("maxInput").forGetter(Randomizer::maxInput), DecimalProvider.CODEC.optionalFieldOf("maxOutput").forGetter(Randomizer::maxOutput),
DecimalProvider.CODEC.optionalFieldOf("maxOutput").forGetter(Randomizer::maxOutput), ).apply(it, ::Randomizer)
).apply(it, ::Randomizer) }
}
)
} }
} }
} }

View File

@ -7,6 +7,7 @@ import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.util.datafix.DataFixTypes
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity import net.minecraft.world.item.Rarity
@ -20,7 +21,7 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.event.TickEvent import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.TickEvent.ServerTickEvent import net.minecraftforge.event.TickEvent.ServerTickEvent
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
@ -52,7 +53,6 @@ import ru.dbotthepony.mc.otm.isServerThread
import ru.dbotthepony.mc.otm.lazyPerServer import ru.dbotthepony.mc.otm.lazyPerServer
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.packetHandled
import java.util.* import java.util.*
import java.util.function.Function import java.util.function.Function
import java.util.function.Supplier import java.util.function.Supplier
@ -155,7 +155,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
val clientData = Object2ObjectOpenHashMap<UUID, IValues>() val clientData = Object2ObjectOpenHashMap<UUID, IValues>()
val serverData: Data by lazyPerServer { val serverData: Data by lazyPerServer {
it.overworld().dataStorage.computeIfAbsent(::Data, ::Data, "otm_$savedataID") it.overworld().dataStorage.computeIfAbsent(SavedData.Factory(::Data, ::Data, DataFixTypes.SAVED_DATA_MAP_DATA), "otm_$savedataID")
} }
private inner class Power(private val stack: ItemStack) : IMatteryEnergyStorage, ICapabilityProvider { private inner class Power(private val stack: ItemStack) : IMatteryEnergyStorage, ICapabilityProvider {
@ -377,8 +377,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
buff.writeDecimal(received) buff.writeDecimal(received)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
val data = type.clientData.computeIfAbsent(uuid, Function { UnboundValues(it) }) val data = type.clientData.computeIfAbsent(uuid, Function { UnboundValues(it) })
data.energy = energy data.energy = energy
data.passed = passed data.passed = passed

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.item.exopack package ru.dbotthepony.mc.otm.item.exopack
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -14,7 +15,6 @@ import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
import java.util.* import java.util.*
@ -34,14 +34,12 @@ class ProceduralExopackSlotUpgradeItem : AbstractExopackSlotUpgradeItem(defaultP
} }
companion object { companion object {
val SERIALIZER = Codec2Serializer<Randomizer>( val CODEC: Codec<Randomizer> = RecordCodecBuilder.create {
RecordCodecBuilder.create { it.group(
it.group( IntProvider.CODEC.fieldOf("slots").forGetter(Randomizer::slots),
IntProvider.CODEC.fieldOf("slots").forGetter(Randomizer::slots), IntProvider.CODEC.optionalFieldOf("luck_bias", ConstantInt.ZERO).forGetter(Randomizer::luckBias),
IntProvider.CODEC.optionalFieldOf("luck_bias", ConstantInt.ZERO).forGetter(Randomizer::luckBias), ).apply(it, ::Randomizer)
).apply(it, ::Randomizer) }
}
)
} }
} }

View File

@ -18,15 +18,12 @@ import net.minecraftforge.client.event.RenderHandEvent
import net.minecraftforge.client.event.RenderPlayerEvent import net.minecraftforge.client.event.RenderPlayerEvent
import net.minecraftforge.client.event.ViewportEvent import net.minecraftforge.client.event.ViewportEvent
import net.minecraftforge.event.TickEvent import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.fml.LogicalSide import net.minecraftforge.fml.LogicalSide
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.capability.matteryEnergy import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.client.font import ru.dbotthepony.mc.otm.client.font
import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.client.render.draw import ru.dbotthepony.mc.otm.client.render.draw
import ru.dbotthepony.mc.otm.client.render.renderRect import ru.dbotthepony.mc.otm.client.render.renderRect
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.math.Angle import ru.dbotthepony.mc.otm.core.math.Angle
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.core.math.Vector
@ -42,11 +39,12 @@ import ru.dbotthepony.mc.otm.core.nbt.EMPTY_UUID
import ru.dbotthepony.mc.otm.core.nbt.booleans import ru.dbotthepony.mc.otm.core.nbt.booleans
import ru.dbotthepony.mc.otm.core.nbt.ints import ru.dbotthepony.mc.otm.core.nbt.ints
import ru.dbotthepony.mc.otm.core.nbt.uuids import ru.dbotthepony.mc.otm.core.nbt.uuids
import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.WeaponNetworkChannel import ru.dbotthepony.mc.otm.network.WeaponNetworkChannel
import java.util.* import java.util.*
import java.util.function.Supplier import kotlin.collections.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.abs import kotlin.math.abs
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -62,16 +60,12 @@ enum class WeaponScopePacket(val scope: Boolean) : MatteryPacket {
buff.writeBoolean(scope) buff.writeBoolean(scope)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context){
context.get().packetHandled = true
// TODO: Manual synchronization // TODO: Manual synchronization
context.get().enqueueWork { val stack = context.sender!!.mainHandItem
val stack = context.get().sender!!.mainHandItem val item = stack.item as? AbstractWeaponItem<*> ?: return
val item = stack.item as? AbstractWeaponItem<*> ?: return@enqueueWork
item.dataTable(stack).wantsToScope = scope item.dataTable(stack).wantsToScope = scope
}
} }
companion object { companion object {
@ -86,26 +80,22 @@ enum class WeaponFireInputPacket(val primary: Boolean) : MatteryPacket {
buff.writeBoolean(primary) buff.writeBoolean(primary)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context){
context.get().packetHandled = true
// TODO: Manual synchronization // TODO: Manual synchronization
context.get().enqueueWork { val stack = context.sender!!.mainHandItem
val stack = context.get().sender!!.mainHandItem val item = stack.item as? AbstractWeaponItem<*> ?: return
val item = stack.item as? AbstractWeaponItem<*> ?: return@enqueueWork
// Listen server: client and server thread compete for lock // Listen server: client and server thread compete for lock
// so it is very likely item is being in predicted context // so it is very likely item is being in predicted context
val predictedData = item.dataTable val predictedData = item.dataTable
item.dataTable = null item.dataTable = null
if (primary) if (primary)
item.tryPrimaryFire(stack, context.get().sender!!) item.tryPrimaryFire(stack, context.sender!!)
else else
item.trySecondaryFire(stack, context.get().sender!!) item.trySecondaryFire(stack, context.sender!!)
(item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData (item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
}
} }
companion object { companion object {

View File

@ -51,10 +51,10 @@ import net.minecraftforge.event.AddReloadListenerEvent
import net.minecraftforge.event.OnDatapackSyncEvent import net.minecraftforge.event.OnDatapackSyncEvent
import net.minecraftforge.event.RegisterCommandsEvent import net.minecraftforge.event.RegisterCommandsEvent
import net.minecraftforge.event.entity.player.ItemTooltipEvent import net.minecraftforge.event.entity.player.ItemTooltipEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.event.server.ServerStartedEvent import net.minecraftforge.event.server.ServerStartedEvent
import net.minecraftforge.eventbus.api.IEventBus import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.fml.ModList import net.minecraftforge.fml.ModList
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.DeferredRegister
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
@ -107,7 +107,6 @@ import java.io.OutputStream
import java.math.BigInteger import java.math.BigInteger
import java.util.* import java.util.*
import java.util.function.BooleanSupplier import java.util.function.BooleanSupplier
import java.util.function.Supplier
import java.util.stream.Stream import java.util.stream.Stream
import java.util.zip.Deflater import java.util.zip.Deflater
import java.util.zip.Inflater import java.util.zip.Inflater
@ -443,19 +442,19 @@ object MatterManager {
val ignoreDamageables = data["ignore_damageables"]?.asBoolean ?: false val ignoreDamageables = data["ignore_damageables"]?.asBoolean ?: false
val allowBacktrack = data["allow_backtrack"]?.asBoolean ?: true val allowBacktrack = data["allow_backtrack"]?.asBoolean ?: true
var stream = server.recipeManager.byType(findRecipeType).values.stream().filter { !it.isIncomplete } var stream = server.recipeManager.byType(findRecipeType).values.stream().filter { !it.value.isIncomplete }
if (ignoreDamageables) { if (ignoreDamageables) {
stream = stream.filter { it.ingredients.stream().flatMap { it.items.stream() }.noneMatch { it.isDamageableItem } } stream = stream.filter { it.value.ingredients.stream().flatMap { it.items.stream() }.noneMatch { it.isDamageableItem } }
} }
stream.filter { it.getResultItem(server.registryAccess()).isNotEmpty }.map { stream.filter { it.value.getResultItem(server.registryAccess()).isNotEmpty }.map {
try { try {
ResolvedRecipe( ResolvedRecipe(
it.ingredients.stream() it.value.ingredients.stream()
.filter { !it.isActuallyEmpty } .filter { !it.isActuallyEmpty }
.map { it.items.stream().filter { it.isNotEmpty }.map(::RecipeEntry) }, .map { it.items.stream().filter { it.isNotEmpty }.map(::RecipeEntry) },
ImmutableStack(it.getResultItem(server.registryAccess())), ImmutableStack(it.value.getResultItem(server.registryAccess())),
isCritical = isCritical, isCritical = isCritical,
name = it.id, name = it.id,
allowBacktrack = allowBacktrack allowBacktrack = allowBacktrack
@ -489,16 +488,16 @@ object MatterManager {
val allowBacktrack = data["allow_backtrack"]?.asBoolean ?: true val allowBacktrack = data["allow_backtrack"]?.asBoolean ?: true
val ignoreDamageables = data["ignore_damageables"]?.asBoolean ?: false val ignoreDamageables = data["ignore_damageables"]?.asBoolean ?: false
val isCritical = data["is_critical"]?.asBoolean ?: true val isCritical = data["is_critical"]?.asBoolean ?: true
var stream = server.recipeManager.byType(findRecipeType).values.stream().filter { !it.isIncomplete } var stream = server.recipeManager.byType(findRecipeType).values.stream().filter { !it.value.isIncomplete }
if (ignoreDamageables) { if (ignoreDamageables) {
stream = stream.filter { it.ingredients.stream().flatMap { it.items.stream() }.noneMatch { it.isDamageableItem } } stream = stream.filter { it.value.ingredients.stream().flatMap { it.items.stream() }.noneMatch { it.isDamageableItem } }
} }
stream.map { stream.map {
try { try {
// avoid reality snap when recipe has no output // avoid reality snap when recipe has no output
val resultItem = it.getResultItem(server.registryAccess()) val resultItem = it.value.getResultItem(server.registryAccess())
if (resultItem.isEmpty) { if (resultItem.isEmpty) {
null null
@ -506,17 +505,17 @@ object MatterManager {
var width: Int var width: Int
var height: Int var height: Int
if (it is IShapedRecipe<*>) { if (it.value is IShapedRecipe<*>) {
width = it.recipeWidth width = (it.value as IShapedRecipe<*>).recipeWidth
height = it.recipeHeight height = (it.value as IShapedRecipe<*>).recipeHeight
} else { } else {
width = 3 width = 3
height = 3 height = 3
} }
if (width * height < it.ingredients.size) { if (width * height < it.value.ingredients.size) {
width = it.ingredients.size.coerceAtLeast(width) width = it.value.ingredients.size.coerceAtLeast(width)
height = it.ingredients.size.coerceAtLeast(height) height = it.value.ingredients.size.coerceAtLeast(height)
} }
val container = TransientCraftingContainer(object : AbstractContainerMenu(null, 0) { val container = TransientCraftingContainer(object : AbstractContainerMenu(null, 0) {
@ -531,12 +530,12 @@ object MatterManager {
val realIngredients = ArrayList<ArrayList<RecipeEntry>>() val realIngredients = ArrayList<ArrayList<RecipeEntry>>()
for (c in it.ingredients.indices) { for (c in it.value.ingredients.indices) {
if (it.ingredients[c].isActuallyEmpty) { if (it.value.ingredients[c].isActuallyEmpty) {
continue continue
} }
for ((i, ingredient) in it.ingredients.withIndex()) { for ((i, ingredient) in it.value.ingredients.withIndex()) {
if (i != c) { if (i != c) {
container[i] = if (ingredient.isActuallyEmpty) ItemStack.EMPTY else ingredient.items.firstOrNull() ?: ItemStack.EMPTY container[i] = if (ingredient.isActuallyEmpty) ItemStack.EMPTY else ingredient.items.firstOrNull() ?: ItemStack.EMPTY
} }
@ -544,11 +543,11 @@ object MatterManager {
val result = ArrayList<RecipeEntry>() val result = ArrayList<RecipeEntry>()
for (item in it.ingredients[c].items) { for (item in it.value.ingredients[c].items) {
container[c] = item container[c] = item
if (!it.assemble(container, server.registryAccess()).isEmpty) { if (!it.value.assemble(container, server.registryAccess()).isEmpty) {
val residue = it.getRemainingItems(container) val residue = it.value.getRemainingItems(container)
val thisResidue = residue[c] val thisResidue = residue[c]
@ -1640,7 +1639,7 @@ object MatterManager {
if (event.player == null) { if (event.player == null) {
syncRegistry(PacketDistributor.ALL.noArg()) syncRegistry(PacketDistributor.ALL.noArg())
} else { } else {
syncRegistry(PacketDistributor.PLAYER.with { event.player ?: throw ConcurrentModificationException() }) syncRegistry(PacketDistributor.PLAYER.with(event.player!!))
} }
} }
@ -1826,7 +1825,7 @@ object MatterManager {
buff.writeBytes(payload, 0, length) buff.writeBytes(payload, 0, length)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
if (SERVER_IS_LIVE) if (SERVER_IS_LIVE)
return // singleplayer or LAN host return // singleplayer or LAN host

View File

@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableList
import com.mojang.datafixers.util.Pair import com.mojang.datafixers.util.Pair
import it.unimi.dsi.fastutil.ints.IntArrayList import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntCollection
import it.unimi.dsi.fastutil.ints.IntList
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
@ -25,7 +24,7 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasBindingCurse import net.minecraft.world.item.enchantment.EnchantmentHelper.hasBindingCurse
import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
@ -40,7 +39,6 @@ import ru.dbotthepony.mc.otm.container.IMatteryContainer
import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.computeSortedIndices import ru.dbotthepony.mc.otm.container.computeSortedIndices
import ru.dbotthepony.mc.otm.container.sort
import ru.dbotthepony.mc.otm.container.sortWithIndices import ru.dbotthepony.mc.otm.container.sortWithIndices
import ru.dbotthepony.mc.otm.core.GetterSetter import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
@ -62,9 +60,6 @@ import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MenuFieldPacket import ru.dbotthepony.mc.otm.network.MenuFieldPacket
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
import ru.dbotthepony.mc.otm.network.SetCarriedPacket import ru.dbotthepony.mc.otm.network.SetCarriedPacket
import ru.dbotthepony.mc.otm.network.enqueueWork
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
import ru.dbotthepony.mc.otm.network.synchronizer.IField import ru.dbotthepony.mc.otm.network.synchronizer.IField
import ru.dbotthepony.mc.otm.network.synchronizer.IMutableBooleanField import ru.dbotthepony.mc.otm.network.synchronizer.IMutableBooleanField
@ -77,8 +72,6 @@ import java.util.function.Consumer
import java.util.function.DoubleSupplier import java.util.function.DoubleSupplier
import java.util.function.IntSupplier import java.util.function.IntSupplier
import java.util.function.Predicate import java.util.function.Predicate
import java.util.function.Supplier
import kotlin.collections.ArrayList
data class PlayerSlot<A : Slot, B : Slot>(val functional: A, val cosmetic: B? = null) data class PlayerSlot<A : Slot, B : Slot>(val functional: A, val cosmetic: B? = null)
@ -126,16 +119,12 @@ abstract class MatteryMenu(
buff.writeBytes(payload) buff.writeBytes(payload)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val menu = context.sender?.containerMenu as? MatteryMenu ?: return
if (menu.containerId != containerId || !menu.stillValid(context.sender!!)) return
context.enqueueWork { val input = menu.playerInputs.getOrNull(inputId) ?: return
val menu = context.sender?.containerMenu as? MatteryMenu ?: return@enqueueWork if (!input.test(context.sender)) return
if (menu.containerId != containerId || !menu.stillValid(context.sender!!)) return@enqueueWork input.invoke(input.codec.read(DataInputStream(FastByteArrayInputStream(payload))))
val input = menu.playerInputs.getOrNull(inputId) ?: return@enqueueWork
if (!input.test(context.sender)) return@enqueueWork
input.invoke(input.codec.read(DataInputStream(FastByteArrayInputStream(payload))))
}
} }
} }
@ -239,8 +228,6 @@ abstract class MatteryMenu(
protected var inventorySlotIndexStart = 0 protected var inventorySlotIndexStart = 0
protected var inventorySlotIndexEnd = 0 protected var inventorySlotIndexEnd = 0
private val playerPacketDistributor = PacketDistributor.PLAYER.with { player as ServerPlayer }
fun addFilterSlots(slots: ItemFilter): List<GetterSetter<ItemStack>> { fun addFilterSlots(slots: ItemFilter): List<GetterSetter<ItemStack>> {
val result = ArrayList<GetterSetter<ItemStack>>(slots.size) val result = ArrayList<GetterSetter<ItemStack>>(slots.size)

View File

@ -11,7 +11,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.ClickAction import net.minecraft.world.inventory.ClickAction
import net.minecraft.world.inventory.ClickType import net.minecraft.world.inventory.ClickType
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.addSorted import ru.dbotthepony.mc.otm.core.addSorted
@ -42,15 +42,12 @@ data class ItemViewInteractPacket(val stackID: Int, val type: ClickType, val act
buff.writeEnum(action) buff.writeEnum(action)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val sender = context.sender ?: return
context.enqueueWork {
val sender = context.sender ?: return@enqueueWork
if (!sender.isSpectator) { if (!sender.isSpectator) {
sender.resetLastActionTime() sender.resetLastActionTime()
(sender.containerMenu as? INetworkedItemViewProvider)?.networkedItemView?.playerInteract(this) (sender.containerMenu as? INetworkedItemViewProvider)?.networkedItemView?.playerInteract(this)
}
} }
} }
@ -62,13 +59,10 @@ data class ItemViewInteractPacket(val stackID: Int, val type: ClickType, val act
} }
abstract class NetworkedItemViewPacket : MatteryPacket { abstract class NetworkedItemViewPacket : MatteryPacket {
final override fun play(context: Supplier<NetworkEvent.Context>) { final override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val get = Minecraft.getInstance().player?.containerMenu ?: return
context.enqueueWork { val view = (get as? INetworkedItemViewProvider)?.networkedItemView ?: throw IllegalStateException("No NetworkedItemView is present in currently open menu")
val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork action(view)
val view = (get as? INetworkedItemViewProvider)?.networkedItemView ?: throw IllegalStateException("No NetworkedItemView is present in currently open menu")
action(view)
}
} }
protected abstract fun action(view: NetworkedItemView) protected abstract fun action(view: NetworkedItemView)
@ -249,7 +243,7 @@ class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val isRemote: Bo
fun network() { fun network() {
check(!isRemote) { "Not a server" } check(!isRemote) { "Not a server" }
val consumer = PacketDistributor.PLAYER.with { ply as ServerPlayer } val consumer = PacketDistributor.PLAYER.with(ply as ServerPlayer)
for (packet in networkBacklog) { for (packet in networkBacklog) {
MenuNetworkChannel.send(consumer, packet) MenuNetworkChannel.send(consumer, packet)

View File

@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.RecipeHolder
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
@ -42,7 +43,7 @@ class PainterMenu(
val inputContainer = MatteryContainer(::rescan, 1) val inputContainer = MatteryContainer(::rescan, 1)
val outputContainer = MatteryContainer(1) val outputContainer = MatteryContainer(1)
private var lastRecipe: PainterRecipe? = null private var lastRecipe: RecipeHolder<PainterRecipe>? = null
var selectedRecipe by mSynchronizer.Field(null, ResourceLocationValueCodec.nullable).also { it.addListener { rescan() } } var selectedRecipe by mSynchronizer.Field(null, ResourceLocationValueCodec.nullable).also { it.addListener { rescan() } }
val isBulk = BooleanInputWithFeedback(this, tile?.let { it::isBulk }) val isBulk = BooleanInputWithFeedback(this, tile?.let { it::isBulk })
@ -53,7 +54,7 @@ class PainterMenu(
val inputSlot = object : MatterySlot(inputContainer, 0) { val inputSlot = object : MatterySlot(inputContainer, 0) {
override fun mayPlace(itemStack: ItemStack): Boolean { override fun mayPlace(itemStack: ItemStack): Boolean {
return super.mayPlace(itemStack) && inventory.player.level().recipeManager.byType(MRecipes.PAINTER).values.any { it.input.test(itemStack) } return super.mayPlace(itemStack) && inventory.player.level().recipeManager.byType(MRecipes.PAINTER).values.any { it.value.input.test(itemStack) }
} }
} }
@ -65,7 +66,7 @@ class PainterMenu(
override fun onTake(player: Player, itemStack: ItemStack) { override fun onTake(player: Player, itemStack: ItemStack) {
if (itemStack.isNotEmpty) { if (itemStack.isNotEmpty) {
lastRecipe?.dyes?.let { tile?.takeDyes(it) } lastRecipe?.value?.dyes?.let { tile?.takeDyes(it) }
if (isBulk.value) { if (isBulk.value) {
val found = player.matteryPlayer!!.inventoryAndExopack val found = player.matteryPlayer!!.inventoryAndExopack
@ -116,11 +117,11 @@ class PainterMenu(
} }
val listeners = ISubscriptable.Impl<Unit>() val listeners = ISubscriptable.Impl<Unit>()
val possibleRecipes = ArrayList<PainterRecipe>() val possibleRecipes = ArrayList<RecipeHolder<PainterRecipe>>()
private fun rescan() { private fun rescan() {
possibleRecipes.clear() possibleRecipes.clear()
possibleRecipes.addAll(inventory.player.level().recipeManager.byType(MRecipes.PAINTER).values.iterator().filter { it.input.test(inputContainer[0]) }) possibleRecipes.addAll(inventory.player.level().recipeManager.byType(MRecipes.PAINTER).values.iterator().filter { it.value.input.test(inputContainer[0]) })
listeners.accept(Unit) listeners.accept(Unit)
if (tile !is PainterBlockEntity) return if (tile !is PainterBlockEntity) return
@ -129,10 +130,10 @@ class PainterMenu(
} else { } else {
val recipe = inventory.player.level().recipeManager.byType(MRecipes.PAINTER)[selectedRecipe] val recipe = inventory.player.level().recipeManager.byType(MRecipes.PAINTER)[selectedRecipe]
if (recipe == null || !recipe.canCraft(dyeStoredDirect) || !recipe.matches(inputContainer, inventory.player.level())) { if (recipe == null || !recipe.value.canCraft(dyeStoredDirect) || !recipe.value.matches(inputContainer, inventory.player.level())) {
outputContainer.clearContent() outputContainer.clearContent()
} else { } else {
outputContainer[0] = recipe.assemble(inputContainer, inventory.player.level().registryAccess()) outputContainer[0] = recipe.value.assemble(inputContainer, inventory.player.level().registryAccess())
lastRecipe = recipe lastRecipe = recipe
} }
} }

View File

@ -52,7 +52,7 @@ class MatterEntanglerMenu(
.recipeManager .recipeManager
.byType(MRecipes.MATTER_ENTANGLER) .byType(MRecipes.MATTER_ENTANGLER)
.values .values
.any { it.preemptivelyMatches(shadow, level) } .any { it.value.preemptivelyMatches(shadow, level) }
} }
} }
} }

View File

@ -5,20 +5,17 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.block.entity.matter.MatterPanelBlockEntity import ru.dbotthepony.mc.otm.block.entity.matter.MatterPanelBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.addSorted import ru.dbotthepony.mc.otm.core.addSorted
import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.core.map
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec
import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.core.util.NullValueCodec import ru.dbotthepony.mc.otm.core.util.NullValueCodec
import ru.dbotthepony.mc.otm.core.util.codec
import ru.dbotthepony.mc.otm.core.util.writeCollection import ru.dbotthepony.mc.otm.core.util.writeCollection
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
@ -30,19 +27,15 @@ import ru.dbotthepony.mc.otm.registry.MMenus
import java.util.* import java.util.*
import java.util.function.Predicate import java.util.function.Predicate
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.collections.ArrayList
class CancelTaskPacket(val id: UUID) : MatteryPacket { class CancelTaskPacket(val id: UUID) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
buff.writeUUID(id) buff.writeUUID(id)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val sender = context.sender!!
context.enqueueWork { (sender.containerMenu as? MatterPanelMenu)?.receiveTaskCancel(sender, id)
val sender = context.sender!!
(sender.containerMenu as? MatterPanelMenu)?.receiveTaskCancel(sender, id)
}
} }
companion object { companion object {
@ -58,16 +51,13 @@ class PatternsChangePacket(val isUpdate: Boolean, val patterns: Collection<Patte
buff.writeCollection(patterns, PatternState::write) buff.writeCollection(patterns, PatternState::write)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return
context.enqueueWork {
val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return@enqueueWork
if (isUpdate) { if (isUpdate) {
menu.networkPatternsUpdated(patterns) menu.networkPatternsUpdated(patterns)
} else { } else {
menu.networkPatternsRemoved(patterns) menu.networkPatternsRemoved(patterns)
}
} }
} }
@ -84,16 +74,13 @@ class TasksChangePacket(val isUpdate: Boolean, val tasks: Collection<Replication
buff.writeCollection(tasks, ReplicationTask::write) buff.writeCollection(tasks, ReplicationTask::write)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return
context.enqueueWork {
val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return@enqueueWork
if (isUpdate) { if (isUpdate) {
menu.networkTasksUpdated(tasks) menu.networkTasksUpdated(tasks)
} else { } else {
menu.networkTasksRemoved(tasks) menu.networkTasksRemoved(tasks)
}
} }
} }
@ -112,14 +99,11 @@ class ReplicationRequestPacket(val id: UUID, amount: Int) : MatteryPacket {
buff.writeInt(amount) buff.writeInt(amount)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val sender = context.sender ?: return
context.enqueueWork { val menu = sender.containerMenu as? MatterPanelMenu ?: return
val sender = context.sender ?: return@enqueueWork
val menu = sender.containerMenu as? MatterPanelMenu ?: return@enqueueWork
menu.requestReplication(sender, id, amount) menu.requestReplication(sender, id, amount)
}
} }
companion object { companion object {
@ -339,7 +323,7 @@ class MatterPanelMenu(
} }
private fun sendNetwork(packet: Any) { private fun sendNetwork(packet: Any) {
MenuNetworkChannel.send(PacketDistributor.PLAYER.with { inventory.player as ServerPlayer }, packet) MenuNetworkChannel.send(inventory.player, packet)
} }
fun fullPatternBroadcast() { fun fullPatternBroadcast() {

View File

@ -9,8 +9,8 @@ import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.RandomSource import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.NetworkDirection import net.minecraftforge.network.NetworkDirection
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.AndroidResearchManager
@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.client.onceClient
import ru.dbotthepony.mc.otm.item.QuantumBatteryItem import ru.dbotthepony.mc.otm.item.QuantumBatteryItem
import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.matter.MatterManager
import java.util.* import java.util.*
import java.util.function.Supplier
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : MatteryPacket { class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : MatteryPacket {
@ -31,12 +30,9 @@ class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : Matter
buff.writeDouble(z) buff.writeDouble(z)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true minecraft.player?.level()?.let {
context.enqueueWork { makeSmoke(x, y, z, it.random, it)
minecraft.player?.level()?.let {
makeSmoke(x, y, z, it.random, it)
}
} }
} }
@ -104,12 +100,8 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
} }
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true execute()
context.enqueueWork {
execute()
}
} }
companion object { companion object {
@ -128,15 +120,15 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
} }
object GenericNetworkChannel : MatteryNetworkChannel( object GenericNetworkChannel : MatteryNetworkChannel(
version = "4", version = 5,
name = "generic" name = "generic"
) { ) {
fun makeSmoke(x: Double, y: Double, z: Double, level: Level) { fun makeSmoke(x: Double, y: Double, z: Double, level: Level) {
send(PacketDistributor.NEAR.with { PacketDistributor.TargetPoint(x, y, z, 64.0, level.dimension()) }, SmokeParticlesPacket(x, y, z)) send(PacketDistributor.NEAR.with(PacketDistributor.TargetPoint(x, y, z, 64.0, level.dimension())), SmokeParticlesPacket(x, y, z))
} }
fun makeSmoke(excluded: ServerPlayer, x: Double, y: Double, z: Double) { fun makeSmoke(excluded: ServerPlayer, x: Double, y: Double, z: Double) {
send(PacketDistributor.NEAR.with { PacketDistributor.TargetPoint(excluded, x, y, z, 64.0, excluded.level().dimension()) }, SmokeParticlesPacket(x, y, z)) send(PacketDistributor.NEAR.with(PacketDistributor.TargetPoint(excluded, x, y, z, 64.0, excluded.level().dimension())), SmokeParticlesPacket(x, y, z))
} }
fun register() { fun register() {
@ -145,7 +137,7 @@ object GenericNetworkChannel : MatteryNetworkChannel(
add(BlockEntitySyncPacket::class.java, BlockEntitySyncPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) add(BlockEntitySyncPacket::class.java, BlockEntitySyncPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
add(ItemEntityDataPacket::class.java, ItemEntityDataPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) add(ItemEntityDataPacket::class.java, ItemEntityDataPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
add(AndroidResearchManager.SyncPacket::class.java, AndroidResearchManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT) add(AndroidResearchManager.SyncPacket::class.java, AndroidResearchManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT, handleOnMainThread = false)
add(MatterManager.SyncPacket::class.java, MatterManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT) add(MatterManager.SyncPacket::class.java, MatterManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT)
add(SmokeParticlesPacket::class, SmokeParticlesPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) add(SmokeParticlesPacket::class, SmokeParticlesPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)

View File

@ -1,67 +1,48 @@
package ru.dbotthepony.mc.otm.network package ru.dbotthepony.mc.otm.network
import java.util.function.Function
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraftforge.event.TickEvent import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.event.TickEvent.ServerTickEvent import net.minecraftforge.network.Channel
import net.minecraftforge.event.server.ServerStoppedEvent import net.minecraftforge.network.ChannelBuilder
import net.minecraftforge.event.server.ServerStoppingEvent
import net.minecraftforge.network.NetworkDirection import net.minecraftforge.network.NetworkDirection
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.NetworkRegistry
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.network.simple.SimpleChannel import net.minecraftforge.network.SimpleChannel
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import java.math.BigDecimal
import java.math.BigInteger
import java.util.Optional
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.LockSupport
import java.util.function.BiConsumer import java.util.function.BiConsumer
import java.util.function.Supplier import java.util.function.Function
import kotlin.reflect.KClass import kotlin.reflect.KClass
fun Supplier<NetworkEvent.Context>.enqueueWork(lambda: Runnable): CompletableFuture<Void> = get().enqueueWork(lambda)
fun Supplier<NetworkEvent.Context>.enqueueWork(lambda: () -> Unit): CompletableFuture<Void> = get().enqueueWork(lambda)
var Supplier<NetworkEvent.Context>.packetHandled: Boolean
get() = get().packetHandled
set(value) { get().packetHandled = value }
val Supplier<NetworkEvent.Context>.sender: ServerPlayer?
get() = get().sender
interface MatteryPacket { interface MatteryPacket {
fun write(buff: FriendlyByteBuf) fun write(buff: FriendlyByteBuf)
fun play(context: Supplier<NetworkEvent.Context>) fun play(context: CustomPayloadEvent.Context)
} }
abstract class MatteryNetworkChannel(val version: String, val name: String) { abstract class MatteryNetworkChannel(val version: Int, val name: String) {
val channel: SimpleChannel = NetworkRegistry.newSimpleChannel( val channel: SimpleChannel = ChannelBuilder
ResourceLocation(OverdriveThatMatters.MOD_ID, name), .named(ResourceLocation(OverdriveThatMatters.MOD_ID, name))
{ version }, .acceptedVersions(Channel.VersionTest.exact(version))
{ it == version }, .networkProtocolVersion(version)
{ it == version }, .simpleChannel()
)
fun sendToServer(packet: Any) = channel.sendToServer(packet) fun sendToServer(packet: Any) = channel.send(packet, PacketDistributor.SERVER.noArg())
fun send(ply: Player, packet: Any) { fun send(ply: Player, packet: Any) {
if (ply is ServerPlayer) { if (ply is ServerPlayer) {
queue.add(Task(channel, PacketDistributor.PLAYER.with { ply }, packet)) queue.add(Task(channel, PacketDistributor.PLAYER.with(ply), packet))
} }
} }
fun sendNow(ply: Player, packet: Any) { fun sendNow(ply: Player, packet: Any) {
if (ply is ServerPlayer) { if (ply is ServerPlayer) {
channel.send(PacketDistributor.PLAYER.with { ply }, packet) channel.send(packet, PacketDistributor.PLAYER.with(ply))
} }
} }
@ -70,7 +51,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
return return
} }
queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY.with { entity }, packet)) queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY.with(entity), packet))
} }
fun sendTrackingAndSelf(entity: Entity, packet: Any) { fun sendTrackingAndSelf(entity: Entity, packet: Any) {
@ -78,7 +59,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
return return
} }
queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY_AND_SELF.with { entity }, packet)) queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY_AND_SELF.with(entity), packet))
} }
fun send(distributor: PacketDistributor.PacketTarget, packet: Any) { fun send(distributor: PacketDistributor.PacketTarget, packet: Any) {
@ -86,7 +67,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
} }
fun sendNow(distributor: PacketDistributor.PacketTarget, packet: Any) { fun sendNow(distributor: PacketDistributor.PacketTarget, packet: Any) {
channel.send(distributor, packet) channel.send(packet, distributor)
} }
private var nextNetworkPacketID = 0 private var nextNetworkPacketID = 0
@ -95,31 +76,43 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
packetClass: Class<T>, packetClass: Class<T>,
writer: BiConsumer<T, FriendlyByteBuf>, writer: BiConsumer<T, FriendlyByteBuf>,
reader: Function<FriendlyByteBuf, T>, reader: Function<FriendlyByteBuf, T>,
handler: BiConsumer<T, Supplier<NetworkEvent.Context>>, handler: BiConsumer<T, CustomPayloadEvent.Context>,
direction: NetworkDirection? = null direction: NetworkDirection? = null,
handleOnMainThread: Boolean = true,
) { ) {
if (nextNetworkPacketID >= 256) { if (nextNetworkPacketID >= 256) {
throw IndexOutOfBoundsException("Network message ID overflow!") throw IndexOutOfBoundsException("Network message ID overflow!")
} }
@Suppress("INACCESSIBLE_TYPE") val builder = channel.messageBuilder(packetClass, direction)
channel.registerMessage(nextNetworkPacketID++, packetClass, writer, reader, handler, if (direction == null) Optional.empty() else Optional.of(direction))
if (handleOnMainThread) {
builder.consumerMainThread(handler)
} else {
builder.consumerNetworkThread(handler)
}
builder.encoder(writer)
builder.decoder(reader)
builder.add()
} }
fun <T : MatteryPacket> add( fun <T : MatteryPacket> add(
packetClass: Class<T>, packetClass: Class<T>,
reader: Function<FriendlyByteBuf, T>, reader: Function<FriendlyByteBuf, T>,
direction: NetworkDirection? = null direction: NetworkDirection? = null,
handleOnMainThread: Boolean = true,
) { ) {
add(packetClass, MatteryPacket::write, reader, MatteryPacket::play, direction) add(packetClass, MatteryPacket::write, reader, MatteryPacket::play, direction, handleOnMainThread)
} }
fun <T : MatteryPacket> add( fun <T : MatteryPacket> add(
packetClass: KClass<T>, packetClass: KClass<T>,
reader: Function<FriendlyByteBuf, T>, reader: Function<FriendlyByteBuf, T>,
direction: NetworkDirection? = null direction: NetworkDirection? = null,
handleOnMainThread: Boolean = true,
) { ) {
add(packetClass.java, MatteryPacket::write, reader, MatteryPacket::play, direction) add(packetClass.java, MatteryPacket::write, reader, MatteryPacket::play, direction, handleOnMainThread)
} }
private data class Task(val channel: SimpleChannel, val target: PacketDistributor.PacketTarget, val packet: Any) private data class Task(val channel: SimpleChannel, val target: PacketDistributor.PacketTarget, val packet: Any)
@ -150,7 +143,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
LockSupport.park() LockSupport.park()
} else { } else {
try { try {
task.channel.send(task.target, task.packet) task.channel.send(task.packet, task.target)
} catch(err: Throwable) { } catch(err: Throwable) {
logger.error("Error executing network dispatcher task", err) logger.error("Error executing network dispatcher task", err)
} }

View File

@ -8,9 +8,9 @@ import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT import net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT
import net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER import net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER
import net.minecraftforge.network.NetworkEvent
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.android.AndroidActiveFeature import ru.dbotthepony.mc.otm.android.AndroidActiveFeature
import ru.dbotthepony.mc.otm.android.AndroidFeatureType import ru.dbotthepony.mc.otm.android.AndroidFeatureType
@ -40,7 +40,6 @@ import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.util.UUID import java.util.UUID
import java.util.function.Supplier
class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int, val isPublic: Boolean, val target: UUID? = null) : MatteryPacket { class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int, val isPublic: Boolean, val target: UUID? = null) : MatteryPacket {
constructor(stream: FastByteArrayOutputStream, isPublic: Boolean, target: UUID? = null) : this(stream.array, stream.length, isPublic, target) constructor(stream: FastByteArrayOutputStream, isPublic: Boolean, target: UUID? = null) : this(stream.array, stream.length, isPublic, target)
@ -55,22 +54,19 @@ class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int, val isPubl
buff.writeBytes(bytes, 0, length) buff.writeBytes(bytes, 0, length)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val player: MatteryPlayerCapability
context.get().enqueueWork {
val player: MatteryPlayerCapability
if (target != null) { if (target != null) {
player = minecraft.level?.players()?.firstOrNull { it.uuid == target }?.matteryPlayer ?: return@enqueueWork player = minecraft.level?.players()?.firstOrNull { it.uuid == target }?.matteryPlayer ?: return
} else { } else {
player = minecraft.player?.matteryPlayer ?: return@enqueueWork player = minecraft.player?.matteryPlayer ?: return
} }
if (isPublic) { if (isPublic) {
player.publicSynchronizer.read(ByteArrayInputStream(bytes, 0, length)) player.publicSynchronizer.read(ByteArrayInputStream(bytes, 0, length))
} else { } else {
player.synchronizer.read(ByteArrayInputStream(bytes, 0, length)) player.synchronizer.read(ByteArrayInputStream(bytes, 0, length))
}
} }
} }
@ -93,18 +89,15 @@ class AndroidResearchRequestPacket(val type: AndroidResearchType) : MatteryPacke
buff.writeUtf(type.id.toString()) buff.writeUtf(type.id.toString())
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val ply = context.sender ?: return
context.enqueueWork { if (ply.isSpectator) return
val ply = context.get().sender ?: return@enqueueWork val android = ply.matteryPlayer ?: return
if (ply.isSpectator) return@enqueueWork
val android = ply.matteryPlayer ?: return@enqueueWork
if (!android.isAndroid || ply.containerMenu !is AndroidStationMenu) if (!android.isAndroid || ply.containerMenu !is AndroidStationMenu)
return@enqueueWork return
android.getResearch(type).research() android.getResearch(type).research()
}
} }
companion object { companion object {
@ -121,15 +114,10 @@ class AndroidResearchSyncPacket(val type: AndroidResearchType, val dataList: Fas
buff.writeBytes(dataList.array, 0, dataList.length) buff.writeBytes(dataList.array, 0, dataList.length)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
dataBytes ?: throw NullPointerException("No data bytes array is present") dataBytes ?: throw NullPointerException("No data bytes array is present")
val android = minecraft.player?.matteryPlayer ?: return
context.get().packetHandled = true android.getResearch(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
android.getResearch(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
}
} }
companion object { companion object {
@ -149,15 +137,10 @@ class AndroidFeatureSyncPacket(val type: AndroidFeatureType<*>, val dataList: Fa
buff.writeBytes(dataList.array, 0, dataList.length) buff.writeBytes(dataList.array, 0, dataList.length)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
dataBytes ?: throw NullPointerException("No data bytes array is present") dataBytes ?: throw NullPointerException("No data bytes array is present")
val android = minecraft.player?.matteryPlayer ?: return
context.get().packetHandled = true android.computeIfAbsent(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
android.computeIfAbsent(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
}
} }
companion object { companion object {
@ -175,13 +158,9 @@ class AndroidFeatureRemovePacket(val type: AndroidFeatureType<*>) : MatteryPacke
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type)) buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.get().packetHandled = true val android = minecraft.player?.matteryPlayer ?: return
context.get().enqueueWork { android.removeFeature(type)
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
android.removeFeature(type)
}
} }
companion object { companion object {
@ -202,7 +181,7 @@ class PlayerIterationPacket(val iteration: Int, val deathLog: List<Pair<Int, Com
} }
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
MatteryGUI.iteration = iteration MatteryGUI.iteration = iteration
@ -234,15 +213,12 @@ class ExopackCarriedPacket(val itemStack: ItemStack, val containerState: Int) :
buff.writeInt(containerState) buff.writeInt(containerState)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val mattery = minecraft.player?.matteryPlayer ?: return
context.enqueueWork {
val mattery = minecraft.player?.matteryPlayer ?: return@enqueueWork
if (mattery.hasExopack) { if (mattery.hasExopack) {
mattery.exoPackMenu.carried = itemStack mattery.exoPackMenu.carried = itemStack
mattery.exoPackMenu.stateId = containerState mattery.exoPackMenu.stateId = containerState
}
} }
} }
@ -260,31 +236,27 @@ class ExopackSlotPacket(val slotId: Int, val itemStack: ItemStack, val container
buff.writeInt(containerState) buff.writeInt(containerState)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
if (slotId < 0) { if (slotId < 0) {
LOGGER.error("Unknown slot with ID {} in exosuit menu", slotId) LOGGER.error("Unknown slot with ID {} in exosuit menu", slotId)
return return
} }
context.enqueueWork { val mattery = minecraft.player?.matteryPlayer ?: return
val mattery = minecraft.player?.matteryPlayer ?: return@enqueueWork
if (mattery.hasExopack) { if (mattery.hasExopack) {
if (slotId >= mattery.exoPackMenu.slots.size) { if (slotId >= mattery.exoPackMenu.slots.size) {
LOGGER.error("Unknown slot with ID {} in exosuit menu", slotId) LOGGER.error("Unknown slot with ID {} in exosuit menu", slotId)
return@enqueueWork return
}
// don't duplicate data
// really.
if (mattery.exoPackMenu.slots[slotId].container == minecraft.player?.inventory && minecraft.player?.containerMenu !is ExopackInventoryMenu)
return@enqueueWork
mattery.exoPackMenu.slots[slotId].set(itemStack)
mattery.exoPackMenu.stateId = containerState
} }
// don't duplicate data
// really.
if (mattery.exoPackMenu.slots[slotId].container == minecraft.player?.inventory && minecraft.player?.containerMenu !is ExopackInventoryMenu)
return
mattery.exoPackMenu.slots[slotId].set(itemStack)
mattery.exoPackMenu.stateId = containerState
} }
} }
@ -309,14 +281,11 @@ class ExopackMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack,
buff.writeInt(containerState) buff.writeInt(containerState)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val mattery = minecraft.player?.matteryPlayer ?: return
context.enqueueWork {
val mattery = minecraft.player?.matteryPlayer ?: return@enqueueWork
if (mattery.hasExopack) { if (mattery.hasExopack) {
mattery.exoPackMenu.initializeContents(containerState, slots, carried) mattery.exoPackMenu.initializeContents(containerState, slots, carried)
}
} }
} }
@ -340,15 +309,12 @@ class ExopackMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack,
object ExopackMenuOpen : MatteryPacket { object ExopackMenuOpen : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {} override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val player = context.sender ?: return
context.enqueueWork { val mattery = player.matteryPlayer ?: return
val player = context.sender ?: return@enqueueWork
val mattery = player.matteryPlayer ?: return@enqueueWork
if (mattery.hasExopack) { if (mattery.hasExopack) {
player.containerMenu = mattery.exoPackMenu player.containerMenu = mattery.exoPackMenu
}
} }
} }
} }
@ -359,28 +325,24 @@ class SwitchAndroidFeaturePacket(val type: AndroidFeatureType<*>, val newState:
buff.writeBoolean(newState) buff.writeBoolean(newState)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val matteryPlayer = context.sender?.matteryPlayer ?: return
context.enqueueWork { if (!matteryPlayer.isAndroid) {
val matteryPlayer = context.sender?.matteryPlayer ?: return@enqueueWork return
}
if (!matteryPlayer.isAndroid) { val feature = matteryPlayer.getFeature(type) ?: return
return@enqueueWork
}
val feature = matteryPlayer.getFeature(type) ?: return@enqueueWork if (feature is AndroidActiveFeature && feature.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || feature.allowToSwitchByPlayerWhileSpectator)) {
matteryPlayer.features
if (feature is AndroidActiveFeature && feature.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || feature.allowToSwitchByPlayerWhileSpectator)) { .map { it as? AndroidActiveFeature }
matteryPlayer.features .filter { it != null }
.map { it as? AndroidActiveFeature } .filter { it !== feature && it!!.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || it.allowToSwitchByPlayerWhileSpectator) }
.filter { it != null } .forEach { it!!.isActive = false }
.filter { it !== feature && it!!.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || it.allowToSwitchByPlayerWhileSpectator) } feature.isActive = newState
.forEach { it!!.isActive = false } } else if (feature is AndroidSwitchableFeature && feature.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || feature.allowToSwitchByPlayerWhileSpectator)) {
feature.isActive = newState feature.isActive = newState
} else if (feature is AndroidSwitchableFeature && feature.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || feature.allowToSwitchByPlayerWhileSpectator)) {
feature.isActive = newState
}
} }
} }
@ -396,21 +358,17 @@ class ActivateAndroidFeaturePacket(val type: AndroidFeatureType<*>) : MatteryPac
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type)) buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val matteryPlayer = context.sender?.matteryPlayer ?: return
context.enqueueWork { if (!matteryPlayer.isAndroid || matteryPlayer.ply.isSpectator) {
val matteryPlayer = context.sender?.matteryPlayer ?: return@enqueueWork return
}
if (!matteryPlayer.isAndroid || matteryPlayer.ply.isSpectator) { val feature = matteryPlayer.getFeature(type) as? AndroidActiveFeature ?: return
return@enqueueWork
}
val feature = matteryPlayer.getFeature(type) as? AndroidActiveFeature ?: return@enqueueWork if (feature.isActive || feature.allowToSwitchByPlayer) {
feature.activate(false)
if (feature.isActive || feature.allowToSwitchByPlayer) {
feature.activate(false)
}
} }
} }
@ -430,30 +388,26 @@ class PickItemFromInventoryPacket(
buff.writeVarInt(sourceExosuitSlot) buff.writeVarInt(sourceExosuitSlot)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true val player = context.sender ?: return
val mattery = player.matteryPlayer ?: return
context.enqueueWork { if (!mattery.hasExopack || sourceExosuitSlot !in 0 until mattery.exopackContainer.containerSize) {
val player = context.sender ?: return@enqueueWork return
val mattery = player.matteryPlayer ?: return@enqueueWork
if (!mattery.hasExopack || sourceExosuitSlot !in 0 until mattery.exopackContainer.containerSize) {
return@enqueueWork
}
if (!Inventory.isHotbarSlot(targetHotbarSlot)) {
return@enqueueWork
}
player.inventory.selected = targetHotbarSlot
val existingItem = player.inventory[targetHotbarSlot].copy()
val inventoryItem = mattery.exopackContainer[sourceExosuitSlot].copy()
player.inventory[targetHotbarSlot] = if (inventoryItem.isEmpty) ItemStack.EMPTY else inventoryItem
mattery.exopackContainer[sourceExosuitSlot] = if (existingItem.isEmpty) ItemStack.EMPTY else existingItem
player.connection.send(ClientboundSetCarriedItemPacket(targetHotbarSlot))
} }
if (!Inventory.isHotbarSlot(targetHotbarSlot)) {
return
}
player.inventory.selected = targetHotbarSlot
val existingItem = player.inventory[targetHotbarSlot].copy()
val inventoryItem = mattery.exopackContainer[sourceExosuitSlot].copy()
player.inventory[targetHotbarSlot] = if (inventoryItem.isEmpty) ItemStack.EMPTY else inventoryItem
mattery.exopackContainer[sourceExosuitSlot] = if (existingItem.isEmpty) ItemStack.EMPTY else existingItem
player.connection.send(ClientboundSetCarriedItemPacket(targetHotbarSlot))
} }
companion object { companion object {
@ -468,7 +422,7 @@ class GlitchPacket(val millis: Long) : MatteryPacket {
buff.writeVarLong(millis) buff.writeVarLong(millis)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
GlitchRenderer.glitchFor(millis) GlitchRenderer.glitchFor(millis)
} }
@ -487,7 +441,7 @@ class ShockwaveEffectPacket(val pos: Vector) : MatteryPacket {
buff.writeDouble(pos.z) buff.writeDouble(pos.z)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
ShockwaveRenderer.handle(this) ShockwaveRenderer.handle(this)
} }
@ -502,7 +456,7 @@ class ShockwaveEffectPacket(val pos: Vector) : MatteryPacket {
object DisplayExopackPacket : MatteryPacket { object DisplayExopackPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {} override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
context.sender?.matteryPlayer?.isExopackVisible = true context.sender?.matteryPlayer?.isExopackVisible = true
} }
@ -511,7 +465,7 @@ object DisplayExopackPacket : MatteryPacket {
object HideExopackPacket : MatteryPacket { object HideExopackPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {} override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
context.sender?.matteryPlayer?.isExopackVisible = false context.sender?.matteryPlayer?.isExopackVisible = false
} }
@ -520,7 +474,7 @@ object HideExopackPacket : MatteryPacket {
object EnableExopackGlowPacket : MatteryPacket { object EnableExopackGlowPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {} override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
context.sender?.matteryPlayer?.exopackGlows = true context.sender?.matteryPlayer?.exopackGlows = true
} }
@ -529,7 +483,7 @@ object EnableExopackGlowPacket : MatteryPacket {
object DisableExopackGlowPacket : MatteryPacket { object DisableExopackGlowPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {} override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
context.sender?.matteryPlayer?.exopackGlows = false context.sender?.matteryPlayer?.exopackGlows = false
} }
@ -538,7 +492,7 @@ object DisableExopackGlowPacket : MatteryPacket {
object ResetExopackColorPacket : MatteryPacket { object ResetExopackColorPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {} override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
context.sender?.matteryPlayer?.exopackColor = null context.sender?.matteryPlayer?.exopackColor = null
} }
@ -551,7 +505,7 @@ data class SetExopackColorPacket(val color: RGBAColor) : MatteryPacket {
buff.writeFloat(color.blue) buff.writeFloat(color.blue)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
context.sender?.matteryPlayer?.exopackColor = color context.sender?.matteryPlayer?.exopackColor = color
} }
@ -568,37 +522,34 @@ data class ExopackSmokePacket(val player: UUID) : MatteryPacket {
buff.writeUUID(player) buff.writeUUID(player)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true context.packetHandled = true
// minecraft.player?.level()?.getPlayerByUUID(player)?.matteryPlayer?.spawnExopackSmoke = true // minecraft.player?.level()?.getPlayerByUUID(player)?.matteryPlayer?.spawnExopackSmoke = true
context.enqueueWork { minecraft.player?.level()?.getPlayerByUUID(player)?.let { ply ->
minecraft.player?.level()?.getPlayerByUUID(player)?.let { ply -> if (ply != minecraft.player || minecraft.gameRenderer.mainCamera.isDetached) {
if (ply != minecraft.player || minecraft.gameRenderer.mainCamera.isDetached) { var (x, y, z) = ply.position
var (x, y, z) = ply.position
y += 1.5 y += 1.5
val deg = toRadians(ply.yBodyRot + 90f) val deg = toRadians(ply.yBodyRot + 90f)
x += kotlin.math.cos(deg) * -0.4 x += kotlin.math.cos(deg) * -0.4
z += kotlin.math.sin(deg) * -0.4 z += kotlin.math.sin(deg) * -0.4
val level = ply.level() val level = ply.level()
val random = level.random val random = level.random
for (i in 0 .. random.nextInt(2, 4)) for (i in 0 .. random.nextInt(2, 4))
level.addParticle( level.addParticle(
ParticleTypes.SMOKE, ParticleTypes.SMOKE,
x + random.nextDouble() * 0.4 - 0.2, x + random.nextDouble() * 0.4 - 0.2,
y + random.nextDouble() * 0.4 - 0.2, y + random.nextDouble() * 0.4 - 0.2,
z + random.nextDouble() * 0.4 - 0.2, z + random.nextDouble() * 0.4 - 0.2,
random.nextGaussian() * 0.02, random.nextGaussian() * 0.02,
random.nextGaussian() * 0.02, random.nextGaussian() * 0.02,
random.nextGaussian() * 0.02) random.nextGaussian() * 0.02)
}
} }
} }
} }
companion object { companion object {
@ -609,7 +560,7 @@ data class ExopackSmokePacket(val player: UUID) : MatteryPacket {
} }
object MatteryPlayerNetworkChannel : MatteryNetworkChannel( object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
version = "6", version = 7,
name = "player" name = "player"
) { ) {
fun register() { fun register() {

View File

@ -3,8 +3,8 @@ package ru.dbotthepony.mc.otm.network
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.NetworkDirection import net.minecraftforge.network.NetworkDirection
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.compat.vanilla.InventoryScrollPacket import ru.dbotthepony.mc.otm.compat.vanilla.InventoryScrollPacket
@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.menu.data.StackAddPacket
import ru.dbotthepony.mc.otm.menu.data.StackChangePacket import ru.dbotthepony.mc.otm.menu.data.StackChangePacket
import ru.dbotthepony.mc.otm.menu.data.StackRemovePacket import ru.dbotthepony.mc.otm.menu.data.StackRemovePacket
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.util.function.Supplier
class MenuFieldPacket(val containerId: Int, val bytes: ByteArray, val length: Int) : MatteryPacket { class MenuFieldPacket(val containerId: Int, val bytes: ByteArray, val length: Int) : MatteryPacket {
constructor(containerId: Int, stream: FastByteArrayOutputStream) : this(containerId, stream.array, stream.length) constructor(containerId: Int, stream: FastByteArrayOutputStream) : this(containerId, stream.array, stream.length)
@ -30,18 +29,14 @@ class MenuFieldPacket(val containerId: Int, val bytes: ByteArray, val length: In
buff.writeBytes(bytes, 0, length) buff.writeBytes(bytes, 0, length)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true if (containerId == ExopackInventoryMenu.CONTAINER_ID) {
minecraft.player?.matteryPlayer?.exoPackMenu?.mSynchronizer?.read(ByteArrayInputStream(bytes, 0, length))
} else {
val menu = minecraft.player?.containerMenu as? MatteryMenu ?: return
context.enqueueWork { if (menu.containerId == containerId)
if (containerId == ExopackInventoryMenu.CONTAINER_ID) { menu.mSynchronizer.read(ByteArrayInputStream(bytes, 0, length))
minecraft.player?.matteryPlayer?.exoPackMenu?.mSynchronizer?.read(ByteArrayInputStream(bytes, 0, length))
} else {
val menu = minecraft.player?.containerMenu as? MatteryMenu ?: return@enqueueWork
if (menu.containerId == containerId)
menu.mSynchronizer.read(ByteArrayInputStream(bytes, 0, length))
}
} }
} }
@ -59,9 +54,8 @@ class SetCarriedPacket(val item: ItemStack) : MatteryPacket {
buff.writeItem(item) buff.writeItem(item)
} }
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: CustomPayloadEvent.Context) {
context.get().packetHandled = true minecraft.player?.containerMenu?.carried = item
context.get().enqueueWork { minecraft.player?.containerMenu?.carried = item }
} }
companion object { companion object {
@ -72,7 +66,7 @@ class SetCarriedPacket(val item: ItemStack) : MatteryPacket {
} }
object MenuNetworkChannel : MatteryNetworkChannel( object MenuNetworkChannel : MatteryNetworkChannel(
version = "4", version = 5,
name = "menu" name = "menu"
) { ) {
fun register() { fun register() {

View File

@ -5,7 +5,7 @@ import ru.dbotthepony.mc.otm.item.weapon.WeaponFireInputPacket
import ru.dbotthepony.mc.otm.item.weapon.WeaponScopePacket import ru.dbotthepony.mc.otm.item.weapon.WeaponScopePacket
object WeaponNetworkChannel : MatteryNetworkChannel( object WeaponNetworkChannel : MatteryNetworkChannel(
version = "2", version = 3,
name = "weapon" name = "weapon"
) { ) {
fun register() { fun register() {

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.recipe package ru.dbotthepony.mc.otm.recipe
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.mojang.serialization.Codec
import net.minecraft.core.NonNullList import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess import net.minecraft.core.RegistryAccess
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
@ -20,6 +21,8 @@ import ru.dbotthepony.mc.otm.capability.iterator
import ru.dbotthepony.mc.otm.container.util.iterator import ru.dbotthepony.mc.otm.container.util.iterator
import ru.dbotthepony.mc.otm.container.util.stream import ru.dbotthepony.mc.otm.container.util.stream
import ru.dbotthepony.mc.otm.core.filterNotNull import ru.dbotthepony.mc.otm.core.filterNotNull
import ru.dbotthepony.mc.otm.core.fromJson
import ru.dbotthepony.mc.otm.core.fromJsonStrict
class EnergyContainerRecipe(val parent: ShapedRecipe) : CraftingRecipe, IShapedRecipe<CraftingContainer> by parent { class EnergyContainerRecipe(val parent: ShapedRecipe) : CraftingRecipe, IShapedRecipe<CraftingContainer> by parent {
override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int): Boolean { override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int): Boolean {
@ -30,10 +33,6 @@ class EnergyContainerRecipe(val parent: ShapedRecipe) : CraftingRecipe, IShapedR
return parent.getResultItem(p_267052_) return parent.getResultItem(p_267052_)
} }
override fun getId(): ResourceLocation {
return parent.id
}
override fun category(): CraftingBookCategory { override fun category(): CraftingBookCategory {
return parent.category() return parent.category()
} }
@ -105,12 +104,16 @@ class EnergyContainerRecipe(val parent: ShapedRecipe) : CraftingRecipe, IShapedR
} }
companion object : RecipeSerializer<EnergyContainerRecipe> { companion object : RecipeSerializer<EnergyContainerRecipe> {
override fun fromJson(id: ResourceLocation, data: JsonObject): EnergyContainerRecipe { private val codec by lazy {
return EnergyContainerRecipe(ShapedRecipe.Serializer.SHAPED_RECIPE.fromJson(id, data)) RecipeSerializer.SHAPED_RECIPE.codec().xmap(::EnergyContainerRecipe, EnergyContainerRecipe::parent)
} }
override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): EnergyContainerRecipe? { override fun codec(): Codec<EnergyContainerRecipe> {
return ShapedRecipe.Serializer.SHAPED_RECIPE.fromNetwork(id, data)?.let(::EnergyContainerRecipe) return codec
}
override fun fromNetwork(data: FriendlyByteBuf): EnergyContainerRecipe? {
return ShapedRecipe.Serializer.SHAPED_RECIPE.fromNetwork(data)?.let(::EnergyContainerRecipe)
} }
override fun toNetwork(buff: FriendlyByteBuf, value: EnergyContainerRecipe) { override fun toNetwork(buff: FriendlyByteBuf, value: EnergyContainerRecipe) {

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.recipe
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException import com.google.gson.JsonSyntaxException
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.NonNullList import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess import net.minecraft.core.RegistryAccess
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
@ -19,18 +20,15 @@ import ru.dbotthepony.mc.otm.container.util.stream
import ru.dbotthepony.mc.otm.core.isActuallyEmpty import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
class ExplosiveHammerPrimingRecipe(private val _id: ResourceLocation, val payload: Ingredient) : CraftingRecipe { class ExplosiveHammerPrimingRecipe(val payload: Ingredient) : CraftingRecipe {
override fun isIncomplete(): Boolean { override fun isIncomplete(): Boolean {
return payload.isActuallyEmpty return payload.isActuallyEmpty
} }
override fun getId(): ResourceLocation {
return _id
}
override fun isSpecial(): Boolean { override fun isSpecial(): Boolean {
return true return true
} }
@ -61,7 +59,7 @@ class ExplosiveHammerPrimingRecipe(private val _id: ResourceLocation, val payloa
} }
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<*> {
return Companion return CODEC
} }
override fun category(): CraftingBookCategory { override fun category(): CraftingBookCategory {
@ -72,39 +70,15 @@ class ExplosiveHammerPrimingRecipe(private val _id: ResourceLocation, val payloa
return NonNullList.of(Ingredient.of(), Ingredient.of(MItems.EXPLOSIVE_HAMMER), Ingredient.of(Tags.Items.GUNPOWDER), payload) return NonNullList.of(Ingredient.of(), Ingredient.of(MItems.EXPLOSIVE_HAMMER), Ingredient.of(Tags.Items.GUNPOWDER), payload)
} }
val finishedRecipe = object : FinishedRecipe { fun toFinished(id: ResourceLocation) = CODEC.toFinished(this, id)
override fun serializeRecipeData(pJson: JsonObject) {
pJson["payload"] = payload.toJson()
}
override fun getId(): ResourceLocation { companion object {
return _id val CODEC = Codec2RecipeSerializer<ExplosiveHammerPrimingRecipe> { p ->
} RecordCodecBuilder.create {
it.group(
override fun getType(): RecipeSerializer<*> { p.ingredients.fieldOf("payload").forGetter(ExplosiveHammerPrimingRecipe::payload)
return Companion ).apply(it, ::ExplosiveHammerPrimingRecipe)
} }
override fun serializeAdvancement(): JsonObject? {
return null
}
override fun getAdvancementId(): ResourceLocation? {
return null
}
}
companion object : RecipeSerializer<ExplosiveHammerPrimingRecipe> {
override fun fromJson(pRecipeId: ResourceLocation, pSerializedRecipe: JsonObject): ExplosiveHammerPrimingRecipe {
return ExplosiveHammerPrimingRecipe(pRecipeId, Ingredient.fromJson(pSerializedRecipe["payload"] ?: throw JsonSyntaxException("Missing `payload` from hammer priming recipe in $pRecipeId")))
}
override fun fromNetwork(pRecipeId: ResourceLocation, pBuffer: FriendlyByteBuf): ExplosiveHammerPrimingRecipe {
return ExplosiveHammerPrimingRecipe(pRecipeId, Ingredient.fromNetwork(pBuffer))
}
override fun toNetwork(pBuffer: FriendlyByteBuf, pRecipe: ExplosiveHammerPrimingRecipe) {
pRecipe.payload.toNetwork(pBuffer)
} }
} }
} }

View File

@ -41,7 +41,6 @@ interface IMatterEntanglerRecipe : IMatteryRecipe<CraftingContainer> {
} }
open class MatterEntanglerRecipe( open class MatterEntanglerRecipe(
private val id: ResourceLocation,
override val ingredients: IIngredientMatrix, override val ingredients: IIngredientMatrix,
override val matter: Decimal, override val matter: Decimal,
override val ticks: Double, override val ticks: Double,
@ -73,10 +72,6 @@ open class MatterEntanglerRecipe(
return result return result
} }
override fun getId(): ResourceLocation {
return id
}
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<*> {
return SERIALIZER return SERIALIZER
} }
@ -97,8 +92,8 @@ open class MatterEntanglerRecipe(
return true return true
} }
fun toFinished(): FinishedRecipe { fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this) return SERIALIZER.toFinished(this, id)
} }
fun energetic() = Energy(this) fun energetic() = Energy(this)
@ -113,8 +108,8 @@ open class MatterEntanglerRecipe(
} }
} }
fun toFinished(): FinishedRecipe { fun toFinished(id: ResourceLocation): FinishedRecipe {
return ENERGY_SERIALIZER.toFinished(this) return ENERGY_SERIALIZER.toFinished(this, id)
} }
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<*> {
@ -131,8 +126,8 @@ open class MatterEntanglerRecipe(
} }
} }
fun toFinished(): FinishedRecipe { fun toFinished(id: ResourceLocation): FinishedRecipe {
return MATTER_SERIALIZER.toFinished(this) return MATTER_SERIALIZER.toFinished(this, id)
} }
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<*> {
@ -150,7 +145,7 @@ open class MatterEntanglerRecipe(
ItemStack.CODEC.fieldOf("result").forGetter(MatterEntanglerRecipe::result), ItemStack.CODEC.fieldOf("result").forGetter(MatterEntanglerRecipe::result),
Codec.STRING.optionalFieldOf("uuidKey", "uuid").forGetter(MatterEntanglerRecipe::uuidKey), Codec.STRING.optionalFieldOf("uuidKey", "uuid").forGetter(MatterEntanglerRecipe::uuidKey),
UUIDUtil.STRING_CODEC.optionalFieldOf("fixedUuid").forGetter(MatterEntanglerRecipe::fixedUuid) UUIDUtil.STRING_CODEC.optionalFieldOf("fixedUuid").forGetter(MatterEntanglerRecipe::fixedUuid)
).apply(it) { a, b, c, d, e, f -> MatterEntanglerRecipe(context.id, a, b, c, d, e, f) } ).apply(it, ::MatterEntanglerRecipe)
} }
} }

View File

@ -14,14 +14,12 @@ import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.item.crafting.RecipeSerializer import net.minecraft.world.item.crafting.RecipeSerializer
import net.minecraft.world.item.crafting.RecipeType import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.core.isActuallyEmpty import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import ru.dbotthepony.mc.otm.data.IngredientCodec
import ru.dbotthepony.mc.otm.data.PredicatedCodecList import ru.dbotthepony.mc.otm.data.PredicatedCodecList
import ru.dbotthepony.mc.otm.data.minRange import ru.dbotthepony.mc.otm.data.minRange
import ru.dbotthepony.mc.otm.registry.MRecipes import ru.dbotthepony.mc.otm.registry.MRecipes
@ -29,17 +27,15 @@ import java.util.EnumMap
import java.util.function.Predicate import java.util.function.Predicate
class PainterRecipe( class PainterRecipe(
private val id: ResourceLocation,
val input: Ingredient, val input: Ingredient,
val output: ItemStack, val output: ItemStack,
val dyes: Map<DyeColor, Int> val dyes: Map<DyeColor, Int>
) : Recipe<Container> { ) : Recipe<Container> {
constructor( constructor(
id: ResourceLocation,
input: Ingredient, input: Ingredient,
output: ItemStack, output: ItemStack,
dyes: Set<DyeColor> dyes: Set<DyeColor>
) : this(id, input, output, dyes.associateWith { 1 }) ) : this(input, output, dyes.associateWith { 1 })
fun canCraft(storedDyes: Map<DyeColor, Int>): Boolean { fun canCraft(storedDyes: Map<DyeColor, Int>): Boolean {
if (isIncomplete) return false if (isIncomplete) return false
@ -96,10 +92,6 @@ class PainterRecipe(
return output return output
} }
override fun getId(): ResourceLocation {
return id
}
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<*> {
return SERIALIZER return SERIALIZER
} }
@ -108,8 +100,8 @@ class PainterRecipe(
return MRecipes.PAINTER return MRecipes.PAINTER
} }
fun toFinished(): FinishedRecipe { fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this) return SERIALIZER.toFinished(this, id)
} }
companion object { companion object {
@ -123,7 +115,7 @@ class PainterRecipe(
Codec.list(DyeColor.CODEC).xmap({ it.associateWith { 1 } }, { ArrayList(it.keys) }) to Predicate { it.values.all { it == 1 } }, Codec.list(DyeColor.CODEC).xmap({ it.associateWith { 1 } }, { ArrayList(it.keys) }) to Predicate { it.values.all { it == 1 } },
Codec.unboundedMap(DyeColor.CODEC, Codec.INT.minRange(1)) to Predicate { true } Codec.unboundedMap(DyeColor.CODEC, Codec.INT.minRange(1)) to Predicate { true }
).fieldOf("dyes").forGetter(PainterRecipe::dyes), ).fieldOf("dyes").forGetter(PainterRecipe::dyes),
).apply(it) { a, b, c -> PainterRecipe(context.id, a, b, c) } ).apply(it, ::PainterRecipe)
} }
} }
} }

View File

@ -20,11 +20,9 @@ import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.registry.MRecipes import ru.dbotthepony.mc.otm.registry.MRecipes
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import ru.dbotthepony.mc.otm.data.IngredientCodec
import ru.dbotthepony.mc.otm.data.minRange import ru.dbotthepony.mc.otm.data.minRange
class PlatePressRecipe( class PlatePressRecipe(
private val id: ResourceLocation,
val input: Ingredient, val input: Ingredient,
val output: Ingredient, val output: Ingredient,
val count: Int = 1, val count: Int = 1,
@ -70,15 +68,13 @@ class PlatePressRecipe(
override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int) = true override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int) = true
override fun getResultItem(registry: RegistryAccess): ItemStack = outputStack override fun getResultItem(registry: RegistryAccess): ItemStack = outputStack
override fun getId() = id
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<*> {
return SERIALIZER return SERIALIZER
} }
override fun getType(): RecipeType<PlatePressRecipe> = MRecipes.PLATE_PRESS override fun getType(): RecipeType<PlatePressRecipe> = MRecipes.PLATE_PRESS
fun toFinished() = SERIALIZER.toFinished(this) fun toFinished(id: ResourceLocation) = SERIALIZER.toFinished(this, id)
companion object { companion object {
val SERIALIZER = Codec2RecipeSerializer<PlatePressRecipe> { context -> val SERIALIZER = Codec2RecipeSerializer<PlatePressRecipe> { context ->
@ -89,7 +85,7 @@ class PlatePressRecipe(
Codec.INT.minRange(1).optionalFieldOf("count", 1).forGetter(PlatePressRecipe::count), Codec.INT.minRange(1).optionalFieldOf("count", 1).forGetter(PlatePressRecipe::count),
Codec.INT.minRange(0).optionalFieldOf("workTime", 200).forGetter(PlatePressRecipe::workTime), Codec.INT.minRange(0).optionalFieldOf("workTime", 200).forGetter(PlatePressRecipe::workTime),
FloatProvider.CODEC.optionalFieldOf("experience", ConstantFloat.ZERO).forGetter(PlatePressRecipe::experience) FloatProvider.CODEC.optionalFieldOf("experience", ConstantFloat.ZERO).forGetter(PlatePressRecipe::experience)
).apply(it) { a, b, c, d, e -> PlatePressRecipe(context.id, a, b, c, d, e) } ).apply(it, ::PlatePressRecipe)
} }
} }
} }

View File

@ -3,12 +3,15 @@ package ru.dbotthepony.mc.otm.recipe
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive import com.google.gson.JsonPrimitive
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.NonNullList import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess import net.minecraft.core.RegistryAccess
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.util.GsonHelper import net.minecraft.util.GsonHelper
import net.minecraft.util.StringRepresentable
import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingBookCategory import net.minecraft.world.item.crafting.CraftingBookCategory
@ -27,6 +30,7 @@ import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.core.util.readBinaryJson import ru.dbotthepony.mc.otm.core.util.readBinaryJson
import ru.dbotthepony.mc.otm.core.util.writeBinaryJson import ru.dbotthepony.mc.otm.core.util.writeBinaryJson
import ru.dbotthepony.mc.otm.core.collect.stream import ru.dbotthepony.mc.otm.core.collect.stream
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import java.util.stream.Stream import java.util.stream.Stream
class UpgradeRecipe( class UpgradeRecipe(
@ -34,6 +38,8 @@ class UpgradeRecipe(
copyPaths: Stream<Op>, copyPaths: Stream<Op>,
val source: ResourceLocation, val source: ResourceLocation,
) : CraftingRecipe, IShapedRecipe<CraftingContainer> by parent { ) : CraftingRecipe, IShapedRecipe<CraftingContainer> by parent {
constructor(parent: ShapedRecipe, copyPaths: Collection<Op>, source: ResourceLocation) : this(parent, copyPaths.stream(), source)
override fun matches(p_44002_: CraftingContainer, p_44003_: Level): Boolean { override fun matches(p_44002_: CraftingContainer, p_44003_: Level): Boolean {
return parent.matches(p_44002_, p_44003_) return parent.matches(p_44002_, p_44003_)
} }
@ -70,10 +76,6 @@ class UpgradeRecipe(
return parent.toastSymbol return parent.toastSymbol
} }
override fun getId(): ResourceLocation {
return parent.id
}
override fun isIncomplete(): Boolean { override fun isIncomplete(): Boolean {
return parent.isIncomplete return parent.isIncomplete
} }
@ -86,42 +88,39 @@ class UpgradeRecipe(
return parent.category() return parent.category()
} }
enum class OpType { enum class OpType : StringRepresentable {
DIRECT { DIRECT {
override fun deserialize(obj: JsonObject): Op { override val codec: Codec<Direct> = RecordCodecBuilder.create {
return Direct(GsonHelper.getAsString(obj, "path")) it.group(
Codec.STRING.fieldOf("path").forGetter(Direct::path)
).apply(it, ::Direct)
} }
}, INDIRECT { }, INDIRECT {
override fun deserialize(obj: JsonObject): Op { override val codec: Codec<Indirect> = RecordCodecBuilder.create {
return Indirect(GsonHelper.getAsString(obj, "source"), GsonHelper.getAsString(obj, "destination")) it.group(
Codec.STRING.fieldOf("source").forGetter(Indirect::pathSource),
Codec.STRING.fieldOf("destination").forGetter(Indirect::pathDestination),
).apply(it, ::Indirect)
} }
}; };
abstract fun deserialize(obj: JsonObject): Op override fun getSerializedName(): String {
} return name.lowercase()
interface Op {
val type: OpType
fun apply(source: CompoundTag, destination: CompoundTag)
fun serialize(json: JsonObject)
fun serialize(): JsonObject {
return JsonObject().also {
it["type"] = JsonPrimitive(type.name)
serialize(it)
}
} }
abstract val codec: Codec<out Op>
} }
data class Direct(val path: String) : Op { sealed class Op {
abstract val type: OpType
abstract fun apply(source: CompoundTag, destination: CompoundTag)
}
data class Direct(val path: String) : Op() {
private val split = path.split('.') private val split = path.split('.')
override val type: OpType override val type: OpType
get() = OpType.DIRECT get() = OpType.DIRECT
override fun serialize(json: JsonObject) {
json["path"] = JsonPrimitive("path")
}
override fun apply(source: CompoundTag, destination: CompoundTag) { override fun apply(source: CompoundTag, destination: CompoundTag) {
var a = source var a = source
var b = destination var b = destination
@ -149,18 +148,13 @@ class UpgradeRecipe(
} }
} }
data class Indirect(val pathSource: String, val pathDestination: String) : Op { data class Indirect(val pathSource: String, val pathDestination: String) : Op() {
private val splitSource = pathSource.split('.') private val splitSource = pathSource.split('.')
private val splitDestination = pathDestination.split('.') private val splitDestination = pathDestination.split('.')
override val type: OpType override val type: OpType
get() = OpType.INDIRECT get() = OpType.INDIRECT
override fun serialize(json: JsonObject) {
json["source"] = JsonPrimitive(pathSource)
json["destination"] = JsonPrimitive(pathDestination)
}
override fun apply(source: CompoundTag, destination: CompoundTag) { override fun apply(source: CompoundTag, destination: CompoundTag) {
var a = source var a = source
var b = destination var b = destination
@ -219,36 +213,23 @@ class UpgradeRecipe(
} }
override fun getSerializer(): RecipeSerializer<UpgradeRecipe> { override fun getSerializer(): RecipeSerializer<UpgradeRecipe> {
return Companion return CODEC
} }
companion object : RecipeSerializer<UpgradeRecipe> { companion object {
fun deserializeOp(json: JsonObject): Op { val COPY_PATHS_CODEC: Codec<List<Op>> = StringRepresentable
return OpType.valueOf(GsonHelper.getAsString(json, "type")).deserialize(json) .fromEnum(OpType::values)
} .dispatch({ it.type }, { it.codec })
.listOf()
override fun fromJson(id: ResourceLocation, data: JsonObject): UpgradeRecipe { val CODEC = Codec2RecipeSerializer<UpgradeRecipe> { p ->
return UpgradeRecipe( RecordCodecBuilder.create {
ShapedRecipe.Serializer.SHAPED_RECIPE.fromJson(id, data), it.group(
GsonHelper.getAsJsonArray(data, "copyPaths").stream().map { deserializeOp(it as JsonObject) }, p.wrap(ShapedRecipe.Serializer.SHAPED_RECIPE).fieldOf("parent").forGetter(UpgradeRecipe::parent),
ResourceLocation(GsonHelper.getAsString(data, "source")) COPY_PATHS_CODEC.fieldOf("copyPaths").forGetter(UpgradeRecipe::copyPaths),
) ResourceLocation.CODEC.fieldOf("source").forGetter(UpgradeRecipe::source)
} ).apply(it, ::UpgradeRecipe)
}
override fun fromNetwork(id: ResourceLocation, buff: FriendlyByteBuf): UpgradeRecipe? {
val recipe = ShapedRecipe.Serializer.SHAPED_RECIPE.fromNetwork(id, buff) ?: return null
return UpgradeRecipe(
recipe,
buff.readCollection({ ArrayList<Op>(it) }, { deserializeOp(it.readBinaryJson() as JsonObject) }).stream(),
buff.readResourceLocation()
)
}
override fun toNetwork(buff: FriendlyByteBuf, value: UpgradeRecipe) {
ShapedRecipe.Serializer.SHAPED_RECIPE.toNetwork(buff, value.parent)
buff.writeCollection(value.copyPaths) { it, v -> it.writeBinaryJson(v.serialize()) }
buff.writeResourceLocation(value.source)
} }
} }
} }

View File

@ -12,9 +12,9 @@ import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem
object MItemFunctionTypes { object MItemFunctionTypes {
private val registry = DeferredRegister.create(Registries.LOOT_FUNCTION_TYPE, OverdriveThatMatters.MOD_ID) private val registry = DeferredRegister.create(Registries.LOOT_FUNCTION_TYPE, OverdriveThatMatters.MOD_ID)
val COPY_TILE_NBT: LootItemFunctionType by registry.register("copy_tile_nbt") { LootItemFunctionType(CopyTileNbtFunction.Companion) } val COPY_TILE_NBT: LootItemFunctionType by registry.register("copy_tile_nbt") { LootItemFunctionType(CopyTileNbtFunction.CODEC) }
val PROCEDURAL_BATTERY: LootItemFunctionType by registry.register(MNames.PROCEDURAL_BATTERY) { LootItemFunctionType(ProceduralBatteryItem.Randomizer.SERIALIZER) } val PROCEDURAL_BATTERY: LootItemFunctionType by registry.register(MNames.PROCEDURAL_BATTERY) { LootItemFunctionType(ProceduralBatteryItem.Randomizer.CODEC) }
val PROCEDURAL_EXOPACK_UPGRADE: LootItemFunctionType by registry.register("exopack_upgrade") { LootItemFunctionType(ProceduralExopackSlotUpgradeItem.Randomizer.SERIALIZER) } val PROCEDURAL_EXOPACK_UPGRADE: LootItemFunctionType by registry.register("exopack_upgrade") { LootItemFunctionType(ProceduralExopackSlotUpgradeItem.Randomizer.CODEC) }
internal fun register(bus: IEventBus) { internal fun register(bus: IEventBus) {
registry.register(bus) registry.register(bus)

View File

@ -6,6 +6,7 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import net.minecraftforge.eventbus.api.IEventBus import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.DeferredRegister
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.data.SingletonCodec
import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition
import ru.dbotthepony.mc.otm.data.condition.HasExoPackCondition import ru.dbotthepony.mc.otm.data.condition.HasExoPackCondition
import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition
@ -16,12 +17,12 @@ import ru.dbotthepony.mc.otm.data.condition.ChanceCondition
object MLootItemConditions { object MLootItemConditions {
private val registry = DeferredRegister.create(Registries.LOOT_CONDITION_TYPE, OverdriveThatMatters.MOD_ID) private val registry = DeferredRegister.create(Registries.LOOT_CONDITION_TYPE, OverdriveThatMatters.MOD_ID)
val HAS_EXOPACK: LootItemConditionType by registry.register("has_exopack") { LootItemConditionType(HasExoPackCondition) } val HAS_EXOPACK: LootItemConditionType by registry.register("has_exopack") { LootItemConditionType(SingletonCodec(HasExoPackCondition)) }
val CHANCE_WITH_PLAYTIME: LootItemConditionType by registry.register("chance_with_playtime") { LootItemConditionType(ChanceWithPlaytimeCondition.SERIALIZER) } val CHANCE_WITH_PLAYTIME: LootItemConditionType by registry.register("chance_with_playtime") { LootItemConditionType(ChanceWithPlaytimeCondition.CODEC) }
val ITEM_IN_INVENTORY: LootItemConditionType by registry.register("item_in_inventory") { LootItemConditionType(ItemInInventoryCondition.SERIALIZER) } val ITEM_IN_INVENTORY: LootItemConditionType by registry.register("item_in_inventory") { LootItemConditionType(ItemInInventoryCondition.CODEC) }
val KILLED_BY_REAL_PLAYER: LootItemConditionType by registry.register("killed_by_real_player") { LootItemConditionType(KilledByRealPlayer) } val KILLED_BY_REAL_PLAYER: LootItemConditionType by registry.register("killed_by_real_player") { LootItemConditionType(SingletonCodec(KilledByRealPlayer)) }
val KILLED_BY_REAL_PLAYER_OR_INDIRECTLY: LootItemConditionType by registry.register("killed_by_real_player_or_indirectly") { LootItemConditionType(KilledByRealPlayerOrIndirectly) } val KILLED_BY_REAL_PLAYER_OR_INDIRECTLY: LootItemConditionType by registry.register("killed_by_real_player_or_indirectly") { LootItemConditionType(SingletonCodec(KilledByRealPlayerOrIndirectly)) }
val CHANCE: LootItemConditionType by registry.register("chance") { LootItemConditionType(ChanceCondition.SERIALIZER) } val CHANCE: LootItemConditionType by registry.register("chance") { LootItemConditionType(ChanceCondition.CODEC) }
internal fun register(bus: IEventBus) { internal fun register(bus: IEventBus) {
registry.register(bus) registry.register(bus)

View File

@ -45,8 +45,8 @@ object MRecipes {
init { init {
serializers.register("plate_press") { PlatePressRecipe.SERIALIZER } serializers.register("plate_press") { PlatePressRecipe.SERIALIZER }
serializers.register("energy_container") { EnergyContainerRecipe.Companion } serializers.register("energy_container") { EnergyContainerRecipe.Companion }
serializers.register("upgrade") { UpgradeRecipe.Companion } serializers.register("upgrade") { UpgradeRecipe.CODEC }
serializers.register("hammer_priming") { ExplosiveHammerPrimingRecipe.Companion } serializers.register("hammer_priming") { ExplosiveHammerPrimingRecipe.CODEC }
serializers.register("painter") { PainterRecipe.SERIALIZER } serializers.register("painter") { PainterRecipe.SERIALIZER }
serializers.register("matter_entangler") { MatterEntanglerRecipe.SERIALIZER } serializers.register("matter_entangler") { MatterEntanglerRecipe.SERIALIZER }
serializers.register("matter_entangler_energetic") { MatterEntanglerRecipe.ENERGY_SERIALIZER } serializers.register("matter_entangler_energetic") { MatterEntanglerRecipe.ENERGY_SERIALIZER }

View File

@ -290,28 +290,28 @@ object MRegistry {
private fun initializeCommon(event: FMLCommonSetupEvent) { private fun initializeCommon(event: FMLCommonSetupEvent) {
event.enqueueWork { event.enqueueWork {
CriteriaTriggers.register(BlackHoleTrigger) CriteriaTriggers.register(BlackHoleTrigger.id.toString(), BlackHoleTrigger)
CriteriaTriggers.register(BecomeAndroidTrigger) CriteriaTriggers.register(BecomeAndroidTrigger.id.toString(), BecomeAndroidTrigger)
CriteriaTriggers.register(BecomeAndroidDeathTrigger) CriteriaTriggers.register(BecomeAndroidDeathTrigger.id.toString(), BecomeAndroidDeathTrigger)
CriteriaTriggers.register(BecomeAndroidSleepTrigger) CriteriaTriggers.register(BecomeAndroidSleepTrigger.id.toString(), BecomeAndroidSleepTrigger)
CriteriaTriggers.register(BecomeHumaneTrigger) CriteriaTriggers.register(BecomeHumaneTrigger.id.toString(), BecomeHumaneTrigger)
CriteriaTriggers.register(AndroidResearchTrigger) CriteriaTriggers.register(AndroidResearchTrigger.id.toString(), AndroidResearchTrigger)
CriteriaTriggers.register(ShockwaveDamageMobTrigger) CriteriaTriggers.register(ShockwaveDamageMobTrigger.id.toString(), ShockwaveDamageMobTrigger)
CriteriaTriggers.register(ShockwaveTrigger) CriteriaTriggers.register(ShockwaveTrigger.id.toString(), ShockwaveTrigger)
CriteriaTriggers.register(AndroidBatteryTrigger) CriteriaTriggers.register(AndroidBatteryTrigger.id.toString(), AndroidBatteryTrigger)
CriteriaTriggers.register(NanobotsArmorTrigger) CriteriaTriggers.register(NanobotsArmorTrigger.id.toString(), NanobotsArmorTrigger)
CriteriaTriggers.register(FallDampenersSaveTrigger) CriteriaTriggers.register(FallDampenersSaveTrigger.id.toString(), FallDampenersSaveTrigger)
CriteriaTriggers.register(EnderTeleporterFallDeathTrigger) CriteriaTriggers.register(EnderTeleporterFallDeathTrigger.id.toString(), EnderTeleporterFallDeathTrigger)
CriteriaTriggers.register(KillAsAndroidTrigger) CriteriaTriggers.register(KillAsAndroidTrigger.id.toString(), KillAsAndroidTrigger)
CriteriaTriggers.register(AndroidTravelUnderwater) CriteriaTriggers.register(AndroidTravelUnderwater.id.toString(), AndroidTravelUnderwater)
CriteriaTriggers.register(NailedEntityTrigger) CriteriaTriggers.register(NailedEntityTrigger.id.toString(), NailedEntityTrigger)
CriteriaTriggers.register(ExopackObtainedTrigger) CriteriaTriggers.register(ExopackObtainedTrigger.id.toString(), ExopackObtainedTrigger)
CriteriaTriggers.register(ExopackGainedSmeltingTrigger) CriteriaTriggers.register(ExopackGainedSmeltingTrigger.id.toString(), ExopackGainedSmeltingTrigger)
CriteriaTriggers.register(ExopackGainedCraftingTrigger) CriteriaTriggers.register(ExopackGainedCraftingTrigger.id.toString(), ExopackGainedCraftingTrigger)
CriteriaTriggers.register(ExopackGainedEnderAccessTrigger) CriteriaTriggers.register(ExopackGainedEnderAccessTrigger.id.toString(), ExopackGainedEnderAccessTrigger)
CriteriaTriggers.register(ExopackSlotsExpandedTrigger) CriteriaTriggers.register(ExopackSlotsExpandedTrigger.id.toString(), ExopackSlotsExpandedTrigger)
CriteriaTriggers.register(ExopackBatterySlotTrigger) CriteriaTriggers.register(ExopackBatterySlotTrigger.id.toString(), ExopackBatterySlotTrigger)
CriteriaTriggers.register(TakeItemOutOfReplicatorTrigger) CriteriaTriggers.register(TakeItemOutOfReplicatorTrigger.id.toString(), TakeItemOutOfReplicatorTrigger)
} }
} }

View File

@ -2,25 +2,22 @@ package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive import com.google.gson.JsonPrimitive
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.* import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidResearchType import ru.dbotthepony.mc.otm.android.AndroidResearchType
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import java.util.Optional
import java.util.function.Predicate import java.util.function.Predicate
object AndroidResearchTrigger : SimpleCriterionTrigger<AndroidResearchTrigger.Instance>() { object AndroidResearchTrigger : SimpleCriterionTrigger<AndroidResearchTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research") val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research")
override fun getId(): ResourceLocation {
return ID
}
override fun createInstance( override fun createInstance(
p_66248_: JsonObject, p_66248_: JsonObject,
p_286603_: ContextAwarePredicate, p_286603_: Optional<ContextAwarePredicate>,
p_66250_: DeserializationContext p_66250_: DeserializationContext
): Instance { ): Instance {
return Instance( return Instance(
@ -34,18 +31,20 @@ object AndroidResearchTrigger : SimpleCriterionTrigger<AndroidResearchTrigger.In
} }
} }
class Instance(val research: ResourceLocation?) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY), Predicate<AndroidResearchType> { class Instance(val research: ResourceLocation?) : AbstractCriterionTriggerInstance(Optional.empty()), Predicate<AndroidResearchType> {
constructor(research: AndroidResearchType) : this(research.id) constructor(research: AndroidResearchType) : this(research.id)
override fun test(t: AndroidResearchType): Boolean { override fun test(t: AndroidResearchType): Boolean {
return research == null || t.id == research return research == null || t.id == research
} }
override fun serializeToJson(p_16979_: SerializationContext): JsonObject { override fun serializeToJson(): JsonObject {
return super.serializeToJson(p_16979_).also { return super.serializeToJson().also {
if (research != null) if (research != null)
it["research"] = JsonPrimitive(research.toString()) it["research"] = JsonPrimitive(research.toString())
} }
} }
fun criterion() = Criterion(AndroidResearchTrigger, this)
} }
} }

View File

@ -3,21 +3,24 @@ package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParseException import com.google.gson.JsonParseException
import com.google.gson.JsonPrimitive import com.google.gson.JsonPrimitive
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.* import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.toJsonStrict
import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import ru.dbotthepony.mc.otm.data.minRange
import java.util.Optional
object AndroidTravelUnderwater : SimpleCriterionTrigger<AndroidTravelUnderwater.Instance>() { object AndroidTravelUnderwater : SimpleCriterionTrigger<AndroidTravelUnderwater.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_walk_underwater") val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_walk_underwater")
override fun getId(): ResourceLocation { override fun createInstance(pJson: JsonObject, pPlayer: Optional<ContextAwarePredicate>, pContext: DeserializationContext): Instance {
return ID return codec.fromJson(pJson, pPlayer, pContext)
}
override fun createInstance(pJson: JsonObject, pPlayer: ContextAwarePredicate, pContext: DeserializationContext): Instance {
return Instance((pJson["distance_to_travel"] as? JsonPrimitive)?.asDouble ?: throw JsonParseException("Invalid 'distance_to_travel' value"))
} }
fun trigger(player: ServerPlayer, travelled: Double) { fun trigger(player: ServerPlayer, travelled: Double) {
@ -26,11 +29,20 @@ object AndroidTravelUnderwater : SimpleCriterionTrigger<AndroidTravelUnderwater.
} }
} }
class Instance(val distanceToTravel: Double) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) { val codec = Codec2TriggerSerializer<Instance> { p ->
override fun serializeToJson(pConditions: SerializationContext): JsonObject { RecordCodecBuilder.create {
return super.serializeToJson(pConditions).also { it.group(
it["distance_to_travel"] = JsonPrimitive(distanceToTravel) Codec.DOUBLE.minRange(0.0).fieldOf("distanceToTravel").forGetter(Instance::distanceToTravel),
} p.playerPredicate.forGetter { it.playerPredicate() }
).apply(it, ::Instance)
} }
} }
class Instance(val distanceToTravel: Double, playerPredicate: Optional<ContextAwarePredicate> = Optional.empty()) : AbstractCriterionTriggerInstance(playerPredicate) {
override fun serializeToJson(): JsonObject {
return codec.toJson(this)
}
fun criterion() = Criterion(AndroidTravelUnderwater, this)
}
} }

View File

@ -3,16 +3,17 @@ package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.mojang.serialization.Codec import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.SerializationContext
import net.minecraft.advancements.critereon.SimpleCriterionTrigger import net.minecraft.advancements.critereon.SimpleCriterionTrigger
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.fromJsonStrict import ru.dbotthepony.mc.otm.core.fromJsonStrict
import ru.dbotthepony.mc.otm.core.toJsonStrict import ru.dbotthepony.mc.otm.core.toJsonStrict
import java.util.Optional
val ExopackObtainedTrigger = SingletonTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_obtained")) val ExopackObtainedTrigger = SingletonTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_obtained"))
val ExopackGainedCraftingTrigger = SingletonTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_gained_crafting")) val ExopackGainedCraftingTrigger = SingletonTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_gained_crafting"))
@ -22,11 +23,7 @@ val ExopackGainedEnderAccessTrigger = SingletonTrigger(ResourceLocation(Overdriv
val ExopackBatterySlotTrigger = ItemTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_battery_slot")) val ExopackBatterySlotTrigger = ItemTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_battery_slot"))
object ExopackSlotsExpandedTrigger : SimpleCriterionTrigger<ExopackSlotsExpandedTrigger.Instance>() { object ExopackSlotsExpandedTrigger : SimpleCriterionTrigger<ExopackSlotsExpandedTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_expanded") val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_expanded")
override fun getId(): ResourceLocation {
return ID
}
val codec: Codec<Instance> = RecordCodecBuilder.create { val codec: Codec<Instance> = RecordCodecBuilder.create {
it.group( it.group(
@ -39,18 +36,20 @@ object ExopackSlotsExpandedTrigger : SimpleCriterionTrigger<ExopackSlotsExpanded
trigger(player) { it.minGained <= gained && it.minTotal <= total } trigger(player) { it.minGained <= gained && it.minTotal <= total }
} }
override fun createInstance(p_66248_: JsonObject, p_286603_: ContextAwarePredicate, p_66250_: DeserializationContext): Instance { override fun createInstance(p_66248_: JsonObject, p_286603_: Optional<ContextAwarePredicate>, p_66250_: DeserializationContext): Instance {
return codec.fromJsonStrict(p_66248_) return codec.fromJsonStrict(p_66248_)
} }
data class Instance(val minGained: Int = 0, val minTotal: Int = 0) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) { data class Instance(val minGained: Int = 0, val minTotal: Int = 0) : AbstractCriterionTriggerInstance(Optional.empty()) {
init { init {
require(minGained >= 0) { "Invalid minGained $minGained" } require(minGained >= 0) { "Invalid minGained $minGained" }
require(minTotal >= 0) { "Invalid minTotal $minTotal" } require(minTotal >= 0) { "Invalid minTotal $minTotal" }
} }
override fun serializeToJson(p_16979_: SerializationContext): JsonObject { override fun serializeToJson(): JsonObject {
return codec.toJsonStrict(this) as JsonObject return codec.toJsonStrict(this) as JsonObject
} }
fun criterion() = Criterion(ExopackSlotsExpandedTrigger, this)
} }
} }

View File

@ -1,54 +1,62 @@
package ru.dbotthepony.mc.otm.triggers package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.* import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.damagesource.DamageSource import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import ru.dbotthepony.mc.otm.data.DamagePredicateCodec
import java.util.Optional
abstract class HurtTrigger : SimpleCriterionTrigger<HurtTrigger.Instance>() { abstract class HurtTrigger : SimpleCriterionTrigger<HurtTrigger.Instance>() {
abstract val ID: ResourceLocation abstract val id: ResourceLocation
override fun getId(): ResourceLocation { final override fun createInstance(
return ID
}
override fun createInstance(
p_66248_: JsonObject, p_66248_: JsonObject,
p_286603_: ContextAwarePredicate, p_286603_: Optional<ContextAwarePredicate>,
p_66250_: DeserializationContext p_66250_: DeserializationContext
): Instance { ): Instance {
return Instance( return codec.fromJson(p_66248_, p_286603_, p_66250_)
EntityPredicate.fromJson(p_66248_, "entity_predicate", p_66250_),
(p_66248_["damage"] as? JsonObject)?.let(DamagePredicate::fromJson) ?: DamagePredicate.ANY
)
} }
fun trigger(player: ServerPlayer, entity: LivingEntity, damage: Float, damageSource: DamageSource) { fun trigger(player: ServerPlayer, entity: LivingEntity, damage: Float, damageSource: DamageSource) {
val context = EntityPredicate.createContext(player, entity) val context = EntityPredicate.createContext(player, entity)
trigger(player) { trigger(player) {
it.predicate.matches(context) && it.damagePredicate.matches(player, damageSource, damage, damage, false) it.predicate.map { it.matches(context) }.orElse(true) && it.damagePredicate.map { it.matches(player, damageSource, damage, damage, false) }.orElse(true)
}
}
val codec = Codec2TriggerSerializer<Instance> { p ->
RecordCodecBuilder.create {
it.group(
p.awareContextCodec.optionalFieldOf("predicate").forGetter(Instance::predicate),
DamagePredicateCodec.optionalFieldOf("damagePredicate").forGetter(Instance::damagePredicate),
p.playerPredicate.forGetter { it.playerPredicate() }
).apply(it, ::Instance)
} }
} }
inner class Instance( inner class Instance(
val predicate: ContextAwarePredicate = ContextAwarePredicate.ANY, val predicate: Optional<ContextAwarePredicate> = Optional.empty(),
val damagePredicate: DamagePredicate = DamagePredicate( val damagePredicate: Optional<DamagePredicate> = Optional.of(DamagePredicate(
MinMaxBounds.Doubles.atLeast(1.0), MinMaxBounds.Doubles.atLeast(1.0),
MinMaxBounds.Doubles.atLeast(1.0), MinMaxBounds.Doubles.atLeast(1.0),
EntityPredicate.ANY, Optional.empty(),
null, Optional.empty(),
DamageSourcePredicate.ANY Optional.empty()
) )),
) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) { player: Optional<ContextAwarePredicate> = Optional.empty()
override fun serializeToJson(pConditions: SerializationContext): JsonObject { ) : AbstractCriterionTriggerInstance(player) {
return super.serializeToJson(pConditions).also { override fun serializeToJson(): JsonObject {
it["entity_predicate"] = predicate.toJson(pConditions) return codec.toJson(this)
it["damage"] = damagePredicate.serializeToJson()
}
} }
fun criterion() = Criterion(this@HurtTrigger, this)
} }
} }

View File

@ -3,42 +3,42 @@ package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.mojang.serialization.Codec import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.advancements.critereon.SerializationContext
import net.minecraft.advancements.critereon.SimpleCriterionTrigger import net.minecraft.advancements.critereon.SimpleCriterionTrigger
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.core.fromJsonStrict import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import ru.dbotthepony.mc.otm.core.toJsonStrict import java.util.Optional
import ru.dbotthepony.mc.otm.data.ItemPredicateCodec
class ItemTrigger(val ID: ResourceLocation) : SimpleCriterionTrigger<ItemTrigger.Instance>() {
override fun getId(): ResourceLocation {
return ID
}
class ItemTrigger(val id: ResourceLocation) : SimpleCriterionTrigger<ItemTrigger.Instance>() {
fun trigger(player: ServerPlayer, item: ItemStack) { fun trigger(player: ServerPlayer, item: ItemStack) {
trigger(player) { if (it.invert) !it.predicate.matches(item) else it.predicate.matches(item) } trigger(player) { if (it.invert) !it.predicate.matches(item) else it.predicate.matches(item) }
} }
val codec: Codec<Instance> = RecordCodecBuilder.create { val codec = Codec2TriggerSerializer<Instance> { p ->
it.group( RecordCodecBuilder.create {
ItemPredicateCodec.fieldOf("predicate").forGetter(Instance::predicate), it.group(
Codec.BOOL.optionalFieldOf("invert", false).forGetter(Instance::invert), ItemPredicate.CODEC.fieldOf("predicate").forGetter(Instance::predicate),
).apply(it, ::Instance) Codec.BOOL.optionalFieldOf("invert", false).forGetter(Instance::invert),
} p.playerPredicate.forGetter { it.playerPredicate() }
).apply(it, ::Instance)
override fun createInstance(p_66248_: JsonObject, p_286603_: ContextAwarePredicate, p_66250_: DeserializationContext): Instance {
return codec.fromJsonStrict(p_66248_)
}
inner class Instance(val predicate: ItemPredicate, val invert: Boolean = false) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) {
override fun serializeToJson(p_16979_: SerializationContext): JsonObject {
return codec.toJsonStrict(this) as JsonObject
} }
} }
override fun createInstance(p_66248_: JsonObject, p_286603_: Optional<ContextAwarePredicate>, p_66250_: DeserializationContext): Instance {
return codec.fromJson(p_66248_, p_286603_, p_66250_)
}
inner class Instance(val predicate: ItemPredicate, val invert: Boolean = false, player: Optional<ContextAwarePredicate> = Optional.empty()) : AbstractCriterionTriggerInstance(player) {
override fun serializeToJson(): JsonObject {
return codec.toJson(this)
}
fun criterion() = Criterion(this@ItemTrigger, this)
}
} }

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException import com.google.gson.JsonSyntaxException
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.* import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
@ -16,16 +17,13 @@ import ru.dbotthepony.mc.otm.core.asIterable
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.stream import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.Optional
import java.util.function.Predicate import java.util.function.Predicate
object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instance>() { object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "kill_as_android") val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "kill_as_android")
override fun getId(): ResourceLocation { override fun createInstance(pJson: JsonObject, pPlayer: Optional<ContextAwarePredicate>, pContext: DeserializationContext): Instance {
return ID
}
override fun createInstance(pJson: JsonObject, pPlayer: ContextAwarePredicate, pContext: DeserializationContext): Instance {
return Instance( return Instance(
predicate = EntityPredicate.fromJson(pJson, "predicate", pContext), predicate = EntityPredicate.fromJson(pJson, "predicate", pContext),
playerPredicate = pPlayer, playerPredicate = pPlayer,
@ -164,16 +162,18 @@ object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instan
} }
class Instance( class Instance(
val predicate: ContextAwarePredicate = ContextAwarePredicate.ANY, val predicate: Optional<ContextAwarePredicate> = Optional.empty(),
val featurePredicate: FeaturePredicate = Always, val featurePredicate: FeaturePredicate = Always,
playerPredicate: ContextAwarePredicate = ContextAwarePredicate.ANY, playerPredicate: Optional<ContextAwarePredicate> = Optional.empty(),
) : AbstractCriterionTriggerInstance(ID, playerPredicate) { ) : AbstractCriterionTriggerInstance(playerPredicate) {
override fun serializeToJson(pConditions: SerializationContext): JsonObject { override fun serializeToJson(): JsonObject {
return super.serializeToJson(pConditions).also { return super.serializeToJson().also {
it["predicate"] = predicate.toJson(pConditions) predicate.ifPresent { p -> it["predicate"] = p.toJson() }
it["feature_predicate"] = featurePredicate.toJson() it["feature_predicate"] = featurePredicate.toJson()
} }
} }
fun criterion() = Criterion(KillAsAndroidTrigger, this)
} }
fun onKill(event: LivingDeathEvent) { fun onKill(event: LivingDeathEvent) {
@ -187,7 +187,7 @@ object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instan
val context = EntityPredicate.createContext(killer, event.entity) val context = EntityPredicate.createContext(killer, event.entity)
trigger(killer) { trigger(killer) {
it.predicate.matches(context) && it.predicate.map { it.matches(context) }.orElse(true) &&
it.featurePredicate.test(data) it.featurePredicate.test(data)
} }
} }

View File

@ -17,8 +17,10 @@ import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.PlayerAdvancements import net.minecraft.server.PlayerAdvancements
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.tags.TagKey
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.CombinedContainer
@ -28,7 +30,9 @@ import ru.dbotthepony.mc.otm.container.util.iterator
import ru.dbotthepony.mc.otm.core.collect.flatMap import ru.dbotthepony.mc.otm.core.collect.flatMap
import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty
import java.util.Optional
import java.util.stream.Collectors import java.util.stream.Collectors
import kotlin.jvm.optionals.getOrNull
/** /**
* This object detours all necessary InventoryChangeTrigger methods * This object detours all necessary InventoryChangeTrigger methods
@ -86,14 +90,14 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
nodes.add(Node( nodes.add(Node(
DefaultStrategy, DefaultStrategy,
{ predicates.iterator().flatMap { (it.items ?: listOf(null)).iterator() }.toList() }, { predicates.iterator().flatMap { (it.items.map { it.map { it.value() } }.orElse(listOf(null))).iterator() }.toList() },
{ v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.item == v }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.item == v },
{ inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> mutableListOf(item.item) })) { inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> mutableListOf(item.item) }))
nodes.add(Node( nodes.add(Node(
DefaultStrategy, DefaultStrategy,
{ predicates.map { it.tag } }, { predicates.map { it.tag as Optional<TagKey<Item>> } },
{ v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.`is`(v) }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.isEmpty || item.`is`(v.get()) },
{ inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> item.tags.collect(Collectors.toCollection(::ArrayList)) })) { inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> item.tags.collect(Collectors.toCollection(::ArrayList)) }))
nodes.add(Node(BoundsStrategy, { predicates.map { it.count } }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.matches(item.count) })) nodes.add(Node(BoundsStrategy, { predicates.map { it.count } }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.matches(item.count) }))
@ -136,13 +140,13 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
fun add(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) { fun add(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
if (set.add(listener)) { if (set.add(listener)) {
search(listener.triggerInstance, tree, 0).forEach { it.add(listener) } search(listener.trigger, tree, 0).forEach { it.add(listener) }
} }
} }
fun remove(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) { fun remove(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
if (set.remove(listener)) { if (set.remove(listener)) {
search(listener.triggerInstance, tree, 0).forEach { it.remove(listener) } search(listener.trigger, tree, 0).forEach { it.remove(listener) }
} }
} }
@ -168,7 +172,7 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
if (nodeId + 1 == nodes.size) { if (nodeId + 1 == nodes.size) {
for (l in v as Set<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>) { for (l in v as Set<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>) {
// переделываем matches у InventoryTriggerInstance // переделываем matches у InventoryTriggerInstance
with (l.triggerInstance) { with (l.trigger) {
if ( if (
this.slotsFull.matches(slotsFull) && this.slotsFull.matches(slotsFull) &&
this.slotsEmpty.matches(slotsEmpty) && this.slotsEmpty.matches(slotsEmpty) &&
@ -212,10 +216,6 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
private val listeners = Reference2ObjectOpenHashMap<PlayerAdvancements, ListenerTree>() private val listeners = Reference2ObjectOpenHashMap<PlayerAdvancements, ListenerTree>()
override fun getId(): ResourceLocation {
return CriteriaTriggers.INVENTORY_CHANGED.id
}
override fun addPlayerListener(advancements: PlayerAdvancements, instance: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) { override fun addPlayerListener(advancements: PlayerAdvancements, instance: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
listeners.computeIfAbsent(advancements, Reference2ObjectFunction { ListenerTree(it as PlayerAdvancements) }).add(instance) listeners.computeIfAbsent(advancements, Reference2ObjectFunction { ListenerTree(it as PlayerAdvancements) }).add(instance)
} }

View File

@ -4,5 +4,5 @@ import net.minecraft.resources.ResourceLocation
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
object NailedEntityTrigger : HurtTrigger() { object NailedEntityTrigger : HurtTrigger() {
override val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "hammer_nail_damage") override val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "hammer_nail_damage")
} }

View File

@ -1,40 +1,45 @@
package ru.dbotthepony.mc.otm.triggers package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.* import net.minecraft.advancements.critereon.*
import net.minecraft.advancements.critereon.MinMaxBounds.Doubles import net.minecraft.advancements.critereon.MinMaxBounds.Doubles
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import ru.dbotthepony.mc.otm.core.set import java.util.Optional
object NanobotsArmorTrigger : SimpleCriterionTrigger<NanobotsArmorTrigger.Instance>() { object NanobotsArmorTrigger : SimpleCriterionTrigger<NanobotsArmorTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor") val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor")
override fun getId(): ResourceLocation {
return ID
}
override fun createInstance( override fun createInstance(
p_66248_: JsonObject, p_66248_: JsonObject,
p_286603_: ContextAwarePredicate, p_286603_: Optional<ContextAwarePredicate>,
p_66250_: DeserializationContext p_66250_: DeserializationContext
): Instance { ): Instance {
return Instance( return codec.fromJson(p_66248_, p_286603_, p_66250_)
Doubles.fromJson(p_66248_["predicate"]) }
)
val codec = Codec2TriggerSerializer<Instance> { p ->
RecordCodecBuilder.create {
it.group(
Doubles.CODEC.fieldOf("predicate").forGetter(Instance::predicate),
p.playerPredicate.forGetter { it.playerPredicate() },
).apply(it, ::Instance)
}
} }
fun trigger(player: ServerPlayer, damageAbsorbed: Double) { fun trigger(player: ServerPlayer, damageAbsorbed: Double) {
trigger(player) { it.predicate.matches(damageAbsorbed) } trigger(player) { it.predicate.matches(damageAbsorbed) }
} }
class Instance(val predicate: Doubles) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) { class Instance(val predicate: Doubles, player: Optional<ContextAwarePredicate> = Optional.empty()) : AbstractCriterionTriggerInstance(player) {
override fun serializeToJson(p_16979_: SerializationContext): JsonObject { override fun serializeToJson(): JsonObject {
return super.serializeToJson(p_16979_).also { return codec.toJson((this))
it["predicate"] = predicate.serializeToJson()
}
} }
fun criterion() = Criterion(NanobotsArmorTrigger, this)
} }
} }

View File

@ -4,5 +4,5 @@ import net.minecraft.resources.ResourceLocation
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
object ShockwaveDamageMobTrigger : HurtTrigger() { object ShockwaveDamageMobTrigger : HurtTrigger() {
override val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "shockwave_damage_mob") override val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "shockwave_damage_mob")
} }

View File

@ -1,25 +1,42 @@
package ru.dbotthepony.mc.otm.triggers package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.SimpleCriterionTrigger import net.minecraft.advancements.critereon.SimpleCriterionTrigger
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import java.util.Optional
class SingletonTrigger(val ID: ResourceLocation) : SimpleCriterionTrigger<AbstractCriterionTriggerInstance>() { class SingletonTrigger(val id: ResourceLocation) : SimpleCriterionTrigger<AbstractCriterionTriggerInstance>() {
override fun getId(): ResourceLocation { override fun createInstance(p_66248_: JsonObject, p_286603_: Optional<ContextAwarePredicate>, p_66250_: DeserializationContext): AbstractCriterionTriggerInstance {
return ID return codec.fromJson(p_66248_, p_286603_, p_66250_)
}
override fun createInstance(p_66248_: JsonObject, p_286603_: ContextAwarePredicate, p_66250_: DeserializationContext): AbstractCriterionTriggerInstance {
return instance
} }
fun trigger(player: ServerPlayer) { fun trigger(player: ServerPlayer) {
trigger(player) { true } trigger(player) { true }
} }
val instance = object : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) {} val codec = Codec2TriggerSerializer<Instance> { p ->
RecordCodecBuilder.create {
it.group(
p.playerPredicate.forGetter { it.playerPredicate() }
).apply(it, ::Instance)
}
}
val empty = Instance()
val criterion = Criterion(this@SingletonTrigger, empty)
inner class Instance(player: Optional<ContextAwarePredicate> = Optional.empty()) : AbstractCriterionTriggerInstance(player) {
override fun serializeToJson(): JsonObject {
return codec.toJson(this)
}
fun criterion() = Criterion(this@SingletonTrigger, this)
}
} }

Some files were not shown because too many files have changed in this diff Show More