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) {
val jei_version: String by project
val mekanism_version: String by project
val cosmetic_armor_reworked_id: String by project
val jade_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("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: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
mod_id=overdrive_that_matters
mod_version=1.3
mod_version=1.4
use_commit_hash_in_version=true
mc_version=1.20.2
use_parchment=false
jei_mc_version=1.20.2
curios_mc_version=1.20
@ -22,7 +21,6 @@ mixin_version=0.8.5
jei_version=16.0.0.28
jupiter_version=5.9.2
mekanism_version=1.20.1-10.3.9.homebaked
curios_version=5.2.0-beta.2
cosmetic_armor_reworked_id=4575609
ad_astra_id=4594155

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,20 +1,16 @@
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.RequirementsStrategy
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.network.chat.contents.TranslatableContents
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
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.key
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider
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.triggers.TakeItemOutOfReplicatorTrigger
import java.util.function.Consumer
@ -27,7 +23,7 @@ private data class CraftEntry(
val russianName: 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 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),
)
.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 chem = AdvancementBuilder()
@ -69,7 +65,7 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
},
)
.addCriterion("has_machine", criterion(MItems.CHEMICAL_GENERATOR))
.save(serializer, modLocation("machines/chemical_generator"), existingFileHelper)
.save(serializer, modLocation("machines/chemical_generator"))
val press = AdvancementBuilder()
.parent(chem)
@ -83,10 +79,10 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
},
)
.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",
russianName = "Двойной стук").make(serializer, existingFileHelper, press, translation)
russianName = "Двойной стук").make(serializer, press, translation)
val scanner = CraftEntry(MItems.MATTER_SCANNER, "Scanning Things that Matter",
russianName = "Сканируем вещи которые материальны")
@ -114,12 +110,12 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
val reconstructor = CraftEntry(MItems.MATTER_RECONSTRUCTOR, "Flipping Hourglass",
russianName = "Переворачиваем песочные часы")
decomposer.make(serializer, existingFileHelper, press, translation).also {
pattern.make(serializer, existingFileHelper, it, translation).also {
scanner.make(serializer, existingFileHelper, it, translation)
panel.make(serializer, existingFileHelper, it, translation)
decomposer.make(serializer, press, translation).also {
pattern.make(serializer, it, translation).also {
scanner.make(serializer, it, translation)
panel.make(serializer, it, translation)
replicator.make(serializer, existingFileHelper, it, translation).also {
replicator.make(serializer, it, translation).also {
AdvancementBuilder()
.parent(it)
.display(
@ -132,8 +128,8 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
},
frameType = FrameType.GOAL
)
.addCriterion("replicate_something", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build(), true))
.save(serializer, modLocation("machines/replicate_something"), existingFileHelper)
.addCriterion("replicate_something", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build(), true).criterion())
.save(serializer, modLocation("machines/replicate_something"))
AdvancementBuilder()
.parent(it)
@ -147,20 +143,20 @@ fun addMachineAdvancements(serializer: Consumer<Advancement>, existingFileHelper
russian("Наблюдайте неудачный результат репликации, где ваш заказ рассыпался в материальную труху")
},
)
.addCriterion("replicate_failure", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build()))
.save(serializer, modLocation("machines/replicate_failure"), existingFileHelper)
.addCriterion("replicate_failure", TakeItemOutOfReplicatorTrigger.Instance(ItemPredicate.Builder.item().of(MItems.MATTER_DUST).build()).criterion())
.save(serializer, modLocation("machines/replicate_failure"))
}
reconstructor.make(serializer, existingFileHelper, it, translation)
reconstructor.make(serializer, it, translation)
}
bottler.make(serializer, existingFileHelper, it, translation)
recycler.make(serializer, existingFileHelper, it, translation)
capacitor.make(serializer, existingFileHelper, it, translation)
bottler.make(serializer, it, translation)
recycler.make(serializer, it, translation)
capacitor.make(serializer, it, translation)
}
counter.make(serializer, existingFileHelper, press, translation).also {
battery.make(serializer, existingFileHelper, it, translation)
counter.make(serializer, press, translation).also {
battery.make(serializer, it, translation)
}
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",
russianName = "Домашняя страница андроидов")
station.make(serializer, existingFileHelper, press, translation).also {
charger.make(serializer, existingFileHelper, it, translation)
station.make(serializer, press, translation).also {
charger.make(serializer, it, translation)
}
CraftEntry(MItems.COBBLESTONE_GENERATOR, "Cobblestone: Infinity + 1",
russianName = "Булыжник: бесконечность + 1",
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",
russianName = "Один большой резистор",
russianSuffix = "Каждый элемент электрической цепи способен испускать свет и тепло, единожды.",
englishSuffix = "Any electrical element can emit light and heat, once.")
.make(serializer, existingFileHelper, press, translation)
.make(serializer, press, translation)
.also {
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",
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 net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.SimpleCookingRecipeBuilder
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
@ -14,7 +15,7 @@ import ru.dbotthepony.mc.otm.registry.MItems
import java.util.*
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)
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}"))
}
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.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.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.ShapelessRecipeBuilder
import net.minecraft.tags.ItemTags
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 java.util.function.Consumer
fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
fun addCraftingTableRecipes(consumer: RecipeOutput) {
val machinesCategory = RecipeCategory.DECORATIONS
MatteryRecipe(MRegistry.CARGO_CRATES.item, category = RecipeCategory.DECORATIONS)
@ -407,7 +408,7 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.unlockedBy(MItemTags.TRITANIUM_INGOTS)
.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)
.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 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)
.rowA(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}"))
}
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)
.row(base, base, base)
.unlockedBy(base)
.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)
.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}"))
}
private fun cut(base: ItemLike, result: ItemLike, amount: Int, consumer: Consumer<FinishedRecipe>) {
private fun cut(base: ItemLike, result: ItemLike, amount: Int, consumer: RecipeOutput) {
SingleItemRecipeBuilder
.stonecutting(Ingredient.of(base), RecipeCategory.BUILDING_BLOCKS, result, amount)
.unlockedBy(base)
.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)
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)
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)
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) {
MatteryRecipe(unrefinedItem, 24)

View File

@ -1,6 +1,6 @@
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.crafting.Ingredient
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.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems
import java.util.function.Consumer
fun addMatterEntanglerRecipes(consumer: Consumer<FinishedRecipe>) {
fun addMatterEntanglerRecipes(consumer: RecipeOutput) {
consumer.accept(
MatterEntanglerRecipe(
modLocation("quantum_capacitor"),
IngredientMatrix.of(
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)),
@ -24,12 +22,11 @@ fun addMatterEntanglerRecipes(consumer: Consumer<FinishedRecipe>) {
Decimal(40),
400.0,
ItemStack(MItems.QUANTUM_CAPACITOR, 2)
).energetic().toFinished()
).energetic().toFinished(modLocation("quantum_capacitor"))
)
consumer.accept(
MatterEntanglerRecipe(
modLocation("quantum_battery"),
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(MItems.BATTERY_DENSE), Ingredient.of(MItems.QUANTUM_TRANSCEIVER), Ingredient.of(MItems.BATTERY_DENSE)),
@ -38,6 +35,6 @@ fun addMatterEntanglerRecipes(consumer: Consumer<FinishedRecipe>) {
Decimal(120),
600.0,
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
import com.google.gson.JsonObject
import net.minecraft.advancements.Advancement
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.ShapedRecipeBuilder
import net.minecraft.resources.ResourceLocation
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.level.ItemLike
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.set
import ru.dbotthepony.mc.otm.core.toJsonStrict
import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
@ -54,6 +57,18 @@ private data class RecipeRow(
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
*/
@ -62,11 +77,11 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
private val rows = arrayOfNulls<RecipeRow>(3)
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))
}
fun unlockedBy(name: String, trigger: CriterionTriggerInstance): MatteryRecipe {
fun unlockedBy(name: String, trigger: Criterion<*>): MatteryRecipe {
unlockedBy.add(name to trigger)
return this
}
@ -163,55 +178,55 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
return this
}
private fun filter(consumer: Consumer<FinishedRecipe>): Consumer<FinishedRecipe> {
private fun filter(): (FinishedRecipe) -> FinishedRecipe {
if (upgradeSource != null) {
check(copyPaths.isNotEmpty()) { "Defined upgrade recipe without nbt migration operations" }
return Consumer {
consumer.accept(object : FinishedRecipe by it {
return {
object : FinishedRecipe by it {
override fun serializeRecipeData(pJson: JsonObject) {
it.serializeRecipeData(pJson)
pJson["copyPaths"] = copyPaths.stream().map { it.serialize() }.collect(JsonArrayCollector)
pJson["copyPaths"] = UpgradeRecipe.COPY_PATHS_CODEC.toJsonStrict(copyPaths)
pJson["source"] = upgradeSource!!.toString()
}
override fun getType(): RecipeSerializer<*> {
return UpgradeRecipe.Companion
override fun type(): RecipeSerializer<*> {
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()
if (name != null) {
builder.save(filter(consumer), modLocation(
builder.save(consumer.map(filter()), modLocation(
if (result.asItem().registryName!!.namespace == OverdriveThatMatters.MOD_ID)
"${result.asItem().registryName!!.path}_$name"
else
"${result.asItem().registryName!!.namespace}_${result.asItem().registryName!!.path}_$name"
))
} else {
builder.save(filter(consumer))
builder.save(consumer.map(filter()))
}
}
fun build(consumer: Consumer<FinishedRecipe>, name: ResourceLocation) {
buildRegular().save(filter(consumer), name)
fun build(consumer: RecipeOutput, name: ResourceLocation) {
buildRegular().save(consumer.map(filter()), name)
}
fun buildEnergetic(consumer: Consumer<FinishedRecipe>, name: String? = null) {
build({
consumer.accept(object : FinishedRecipe by it {
override fun getType(): RecipeSerializer<*> {
fun buildEnergetic(consumer: RecipeOutput, name: String? = null) {
build(consumer.map {
object : FinishedRecipe by it {
override fun type(): RecipeSerializer<*> {
return EnergyContainerRecipe.Companion
}
})
}
}, name)
}

View File

@ -1,5 +1,8 @@
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.EntityPredicate
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.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeBuilder
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.RecipeProvider
import net.minecraft.resources.ResourceLocation
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.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
import java.util.LinkedList
import java.util.*
import java.util.function.Consumer
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())
}
fun has(p_125978_: ItemLike): InventoryChangeTrigger.TriggerInstance {
fun has(p_125978_: ItemLike): Criterion<InventoryChangeTrigger.TriggerInstance> {
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())
}
fun inventoryTrigger(vararg p_126012_: ItemPredicate): InventoryChangeTrigger.TriggerInstance {
return InventoryChangeTrigger.TriggerInstance(
ContextAwarePredicate.ANY,
fun inventoryTrigger(vararg p_126012_: ItemPredicate): Criterion<InventoryChangeTrigger.TriggerInstance> {
return CriteriaTriggers.INVENTORY_CHANGED.createCriterion(InventoryChangeTrigger.TriggerInstance(
Optional.empty(),
MinMaxBounds.Ints.ANY,
MinMaxBounds.Ints.ANY,
MinMaxBounds.Ints.ANY,
p_126012_
)
ImmutableList.copyOf(p_126012_)
))
}
fun <T : RecipeBuilder> T.unlockedBy(item: ItemLike): T {
@ -75,7 +79,7 @@ class MatteryRecipeProvider(generatorIn: DataGenerator) : RecipeProvider(generat
return this
}
override fun buildRecipes(callback: Consumer<FinishedRecipe>) {
override fun buildRecipes(callback: RecipeOutput) {
for (lambda in callbacks) {
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) {
exec { _, consumer ->
consumer.accept(PlatePressRecipe(
modLocation("plates/$id"),
Ingredient.of(ItemTags.create(ResourceLocation("forge", "ingots/$id"))),
Ingredient.of(ItemTags.create(ResourceLocation("forge", "plates/$id"))),
count,
workTicks,
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) {
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.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.SimpleCookingRecipeBuilder
import net.minecraft.world.item.crafting.Ingredient
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 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.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
import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
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 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) {
if (targetColor == null) continue
consumer.accept(PainterRecipe(
modLocation("painter/" + targetItem.recipeName),
Ingredient.of(items.entries.stream().filter { it.key != null && it.key != targetColor }.map { ItemStack(it.value) }),
ItemStack(targetItem),
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)
if (cleaning)
@ -39,37 +39,34 @@ private fun generate(consumer: Consumer<FinishedRecipe>, default: Item, items: M
if (k1 == null) continue
consumer.accept(PainterRecipe(
modLocation("painter/" + default.recipeName + "/" + v1.recipeName),
Ingredient.of(default),
ItemStack(v1),
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(
modLocation("painter/cleaning/" + to.recipeName),
Ingredient.of(from.entries.stream().filter { it.key != null }.map { ItemStack(it.value) }),
ItemStack(to),
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) {
val (baseColor, stripe) = colors
consumer.accept(PainterRecipe(
modLocation("painter/stripes_$name/${baseColor.getName()}/${stripe.getName()}"),
Ingredient.of(base[baseColor]),
ItemStack(stripeItem),
setOf(stripe)
).toFinished())
).toFinished(modLocation("painter/stripes_$name/${baseColor.getName()}/${stripe.getName()}")))
}
}
fun addPainterRecipes(consumer: Consumer<FinishedRecipe>) {
fun addPainterRecipes(consumer: RecipeOutput) {
generate(consumer, mapOf(
DyeColor.WHITE to Items.WHITE_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.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.ShapelessRecipeBuilder
import net.minecraft.world.item.DyeColor
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 java.util.function.Consumer
fun addShapelessRecipes(consumer: Consumer<FinishedRecipe>) {
for (color in DyeColor.values()) {
fun addShapelessRecipes(consumer: RecipeOutput) {
for (color in DyeColor.entries) {
ShapelessRecipeBuilder(RecipeCategory.TRANSPORTATION, MItems.CARGO_CRATE_MINECARTS[color]!!, 1)
.requires(Items.MINECART)
.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.minecraftforge.event.AddReloadListenerEvent
import net.minecraftforge.event.OnDatapackSyncEvent
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager
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.network.GenericNetworkChannel
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 java.util.LinkedList
import java.util.function.Supplier
object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_android_research"), Iterable<AndroidResearchType> {
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")
}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
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.isActuallyEmpty
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.isClient
import java.util.Optional
@ -393,7 +392,7 @@ class AndroidResearchType(
ListCodec(
RecordCodecBuilder.create<Pair<Ingredient, Int>> {
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 }
).apply(it, ::Pair)
}

View File

@ -5,7 +5,7 @@ import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.entity.Entity
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.android.AndroidSwitchableFeature
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.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.UUID
import java.util.WeakHashMap
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) {
companion object {
@ -46,8 +44,7 @@ class ItemEntityDataPacket(val itemUUID: Int, val owner: UUID? = null, val age:
buff.writeBoolean(hasPickupDelay)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
override fun play(context: CustomPayloadEvent.Context) {
val level = minecraft.player?.level() as ClientLevel? ?: return
val entity = level.getEntity(itemUUID) as ItemEntity? ?: return
datatable[entity] = SharedItemEntityData(owner, age, lifespan, hasPickupDelay)

View File

@ -1,23 +1,17 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource
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 net.minecraftforge.event.network.CustomPayloadEvent
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
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.config.AndroidConfig
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.Vector
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.MatteryPlayerNetworkChannel
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.MSoundEvents
import java.util.function.Supplier
@ -37,16 +28,13 @@ object TriggerJumpBoostPacket : MatteryPacket {
// no op
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val mattery = context.sender?.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val mattery = context.sender?.matteryPlayer ?: return
if (!mattery.isAndroid)
return@enqueueWork
return
val feature = mattery.getFeature(AndroidFeatures.JUMP_BOOST) ?: return@enqueueWork
val feature = mattery.getFeature(AndroidFeatures.JUMP_BOOST) ?: return
if (feature.isActive && feature.cooldown <= 4 && mattery.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, false)) {
feature.putOnCooldown()
@ -62,7 +50,6 @@ object TriggerJumpBoostPacket : MatteryPacket {
}
}
}
}
}
class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.JUMP_BOOST, capability) {

View File

@ -1,54 +1,41 @@
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 net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.monster.warden.Warden
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import net.minecraftforge.event.network.CustomPayloadEvent
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
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.core.math.Vector
import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.core.math.getEllipsoidBlockPositions
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.core.damageType
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
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.plus
import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.core.math.roundToIntVector
import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
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.core.position
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.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.registry.AndroidFeatures
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.MatteryDamageSource
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger
import java.util.function.Supplier
import kotlin.math.pow
import kotlin.math.roundToInt
@ -57,10 +44,8 @@ object TriggerShockwavePacket : MatteryPacket {
// no op
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) as ShockwaveFeature? ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) ?: return
if (!shockwave.isOnCooldown && shockwave.isActive && shockwave.airTicks > 0) {
onceServer { // delay by one tick so player update its position as well
@ -68,7 +53,6 @@ object TriggerShockwavePacket : MatteryPacket {
}
}
}
}
}
class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.SHOCKWAVE, capability) {

View File

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

View File

@ -77,7 +77,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
.recipeManager
.byType(MRecipes.MATTER_ENTANGLER)
.values
.any { it.preemptivelyMatches(shadow, level!!) }
.any { it.value.preemptivelyMatches(shadow, level!!) }
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
@ -139,9 +139,9 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
.recipeManager
.byType(MRecipes.MATTER_ENTANGLER)
.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.setChanged()
@ -149,8 +149,8 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
return JobContainer.success(
Job(
result,
recipe.matter,
recipe.ticks * MachinesConfig.MATTER_ENTANGLER.workTimeMultiplier
recipe.value.matter,
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 (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)
val poweredView = poweredView

View File

@ -92,8 +92,8 @@ class PlatePressBlockEntity(
.byType(MRecipes.PLATE_PRESS)
.values
.iterator()
.filter { it.matches(inputContainer, id) }
.maybe() ?: return JobContainer.noItem()
.filter { it.value.matches(inputContainer, id) }
.maybe()?.value ?: return JobContainer.noItem()
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()
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)
inputs[id][0].shrink(toProcess)
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())
}

View File

@ -520,10 +520,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return JobContainer.noItem()
} else {
val actual = recipe.get()
val item = actual.assemble(input, level.registryAccess())
val item = actual.value.assemble(input, level.registryAccess())
input[0].shrink(1)
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)
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) {
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
return
}
@ -226,7 +226,7 @@ fun onMouseScrolled(event: MouseScrolled.Pre) {
val slot = screen.slotUnderMouse
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
return
}

View File

@ -54,7 +54,6 @@ import java.util.*
import kotlin.collections.ArrayDeque
import kotlin.collections.List
import kotlin.collections.MutableSet
import kotlin.collections.indices
import kotlin.collections.isNotEmpty
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_)
}
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) {
if (panel.mouseScrolledChecked(p_94686_, p_94687_, p_94688_)) {
if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) {
return true
}
}
@ -648,7 +647,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
val mouseYf = mouseY.toFloat()
// dark background
this.renderBackground(graphics)
this.renderBackground(graphics, mouseX, mouseY, partialTick)
super.hoveredSlot = null
var hovered = false

View File

@ -123,8 +123,8 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
buttons.forEach { it.remove() }
buttons.clear()
for (recipe in menu.possibleRecipes.sortedWith(CreativeMenuItemComparator.map { it.output.item })) {
object : LargeRectangleButtonPanel<PainterScreen>(this@PainterScreen, canvas.canvas, icon = ItemStackIcon(recipe.output, 14f, 14f).fixed()) {
for (recipe in menu.possibleRecipes.sortedWith(CreativeMenuItemComparator.map { it.value.output.item })) {
object : LargeRectangleButtonPanel<PainterScreen>(this@PainterScreen, canvas.canvas, icon = ItemStackIcon(recipe.value.output, 14f, 14f).fixed()) {
init {
buttons.add(this)
dockRight = 1f
@ -132,13 +132,13 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
}
override var isDisabled: Boolean
get() = !recipe.canCraft(menu.dyeStoredDirect)
get() = !recipe.value.canCraft(menu.dyeStoredDirect)
set(value) {}
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
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_)
}
override fun mouseScrolled(p_94734_: Double, p_94735_: Double, p_94736_: Double): Boolean {
return this@EditablePanel.mouseScrolled(p_94734_, p_94735_, p_94736_)
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
return this@EditablePanel.mouseScrolled(mouseX, mouseY, scrollY)
}
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
}
val renderX = width.toInt() / 2
val renderY = (height * 0.9f).toInt()
val renderX = this.width.toInt() / 2
val renderY = (this.height * 0.9f).toInt()
InventoryScreen.renderEntityInInventoryFollowsMouse(
graphics,
renderX,
renderY,
this.width.toInt(), this.height.toInt(),
renderScale,
0f,
absoluteX.toInt() + renderX - mouseX,
absoluteY + height * 0.15f - mouseY,
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_)
}
override fun mouseScrolled(p_94734_: Double, p_94735_: Double, p_94736_: Double): Boolean {
return panel.mouseScrolledChecked(p_94734_, p_94735_, p_94736_)
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
return panel.mouseScrolledChecked(mouseX, mouseY, scrollY)
}
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
}
override fun tickInner() {
super.tickInner()
widget?.tick()
}
override fun configureNew(widget: EditBox, recreation: Boolean) {
widget.isFocused = isFocusedThis
}

View File

@ -36,7 +36,8 @@ fun onCuriosSlotModifiersUpdated(event: SlotModifiersUpdatedEvent) {
}
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>> {

View File

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

View File

@ -87,9 +87,9 @@ class JEIPlugin : IModPlugin {
override fun registerRecipes(registration: IRecipeRegistration) {
val level = minecraft.level ?: throw NullPointerException("No ClientLevel. OLOLOLOLOLOLO")
registration.addRecipes(PlatePressRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PLATE_PRESS).filter { !it.isIncomplete })
registration.addRecipes(PainterRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PAINTER).filter { !it.isIncomplete })
registration.addRecipes(MatterEntanglerRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.MATTER_ENTANGLER).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.value.isIncomplete }.map { it.value })
registration.addRecipes(MatterEntanglerRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.MATTER_ENTANGLER).filter { !it.value.isIncomplete }.map { it.value })
}
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.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
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.function.Supplier
@ -226,8 +224,7 @@ class InventoryScrollPacket(val scroll: Int) : MatteryPacket {
}.scroll = scroll
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
override fun play(context: CustomPayloadEvent.Context) {
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.ListTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
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.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.core.nbt.set
import java.util.Arrays
import java.util.LinkedList
import java.util.*
import java.util.function.Consumer
import java.util.function.Supplier
class ItemFilter(
val size: Int,

View File

@ -206,8 +206,8 @@ fun FriendlyByteBuf.readItemType(): Item {
return ForgeRegistries.ITEMS.getValue(readInt()) ?: Items.AIR
}
fun InputStream.readItemType(sizeLimit: NbtAccounter? = null): Item {
return ForgeRegistries.ITEMS.getValue(readVarIntLE(sizeLimit)) ?: Items.AIR
fun InputStream.readItemType(): Item {
return ForgeRegistries.ITEMS.getValue(readVarIntLE()) ?: Items.AIR
}
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.writeDecimal(value: Decimal) = value.write(this)
fun InputStream.readDecimal(sizeLimit: NbtAccounter = NbtAccounter(512L)): Decimal {
val size = readVarIntLE(sizeLimit)
fun InputStream.readDecimal(): Decimal {
val size = readVarIntLE()
require(size >= 0) { "Negative payload size: $size" }
sizeLimit.accountBytes(size.toLong())
val bytes = ByteArray(size)
read(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))
}
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)
if (bytes.isEmpty())
return null
return FastByteArrayInputStream(bytes).readBinaryJson(sizeLimit)
return FastByteArrayInputStream(bytes).readBinaryJson()
}
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 read(stream: InputStream, accounter: NbtAccounter): JsonElement {
override fun read(stream: InputStream): JsonElement {
return JsonNull.INSTANCE
}
},
@ -29,8 +29,7 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
stream.writeDouble(element.asDouble)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
accounter.accountBytes(8L)
override fun read(stream: InputStream): JsonElement {
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)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
accounter.accountBytes(1L)
override fun read(stream: InputStream): JsonElement {
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}")
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return JsonPrimitive(stream.readVarLongLE(accounter))
override fun read(stream: InputStream): JsonElement {
return JsonPrimitive(stream.readVarLongLE())
}
},
@ -66,8 +64,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
stream.writeBinaryString(element.asString)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return JsonPrimitive(stream.readBinaryString(accounter))
override fun read(stream: InputStream): JsonElement {
return JsonPrimitive(stream.readBinaryString())
}
},
@ -76,8 +74,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, OutputStream::writeBinaryJson)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return readArray(stream, accounter, InputStream::readBinaryJson)
override fun read(stream: InputStream): JsonElement {
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 {
val count = stream.readVarIntLE(accounter)
override fun read(stream: InputStream): JsonElement {
val count = stream.readVarIntLE()
if (count == 0) return JsonObject()
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) {
val key = try {
stream.readBinaryString(accounter)
stream.readBinaryString()
} catch(err: Throwable) {
throw JsonSyntaxException("Reading json object at $i", err)
}
try {
build.add(key, stream.readBinaryJson(accounter))
build.add(key, stream.readBinaryJson())
} catch(err: Throwable) {
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)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return readArray(stream, accounter, DOUBLE::read)
override fun read(stream: InputStream): JsonElement {
return readArray(stream, DOUBLE::read)
}
},
@ -133,8 +131,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, INT::write)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return readArray(stream, accounter, INT::read)
override fun read(stream: InputStream): JsonElement {
return readArray(stream, INT::read)
}
},
@ -143,8 +141,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, BOOLEAN::write)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return readArray(stream, accounter, BOOLEAN::read)
override fun read(stream: InputStream): JsonElement {
return readArray(stream, BOOLEAN::read)
}
},
@ -153,8 +151,8 @@ private enum class BinaryElementType(private val predicate: Predicate<JsonElemen
writeArray(stream, element, NULL::write)
}
override fun read(stream: InputStream, accounter: NbtAccounter): JsonElement {
return readArray(stream, accounter, NULL::read)
override fun read(stream: InputStream): JsonElement {
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 {
val count = stream.readVarIntLE(accounter)
protected fun readArray(stream: InputStream, reader: (InputStream) -> JsonElement): JsonArray {
val count = stream.readVarIntLE()
if (count == 0) return JsonArray()
if (count < 0) throw JsonSyntaxException("Tried to read json array with $count elements in it")
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 read(stream: InputStream, accounter: NbtAccounter): JsonElement
abstract fun read(stream: InputStream): JsonElement
companion object {
val cached: ImmutableList<BinaryElementType> = ImmutableList.of(
NULL, DOUBLE, BOOLEAN, INT, STRING, OBJECT,
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
*/
fun InputStream.readBinaryJson(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): JsonElement {
sizeLimit.accountBytes(1L)
fun InputStream.readBinaryJson(): JsonElement {
val id = read() - 1
val reader = BinaryElementType.ordered.getOrNull(id) ?: throw JsonParseException("Unknown element type ${id + 1}")
return reader.read(this, sizeLimit)
val reader = BinaryElementType.entries.getOrNull(id) ?: throw JsonParseException("Unknown element type ${id + 1}")
return reader.read(this)
}

View File

@ -12,8 +12,8 @@ import net.minecraft.nbt.NbtAccounter
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
fun FriendlyByteBuf.readBinaryJson(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18)): JsonElement {
return ByteBufInputStream(this).readBinaryJson(sizeLimit)
fun FriendlyByteBuf.readBinaryJson(): JsonElement {
return ByteBufInputStream(this).readBinaryJson()
}
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()}") }))
}
fun <S> FriendlyByteBuf.readBinaryJsonWithCodec(codec: Codec<S>, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18)): S {
return codec.decode(JsonOps.INSTANCE, readBinaryJson(sizeLimit))
fun <S> FriendlyByteBuf.readBinaryJsonWithCodec(codec: Codec<S>): S {
return codec.decode(JsonOps.INSTANCE, readBinaryJson())
.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> {
return codec.decode(JsonOps.INSTANCE, readBinaryJson(sizeLimit)).map { it.first }
fun <S> FriendlyByteBuf.readBinaryJsonWithCodecIndirect(codec: Codec<S>): DataResult<S> {
return codec.decode(JsonOps.INSTANCE, readBinaryJson()).map { it.first }
}
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 {
NbtIo.read(if (this is DataInputStream) this else DataInputStream(this), accounter)
NbtIo.read(if (this is DataInputStream) this else DataInputStream(this))
} catch (ioexception: 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 {
sizeLimit.accountBytes(1L)
fun InputStream.readItem(): ItemStack {
if (read() == 0) {
return ItemStack.EMPTY
}
sizeLimit.accountBytes(9L)
val item = (ForgeRegistries.ITEMS as ForgeRegistry<Item>).getValue(readInt())
val itemStack = ItemStack(item, readInt())
if (read() != 0) {
itemStack.readShareTag(readNbt(sizeLimit))
itemStack.readShareTag(readNbt())
}
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) {
return FluidStack.EMPTY
} else {
@ -108,7 +105,7 @@ fun InputStream.readFluidStack(sizeLimit: NbtAccounter = NbtAccounter(1L shl 14
val amount = readInt()
if (read() > 0) {
return FluidStack(fluid, amount, readNbt(sizeLimit))
return FluidStack(fluid, amount, readNbt())
} else {
return FluidStack(fluid, amount)
}
@ -122,11 +119,10 @@ fun OutputStream.writeBigDecimal(value: BigDecimal) {
write(bytes)
}
fun InputStream.readBigDecimal(sizeLimit: NbtAccounter = NbtAccounter(512L)): BigDecimal {
fun InputStream.readBigDecimal(): BigDecimal {
val scale = readInt()
val size = readVarIntLE(sizeLimit)
val size = readVarIntLE()
require(size >= 0) { "Negative payload size: $size" }
sizeLimit.accountBytes(size.toLong() + 4L)
val bytes = ByteArray(size)
read(bytes)
return BigDecimal(BigInteger(bytes), scale)
@ -215,8 +211,7 @@ fun InputStream.readFloat() = Float.fromBits(readInt())
fun OutputStream.writeDouble(value: Double) = writeLong(value.toBits())
fun InputStream.readDouble() = Double.fromBits(readLong())
fun InputStream.readVarIntLE(sizeLimit: NbtAccounter? = null): Int {
sizeLimit?.accountBytes(1L)
fun InputStream.readVarIntLE(): Int {
val readFirst = read()
if (readFirst < 0) {
@ -234,7 +229,6 @@ fun InputStream.readVarIntLE(sizeLimit: NbtAccounter? = null): Int {
while (nextBit != 0) {
result = result or (read shl i)
sizeLimit?.accountBytes(1L)
read = read()
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()
require(size >= 0) { "Negative payload size: $size" }
sizeLimit.accountBytes(size.toLong())
val bytes = ByteArray(size)
read(bytes)
return bytes.decodeToString()
@ -329,8 +322,8 @@ fun OutputStream.writeBinaryString(input: String) {
write(bytes)
}
fun InputStream.readResourceLocation(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): ResourceLocation {
return ResourceLocation(readBinaryString(sizeLimit), readBinaryString(sizeLimit))
fun InputStream.readResourceLocation(): ResourceLocation {
return ResourceLocation(readBinaryString(), readBinaryString())
}
fun OutputStream.writeResourceLocation(value: ResourceLocation) {

View File

@ -32,7 +32,7 @@ import kotlin.reflect.KClass
* Also provides [copy] and [compare] methods
*/
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)
/**
@ -51,7 +51,7 @@ interface IStreamCodec<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 copier: ((value: V) -> V) = { it },
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,
copier: ((value: V) -> V) = { it },
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?> {
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V? {
sizeLimit.accountBytes(1L)
return if (stream.read() == 0) null else reader.invoke(stream, sizeLimit)
override fun read(stream: DataInputStream): V? {
return if (stream.read() == 0) null else reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V?) {
@ -88,8 +87,8 @@ class StreamCodec<V>(
}
}
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V {
return reader.invoke(stream, sizeLimit)
override fun read(stream: DataInputStream): V {
return reader.invoke(stream)
}
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> {
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): C {
val size = stream.readVarIntLE(sizeLimit)
override fun read(stream: DataInputStream): C {
val size = stream.readVarIntLE()
if (size <= 0) {
return collectionFactory.invoke(0)
@ -116,7 +115,7 @@ class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStre
val collection = collectionFactory.invoke(size)
for (i in 0 until size) {
collection.add(elementCodec.read(stream, sizeLimit))
collection.add(elementCodec.read(stream))
}
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 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 }
@ -147,18 +146,18 @@ val FluidStackValueCodec = StreamCodec(DataInputStream::readFluidStack, DataOutp
val ItemValueCodec = StreamCodec(DataInputStream::readItemType, DataOutputStream::writeItemType) { a, b -> a === b }
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
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 VarLongValueCodec = StreamCodec(DataInputStream::readVarLongLE, DataOutputStream::writeVarLongLE) { a, b -> a == b }
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
val ResourceLocationValueCodec = StreamCodec(DataInputStream::readResourceLocation, DataOutputStream::writeResourceLocation)
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) })
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) })
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)
}
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V {
val id = stream.readVarIntLE(sizeLimit)
override fun read(stream: DataInputStream): V {
val id = stream.readVarIntLE()
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.DynamicOps
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.network.FriendlyByteBuf
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 kotlin.collections.ArrayDeque
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<*>>(
val empty: 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)
private class CurrentContext {
val idStack = ArrayDeque<ResourceLocation>()
var isNetwork = 0
}
inner class Context {
val id: ResourceLocation
get() = checkNotNull(context.idStack.lastOrNull()) { "Not currently deserializing recipe" }
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())
@ -56,45 +97,30 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
}
}
override fun fromJson(id: ResourceLocation, data: JsonObject): S {
try {
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 codec(): Codec<S> {
return this
}
override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): S? {
override fun fromNetwork(data: FriendlyByteBuf): S? {
try {
context.idStack.addLast(id)
context.isNetwork++
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 {
context.isNetwork--
context.idStack.removeLast()
}
}
override fun toNetwork(data: FriendlyByteBuf, recipe: S) {
try {
context.idStack.addLast(recipe.id)
context.isNetwork++
data.writeBinaryJsonWithCodec(this, recipe)
} finally {
context.isNetwork--
context.idStack.removeLast()
}
}
fun toFinished(recipe: S): FinishedRecipe {
fun toFinished(recipe: S, id: ResourceLocation): FinishedRecipe {
return object : FinishedRecipe {
override fun serializeRecipeData(p_125967_: JsonObject) {
encode(recipe, JsonOps.INSTANCE, p_125967_).get().map(
@ -111,19 +137,15 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
)
}
override fun getId(): ResourceLocation {
return recipe.id
override fun id(): ResourceLocation {
return id
}
override fun getType(): RecipeSerializer<*> {
override fun type(): RecipeSerializer<*> {
return this@Codec2RecipeSerializer
}
override fun serializeAdvancement(): JsonObject? {
return null
}
override fun getAdvancementId(): ResourceLocation? {
override fun advancement(): AdvancementHolder? {
return null
}
}
@ -134,7 +156,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) {
networkIngredientCodec.encode(input, ops, prefix)
} 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) {
networkIngredientCodec.decode(ops, input)
} 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).
* To make it stateless, [ThreadLocal] is used.
*/
private val contextHolder = ThreadLocal<CurrentContext>()
private val context: CurrentContext
get() = contextHolder.getOrSet { CurrentContext() }
private val context by object : ThreadLocal<CurrentContext>() {
override fun initialValue(): 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
import com.mojang.serialization.Codec
import com.mojang.serialization.Dynamic
import com.mojang.serialization.JsonOps
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
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> {
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.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
/**
@ -29,6 +28,12 @@ data class ChanceCondition(val chance: Double) : LootItemCondition, LootItemCond
}
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.LootItemConditionType
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.registry.MLootItemConditions
@ -49,7 +48,7 @@ data class ChanceWithPlaytimeCondition(
}
companion object {
val SERIALIZER = Codec2Serializer<ChanceWithPlaytimeCondition>(
val CODEC: Codec<ChanceWithPlaytimeCondition> by lazy {
RecordCodecBuilder.create {
it.group(
Codec.INT.optionalFieldOf("minPlaytime", 0).forGetter(ChanceWithPlaytimeCondition::minPlaytime),
@ -58,6 +57,6 @@ data class ChanceWithPlaytimeCondition(
Codec.DOUBLE.fieldOf("maxProbability").forGetter(ChanceWithPlaytimeCondition::maxProbability),
).apply(it, ::ChanceWithPlaytimeCondition)
}
)
}
}
}

View File

@ -1,10 +1,6 @@
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.Serializer
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.LootItemCondition
@ -13,7 +9,7 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.data.get
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 {
t[LootContextParams.LAST_DAMAGE_PLAYER]?.matteryPlayer?.let {
return it.hasExopack
@ -26,13 +22,6 @@ object HasExoPackCondition : LootItemCondition, Serializer<HasExoPackCondition>,
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 {
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 ru.dbotthepony.mc.otm.capability.items
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.registry.MLootItemConditions
@ -58,7 +57,7 @@ data class ItemInInventoryCondition(
}
companion object {
val SERIALIZER = Codec2Serializer<ItemInInventoryCondition>(
val CODEC: Codec<ItemInInventoryCondition> by lazy {
RecordCodecBuilder.create {
it.group(
ItemStack.CODEC.fieldOf("item").forGetter(ItemInInventoryCondition::item),
@ -67,6 +66,6 @@ data class ItemInInventoryCondition(
Codec.BOOL.optionalFieldOf("matchCosmetics", false).forGetter(ItemInInventoryCondition::matchCosmetics),
).apply(it, ::ItemInInventoryCondition)
}
)
}
}
}

View File

@ -1,10 +1,6 @@
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.Serializer
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.LootItemCondition
@ -13,7 +9,7 @@ import net.minecraftforge.common.util.FakePlayer
import ru.dbotthepony.mc.otm.data.get
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 {
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
}
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 {
return this
}

View File

@ -1,11 +1,7 @@
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.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.predicates.InvertedLootItemCondition
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.registry.MLootItemConditions
object KilledByRealPlayerOrIndirectly : LootItemCondition, Serializer<KilledByRealPlayerOrIndirectly>, LootItemCondition.Builder {
object KilledByRealPlayerOrIndirectly : LootItemCondition, LootItemCondition.Builder {
override fun test(t: LootContext): Boolean {
if (t.hasParam(LootContextParams.LAST_DAMAGE_PLAYER) && t[LootContextParams.LAST_DAMAGE_PLAYER] !is FakePlayer) {
return true
@ -43,13 +39,6 @@ object KilledByRealPlayerOrIndirectly : LootItemCondition, Serializer<KilledByRe
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 {
return this
}

View File

@ -1,28 +1,23 @@
package ru.dbotthepony.mc.otm.data.loot
import com.google.common.collect.ImmutableList
import com.google.gson.JsonArray
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.ItemStack
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.LootItemFunctionType
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
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.set
import ru.dbotthepony.mc.otm.core.stream
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 java.util.Optional
import java.util.stream.Stream
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
}
companion object : Serializer<CopyTileNbtFunction> {
override fun serialize(
pJson: JsonObject,
pValue: CopyTileNbtFunction,
pSerializationContext: JsonSerializationContext
) {
pJson["filter"] = JsonArray().also { for (v in pValue.filter) it.add(v) }
companion object {
val CODEC: Codec<CopyTileNbtFunction> by lazy {
RecordCodecBuilder.create {
it.group(
Codec.STRING.listOf()
.optionalFieldOf("filter")
.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
import com.google.common.collect.ImmutableList
import com.google.gson.*
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 it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.resources.ResourceLocation
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.LootPool
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.LootModifier
import java.util.Arrays
import java.util.Deque
import java.util.*
import java.util.stream.Stream
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
}
// TODO: remove reflection once Forge implement a way to provide lootpool deserialization context in non-reflective way
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> =
RecordCodecBuilder.create {
codecStart(it).and(
lootPoolCodec.fieldOf("pools").forGetter(LootPoolAppender::pools)
LootPool.CODEC.listOf().fieldOf("pools").forGetter(LootPoolAppender::pools)
).apply(it, ::LootPoolAppender)
}
}

View File

@ -107,7 +107,7 @@ class FluidCapsuleItem(val capacity: IntSupplier) : Item(Properties().stacksTo(6
actionResult.result
} else {
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)
if (!actionResult.isSuccess) return InteractionResultHolder.pass(item)

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.mc.otm.item
import net.minecraft.core.BlockSource
import net.minecraft.core.Direction
import net.minecraft.core.dispenser.BlockSource
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior
import net.minecraft.core.dispenser.DispenseItemBehavior
import net.minecraft.tags.BlockTags
@ -67,11 +67,11 @@ class MinecartCargoCrateItem(val color: DyeColor?) : Item(Properties().stacksTo(
private val default = DefaultDispenseItemBehavior()
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 x = blockSource.x() + direction.stepX.toDouble() * 1.125
val y = floor(blockSource.y()) + direction.stepY.toDouble()
val z = blockSource.z() + direction.stepZ.toDouble() * 1.125
val x = blockSource.pos.x + direction.stepX.toDouble() * 1.125
val y = blockSource.pos.y + direction.stepY.toDouble()
val z = blockSource.pos.z + direction.stepZ.toDouble() * 1.125
val blockpos = blockSource.pos.relative(direction)
val blockstate = level.getBlockState(blockpos)
val railshape =

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.item
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting
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.nbt.mapPresent
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.registry.MItemFunctionTypes
import java.util.Optional
@ -119,8 +119,7 @@ class ProceduralBatteryItem : Item(Properties().stacksTo(1)) {
}
companion object {
val SERIALIZER by lazy {
Codec2Serializer<Randomizer>(
val CODEC: Codec<Randomizer> by lazy {
RecordCodecBuilder.create {
it.group(
DecimalProvider.CODEC.fieldOf("maxBatteryLevel").forGetter(Randomizer::maxBatteryLevel),
@ -129,7 +128,6 @@ class ProceduralBatteryItem : Item(Properties().stacksTo(1)) {
DecimalProvider.CODEC.optionalFieldOf("maxOutput").forGetter(Randomizer::maxOutput),
).apply(it, ::Randomizer)
}
)
}
}
}

View File

@ -7,6 +7,7 @@ import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.util.datafix.DataFixTypes
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
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.event.TickEvent
import net.minecraftforge.event.TickEvent.ServerTickEvent
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.capability.FlowDirection
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.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.packetHandled
import java.util.*
import java.util.function.Function
import java.util.function.Supplier
@ -155,7 +155,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
val clientData = Object2ObjectOpenHashMap<UUID, IValues>()
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 {
@ -377,8 +377,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
buff.writeDecimal(received)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
override fun play(context: CustomPayloadEvent.Context) {
val data = type.clientData.computeIfAbsent(uuid, Function { UnboundValues(it) })
data.energy = energy
data.passed = passed

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.item.exopack
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting
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.nbt.set
import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
import java.util.*
@ -34,14 +34,12 @@ class ProceduralExopackSlotUpgradeItem : AbstractExopackSlotUpgradeItem(defaultP
}
companion object {
val SERIALIZER = Codec2Serializer<Randomizer>(
RecordCodecBuilder.create {
val CODEC: Codec<Randomizer> = RecordCodecBuilder.create {
it.group(
IntProvider.CODEC.fieldOf("slots").forGetter(Randomizer::slots),
IntProvider.CODEC.optionalFieldOf("luck_bias", ConstantInt.ZERO).forGetter(Randomizer::luckBias),
).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.ViewportEvent
import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.network.CustomPayloadEvent
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.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.renderRect
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.math.Angle
import ru.dbotthepony.mc.otm.core.math.RGBAColor
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.ints
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.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.WeaponNetworkChannel
import java.util.*
import java.util.function.Supplier
import kotlin.collections.set
import kotlin.math.PI
import kotlin.math.abs
import kotlin.reflect.KClass
@ -62,17 +60,13 @@ enum class WeaponScopePacket(val scope: Boolean) : MatteryPacket {
buff.writeBoolean(scope)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
override fun play(context: CustomPayloadEvent.Context){
// TODO: Manual synchronization
context.get().enqueueWork {
val stack = context.get().sender!!.mainHandItem
val item = stack.item as? AbstractWeaponItem<*> ?: return@enqueueWork
val stack = context.sender!!.mainHandItem
val item = stack.item as? AbstractWeaponItem<*> ?: return
item.dataTable(stack).wantsToScope = scope
}
}
companion object {
fun read(buff: FriendlyByteBuf) = if (buff.readBoolean()) SCOPE_IN else SCOPE_OUT
@ -86,13 +80,10 @@ enum class WeaponFireInputPacket(val primary: Boolean) : MatteryPacket {
buff.writeBoolean(primary)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
override fun play(context: CustomPayloadEvent.Context){
// TODO: Manual synchronization
context.get().enqueueWork {
val stack = context.get().sender!!.mainHandItem
val item = stack.item as? AbstractWeaponItem<*> ?: return@enqueueWork
val stack = context.sender!!.mainHandItem
val item = stack.item as? AbstractWeaponItem<*> ?: return
// Listen server: client and server thread compete for lock
// so it is very likely item is being in predicted context
@ -100,13 +91,12 @@ enum class WeaponFireInputPacket(val primary: Boolean) : MatteryPacket {
item.dataTable = null
if (primary)
item.tryPrimaryFire(stack, context.get().sender!!)
item.tryPrimaryFire(stack, context.sender!!)
else
item.trySecondaryFire(stack, context.get().sender!!)
item.trySecondaryFire(stack, context.sender!!)
(item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
}
}
companion object {
fun read(buff: FriendlyByteBuf) = if (buff.readBoolean()) PRIMARY else SECONDARY

View File

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

View File

@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableList
import com.mojang.datafixers.util.Pair
import it.unimi.dsi.fastutil.ints.IntArrayList
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.FastByteArrayOutputStream
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.enchantment.EnchantmentHelper.hasBindingCurse
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 ru.dbotthepony.mc.otm.capability.IMatteryUpgrade
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.UpgradeContainer
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.core.GetterSetter
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.MenuNetworkChannel
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.IField
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.IntSupplier
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)
@ -126,18 +119,14 @@ abstract class MatteryMenu(
buff.writeBytes(payload)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val menu = context.sender?.containerMenu as? MatteryMenu ?: return@enqueueWork
if (menu.containerId != containerId || !menu.stillValid(context.sender!!)) return@enqueueWork
val input = menu.playerInputs.getOrNull(inputId) ?: return@enqueueWork
if (!input.test(context.sender)) return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val menu = context.sender?.containerMenu as? MatteryMenu ?: return
if (menu.containerId != containerId || !menu.stillValid(context.sender!!)) return
val input = menu.playerInputs.getOrNull(inputId) ?: return
if (!input.test(context.sender)) return
input.invoke(input.codec.read(DataInputStream(FastByteArrayInputStream(payload))))
}
}
}
/**
* Client->Server input
@ -239,8 +228,6 @@ abstract class MatteryMenu(
protected var inventorySlotIndexStart = 0
protected var inventorySlotIndexEnd = 0
private val playerPacketDistributor = PacketDistributor.PLAYER.with { player as ServerPlayer }
fun addFilterSlots(slots: ItemFilter): List<GetterSetter<ItemStack>> {
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.ClickType
import net.minecraft.world.item.ItemStack
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.addSorted
@ -42,17 +42,14 @@ data class ItemViewInteractPacket(val stackID: Int, val type: ClickType, val act
buff.writeEnum(action)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val sender = context.sender ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val sender = context.sender ?: return
if (!sender.isSpectator) {
sender.resetLastActionTime()
(sender.containerMenu as? INetworkedItemViewProvider)?.networkedItemView?.playerInteract(this)
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): ItemViewInteractPacket {
@ -62,14 +59,11 @@ data class ItemViewInteractPacket(val stackID: Int, val type: ClickType, val act
}
abstract class NetworkedItemViewPacket : MatteryPacket {
final override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork
final override fun play(context: CustomPayloadEvent.Context) {
val get = Minecraft.getInstance().player?.containerMenu ?: return
val view = (get as? INetworkedItemViewProvider)?.networkedItemView ?: throw IllegalStateException("No NetworkedItemView is present in currently open menu")
action(view)
}
}
protected abstract fun action(view: NetworkedItemView)
}
@ -249,7 +243,7 @@ class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val isRemote: Bo
fun network() {
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) {
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.item.DyeColor
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.capability.matteryPlayer
import ru.dbotthepony.mc.otm.container.MatteryContainer
@ -42,7 +43,7 @@ class PainterMenu(
val inputContainer = MatteryContainer(::rescan, 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() } }
val isBulk = BooleanInputWithFeedback(this, tile?.let { it::isBulk })
@ -53,7 +54,7 @@ class PainterMenu(
val inputSlot = object : MatterySlot(inputContainer, 0) {
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) {
if (itemStack.isNotEmpty) {
lastRecipe?.dyes?.let { tile?.takeDyes(it) }
lastRecipe?.value?.dyes?.let { tile?.takeDyes(it) }
if (isBulk.value) {
val found = player.matteryPlayer!!.inventoryAndExopack
@ -116,11 +117,11 @@ class PainterMenu(
}
val listeners = ISubscriptable.Impl<Unit>()
val possibleRecipes = ArrayList<PainterRecipe>()
val possibleRecipes = ArrayList<RecipeHolder<PainterRecipe>>()
private fun rescan() {
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)
if (tile !is PainterBlockEntity) return
@ -129,10 +130,10 @@ class PainterMenu(
} else {
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()
} else {
outputContainer[0] = recipe.assemble(inputContainer, inventory.player.level().registryAccess())
outputContainer[0] = recipe.value.assemble(inputContainer, inventory.player.level().registryAccess())
lastRecipe = recipe
}
}

View File

@ -52,7 +52,7 @@ class MatterEntanglerMenu(
.recipeManager
.byType(MRecipes.MATTER_ENTANGLER)
.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.Player
import net.minecraft.world.item.Item
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.block.entity.matter.MatterPanelBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.*
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.map
import ru.dbotthepony.mc.otm.core.math.Decimal
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.codec
import ru.dbotthepony.mc.otm.core.util.writeCollection
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
@ -30,20 +27,16 @@ import ru.dbotthepony.mc.otm.registry.MMenus
import java.util.*
import java.util.function.Predicate
import java.util.function.Supplier
import kotlin.collections.ArrayList
class CancelTaskPacket(val id: UUID) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
buff.writeUUID(id)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
override fun play(context: CustomPayloadEvent.Context) {
val sender = context.sender!!
(sender.containerMenu as? MatterPanelMenu)?.receiveTaskCancel(sender, id)
}
}
companion object {
fun read(buff: FriendlyByteBuf): CancelTaskPacket {
@ -58,10 +51,8 @@ class PatternsChangePacket(val isUpdate: Boolean, val patterns: Collection<Patte
buff.writeCollection(patterns, PatternState::write)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return
if (isUpdate) {
menu.networkPatternsUpdated(patterns)
@ -69,7 +60,6 @@ class PatternsChangePacket(val isUpdate: Boolean, val patterns: Collection<Patte
menu.networkPatternsRemoved(patterns)
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): PatternsChangePacket {
@ -84,10 +74,8 @@ class TasksChangePacket(val isUpdate: Boolean, val tasks: Collection<Replication
buff.writeCollection(tasks, ReplicationTask::write)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val menu = minecraft.player?.containerMenu as? MatterPanelMenu ?: return
if (isUpdate) {
menu.networkTasksUpdated(tasks)
@ -95,7 +83,6 @@ class TasksChangePacket(val isUpdate: Boolean, val tasks: Collection<Replication
menu.networkTasksRemoved(tasks)
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): TasksChangePacket {
@ -112,15 +99,12 @@ class ReplicationRequestPacket(val id: UUID, amount: Int) : MatteryPacket {
buff.writeInt(amount)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val sender = context.sender ?: return@enqueueWork
val menu = sender.containerMenu as? MatterPanelMenu ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val sender = context.sender ?: return
val menu = sender.containerMenu as? MatterPanelMenu ?: return
menu.requestReplication(sender, id, amount)
}
}
companion object {
fun read(buff: FriendlyByteBuf): ReplicationRequestPacket {
@ -339,7 +323,7 @@ class MatterPanelMenu(
}
private fun sendNetwork(packet: Any) {
MenuNetworkChannel.send(PacketDistributor.PLAYER.with { inventory.player as ServerPlayer }, packet)
MenuNetworkChannel.send(inventory.player, packet)
}
fun fullPatternBroadcast() {

View File

@ -9,8 +9,8 @@ import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.NetworkDirection
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager
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.matter.MatterManager
import java.util.*
import java.util.function.Supplier
import kotlin.collections.ArrayList
class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : MatteryPacket {
@ -31,14 +30,11 @@ class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : Matter
buff.writeDouble(z)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
override fun play(context: CustomPayloadEvent.Context) {
minecraft.player?.level()?.let {
makeSmoke(x, y, z, it.random, it)
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): SmokeParticlesPacket {
@ -104,13 +100,9 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
}
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
override fun play(context: CustomPayloadEvent.Context) {
execute()
}
}
companion object {
private val backlog = WeakHashMap<Level, Object2ObjectOpenHashMap<BlockPos, ArrayList<BlockEntitySyncPacket>>>()
@ -128,15 +120,15 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
}
object GenericNetworkChannel : MatteryNetworkChannel(
version = "4",
version = 5,
name = "generic"
) {
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) {
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() {
@ -145,7 +137,7 @@ object GenericNetworkChannel : MatteryNetworkChannel(
add(BlockEntitySyncPacket::class.java, BlockEntitySyncPacket.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(SmokeParticlesPacket::class, SmokeParticlesPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)

View File

@ -1,67 +1,48 @@
package ru.dbotthepony.mc.otm.network
import java.util.function.Function
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.TickEvent.ServerTickEvent
import net.minecraftforge.event.server.ServerStoppedEvent
import net.minecraftforge.event.server.ServerStoppingEvent
import net.minecraftforge.event.network.CustomPayloadEvent
import net.minecraftforge.network.Channel
import net.minecraftforge.network.ChannelBuilder
import net.minecraftforge.network.NetworkDirection
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.NetworkRegistry
import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.network.simple.SimpleChannel
import net.minecraftforge.network.SimpleChannel
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
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.locks.LockSupport
import java.util.function.BiConsumer
import java.util.function.Supplier
import java.util.function.Function
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 {
fun write(buff: FriendlyByteBuf)
fun play(context: Supplier<NetworkEvent.Context>)
fun play(context: CustomPayloadEvent.Context)
}
abstract class MatteryNetworkChannel(val version: String, val name: String) {
val channel: SimpleChannel = NetworkRegistry.newSimpleChannel(
ResourceLocation(OverdriveThatMatters.MOD_ID, name),
{ version },
{ it == version },
{ it == version },
)
abstract class MatteryNetworkChannel(val version: Int, val name: String) {
val channel: SimpleChannel = ChannelBuilder
.named(ResourceLocation(OverdriveThatMatters.MOD_ID, name))
.acceptedVersions(Channel.VersionTest.exact(version))
.networkProtocolVersion(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) {
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) {
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
}
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) {
@ -78,7 +59,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
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) {
@ -86,7 +67,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
}
fun sendNow(distributor: PacketDistributor.PacketTarget, packet: Any) {
channel.send(distributor, packet)
channel.send(packet, distributor)
}
private var nextNetworkPacketID = 0
@ -95,31 +76,43 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
packetClass: Class<T>,
writer: BiConsumer<T, FriendlyByteBuf>,
reader: Function<FriendlyByteBuf, T>,
handler: BiConsumer<T, Supplier<NetworkEvent.Context>>,
direction: NetworkDirection? = null
handler: BiConsumer<T, CustomPayloadEvent.Context>,
direction: NetworkDirection? = null,
handleOnMainThread: Boolean = true,
) {
if (nextNetworkPacketID >= 256) {
throw IndexOutOfBoundsException("Network message ID overflow!")
}
@Suppress("INACCESSIBLE_TYPE")
channel.registerMessage(nextNetworkPacketID++, packetClass, writer, reader, handler, if (direction == null) Optional.empty() else Optional.of(direction))
val builder = channel.messageBuilder(packetClass, direction)
if (handleOnMainThread) {
builder.consumerMainThread(handler)
} else {
builder.consumerNetworkThread(handler)
}
builder.encoder(writer)
builder.decoder(reader)
builder.add()
}
fun <T : MatteryPacket> add(
packetClass: Class<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(
packetClass: KClass<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)
@ -150,7 +143,7 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
LockSupport.park()
} else {
try {
task.channel.send(task.target, task.packet)
task.channel.send(task.packet, task.target)
} catch(err: Throwable) {
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.world.entity.player.Inventory
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_SERVER
import net.minecraftforge.network.NetworkEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.android.AndroidActiveFeature
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 java.io.ByteArrayInputStream
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 {
constructor(stream: FastByteArrayOutputStream, isPublic: Boolean, target: UUID? = null) : this(stream.array, stream.length, isPublic, target)
@ -55,15 +54,13 @@ class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int, val isPubl
buff.writeBytes(bytes, 0, length)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.get().enqueueWork {
override fun play(context: CustomPayloadEvent.Context) {
val player: MatteryPlayerCapability
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 {
player = minecraft.player?.matteryPlayer ?: return@enqueueWork
player = minecraft.player?.matteryPlayer ?: return
}
if (isPublic) {
@ -72,7 +69,6 @@ class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int, val isPubl
player.synchronizer.read(ByteArrayInputStream(bytes, 0, length))
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): MatteryPlayerFieldPacket {
@ -93,19 +89,16 @@ class AndroidResearchRequestPacket(val type: AndroidResearchType) : MatteryPacke
buff.writeUtf(type.id.toString())
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val ply = context.get().sender ?: return@enqueueWork
if (ply.isSpectator) return@enqueueWork
val android = ply.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val ply = context.sender ?: return
if (ply.isSpectator) return
val android = ply.matteryPlayer ?: return
if (!android.isAndroid || ply.containerMenu !is AndroidStationMenu)
return@enqueueWork
return
android.getResearch(type).research()
}
}
companion object {
fun read(buff: FriendlyByteBuf): AndroidResearchRequestPacket {
@ -121,16 +114,11 @@ class AndroidResearchSyncPacket(val type: AndroidResearchType, val dataList: Fas
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")
context.get().packetHandled = true
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
val android = minecraft.player?.matteryPlayer ?: return
android.getResearch(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
}
}
companion object {
fun read(buff: FriendlyByteBuf): AndroidResearchSyncPacket {
@ -149,16 +137,11 @@ class AndroidFeatureSyncPacket(val type: AndroidFeatureType<*>, val dataList: Fa
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")
context.get().packetHandled = true
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
val android = minecraft.player?.matteryPlayer ?: return
android.computeIfAbsent(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
}
}
companion object {
fun read(buff: FriendlyByteBuf): AndroidFeatureSyncPacket {
@ -175,14 +158,10 @@ class AndroidFeatureRemovePacket(val type: AndroidFeatureType<*>) : MatteryPacke
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val android = minecraft.player?.matteryPlayer ?: return
android.removeFeature(type)
}
}
companion object {
fun read(buff: FriendlyByteBuf): AndroidFeatureRemovePacket {
@ -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
MatteryGUI.iteration = iteration
@ -234,17 +213,14 @@ class ExopackCarriedPacket(val itemStack: ItemStack, val containerState: Int) :
buff.writeInt(containerState)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val mattery = minecraft.player?.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val mattery = minecraft.player?.matteryPlayer ?: return
if (mattery.hasExopack) {
mattery.exoPackMenu.carried = itemStack
mattery.exoPackMenu.stateId = containerState
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): ExopackCarriedPacket {
@ -260,33 +236,29 @@ class ExopackSlotPacket(val slotId: Int, val itemStack: ItemStack, val container
buff.writeInt(containerState)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
override fun play(context: CustomPayloadEvent.Context) {
if (slotId < 0) {
LOGGER.error("Unknown slot with ID {} in exosuit menu", slotId)
return
}
context.enqueueWork {
val mattery = minecraft.player?.matteryPlayer ?: return@enqueueWork
val mattery = minecraft.player?.matteryPlayer ?: return
if (mattery.hasExopack) {
if (slotId >= mattery.exoPackMenu.slots.size) {
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
return
mattery.exoPackMenu.slots[slotId].set(itemStack)
mattery.exoPackMenu.stateId = containerState
}
}
}
companion object {
private val LOGGER = LogManager.getLogger()
@ -309,16 +281,13 @@ class ExopackMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack,
buff.writeInt(containerState)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val mattery = minecraft.player?.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val mattery = minecraft.player?.matteryPlayer ?: return
if (mattery.hasExopack) {
mattery.exoPackMenu.initializeContents(containerState, slots, carried)
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): ExopackMenuInitPacket {
@ -340,17 +309,14 @@ class ExopackMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack,
object ExopackMenuOpen : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val player = context.sender ?: return@enqueueWork
val mattery = player.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val player = context.sender ?: return
val mattery = player.matteryPlayer ?: return
if (mattery.hasExopack) {
player.containerMenu = mattery.exoPackMenu
}
}
}
}
class SwitchAndroidFeaturePacket(val type: AndroidFeatureType<*>, val newState: Boolean) : MatteryPacket {
@ -359,17 +325,14 @@ class SwitchAndroidFeaturePacket(val type: AndroidFeatureType<*>, val newState:
buff.writeBoolean(newState)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val matteryPlayer = context.sender?.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val matteryPlayer = context.sender?.matteryPlayer ?: return
if (!matteryPlayer.isAndroid) {
return@enqueueWork
return
}
val feature = matteryPlayer.getFeature(type) ?: return@enqueueWork
val feature = matteryPlayer.getFeature(type) ?: return
if (feature is AndroidActiveFeature && feature.allowToSwitchByPlayer && (!matteryPlayer.ply.isSpectator || feature.allowToSwitchByPlayerWhileSpectator)) {
matteryPlayer.features
@ -382,7 +345,6 @@ class SwitchAndroidFeaturePacket(val type: AndroidFeatureType<*>, val newState:
feature.isActive = newState
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): SwitchAndroidFeaturePacket {
@ -396,23 +358,19 @@ class ActivateAndroidFeaturePacket(val type: AndroidFeatureType<*>) : MatteryPac
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val matteryPlayer = context.sender?.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val matteryPlayer = context.sender?.matteryPlayer ?: return
if (!matteryPlayer.isAndroid || matteryPlayer.ply.isSpectator) {
return@enqueueWork
return
}
val feature = matteryPlayer.getFeature(type) as? AndroidActiveFeature ?: return@enqueueWork
val feature = matteryPlayer.getFeature(type) as? AndroidActiveFeature ?: return
if (feature.isActive || feature.allowToSwitchByPlayer) {
feature.activate(false)
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): ActivateAndroidFeaturePacket {
@ -430,19 +388,16 @@ class PickItemFromInventoryPacket(
buff.writeVarInt(sourceExosuitSlot)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
context.enqueueWork {
val player = context.sender ?: return@enqueueWork
val mattery = player.matteryPlayer ?: return@enqueueWork
override fun play(context: CustomPayloadEvent.Context) {
val player = context.sender ?: return
val mattery = player.matteryPlayer ?: return
if (!mattery.hasExopack || sourceExosuitSlot !in 0 until mattery.exopackContainer.containerSize) {
return@enqueueWork
return
}
if (!Inventory.isHotbarSlot(targetHotbarSlot)) {
return@enqueueWork
return
}
player.inventory.selected = targetHotbarSlot
@ -454,7 +409,6 @@ class PickItemFromInventoryPacket(
player.connection.send(ClientboundSetCarriedItemPacket(targetHotbarSlot))
}
}
companion object {
fun read(buff: FriendlyByteBuf): PickItemFromInventoryPacket {
@ -468,7 +422,7 @@ class GlitchPacket(val millis: Long) : MatteryPacket {
buff.writeVarLong(millis)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
GlitchRenderer.glitchFor(millis)
}
@ -487,7 +441,7 @@ class ShockwaveEffectPacket(val pos: Vector) : MatteryPacket {
buff.writeDouble(pos.z)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
ShockwaveRenderer.handle(this)
}
@ -502,7 +456,7 @@ class ShockwaveEffectPacket(val pos: Vector) : MatteryPacket {
object DisplayExopackPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
context.sender?.matteryPlayer?.isExopackVisible = true
}
@ -511,7 +465,7 @@ object DisplayExopackPacket : MatteryPacket {
object HideExopackPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
context.sender?.matteryPlayer?.isExopackVisible = false
}
@ -520,7 +474,7 @@ object HideExopackPacket : MatteryPacket {
object EnableExopackGlowPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
context.sender?.matteryPlayer?.exopackGlows = true
}
@ -529,7 +483,7 @@ object EnableExopackGlowPacket : MatteryPacket {
object DisableExopackGlowPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
context.sender?.matteryPlayer?.exopackGlows = false
}
@ -538,7 +492,7 @@ object DisableExopackGlowPacket : MatteryPacket {
object ResetExopackColorPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
context.sender?.matteryPlayer?.exopackColor = null
}
@ -551,7 +505,7 @@ data class SetExopackColorPacket(val color: RGBAColor) : MatteryPacket {
buff.writeFloat(color.blue)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
context.sender?.matteryPlayer?.exopackColor = color
}
@ -568,11 +522,10 @@ data class ExopackSmokePacket(val player: UUID) : MatteryPacket {
buff.writeUUID(player)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
override fun play(context: CustomPayloadEvent.Context) {
context.packetHandled = true
// minecraft.player?.level()?.getPlayerByUUID(player)?.matteryPlayer?.spawnExopackSmoke = true
context.enqueueWork {
minecraft.player?.level()?.getPlayerByUUID(player)?.let { ply ->
if (ply != minecraft.player || minecraft.gameRenderer.mainCamera.isDetached) {
var (x, y, z) = ply.position
@ -599,8 +552,6 @@ data class ExopackSmokePacket(val player: UUID) : MatteryPacket {
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): ExopackSmokePacket {
return ExopackSmokePacket(buff.readUUID())
@ -609,7 +560,7 @@ data class ExopackSmokePacket(val player: UUID) : MatteryPacket {
}
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
version = "6",
version = 7,
name = "player"
) {
fun register() {

View File

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

View File

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

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.recipe
import com.google.gson.JsonObject
import com.mojang.serialization.Codec
import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess
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.stream
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 {
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_)
}
override fun getId(): ResourceLocation {
return parent.id
}
override fun category(): CraftingBookCategory {
return parent.category()
}
@ -105,12 +104,16 @@ class EnergyContainerRecipe(val parent: ShapedRecipe) : CraftingRecipe, IShapedR
}
companion object : RecipeSerializer<EnergyContainerRecipe> {
override fun fromJson(id: ResourceLocation, data: JsonObject): EnergyContainerRecipe {
return EnergyContainerRecipe(ShapedRecipe.Serializer.SHAPED_RECIPE.fromJson(id, data))
private val codec by lazy {
RecipeSerializer.SHAPED_RECIPE.codec().xmap(::EnergyContainerRecipe, EnergyContainerRecipe::parent)
}
override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): EnergyContainerRecipe? {
return ShapedRecipe.Serializer.SHAPED_RECIPE.fromNetwork(id, data)?.let(::EnergyContainerRecipe)
override fun codec(): Codec<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) {

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.recipe
import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess
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.isNotEmpty
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.registry.MItems
class ExplosiveHammerPrimingRecipe(private val _id: ResourceLocation, val payload: Ingredient) : CraftingRecipe {
class ExplosiveHammerPrimingRecipe(val payload: Ingredient) : CraftingRecipe {
override fun isIncomplete(): Boolean {
return payload.isActuallyEmpty
}
override fun getId(): ResourceLocation {
return _id
}
override fun isSpecial(): Boolean {
return true
}
@ -61,7 +59,7 @@ class ExplosiveHammerPrimingRecipe(private val _id: ResourceLocation, val payloa
}
override fun getSerializer(): RecipeSerializer<*> {
return Companion
return CODEC
}
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)
}
val finishedRecipe = object : FinishedRecipe {
override fun serializeRecipeData(pJson: JsonObject) {
pJson["payload"] = payload.toJson()
}
fun toFinished(id: ResourceLocation) = CODEC.toFinished(this, id)
override fun getId(): ResourceLocation {
return _id
companion object {
val CODEC = Codec2RecipeSerializer<ExplosiveHammerPrimingRecipe> { p ->
RecordCodecBuilder.create {
it.group(
p.ingredients.fieldOf("payload").forGetter(ExplosiveHammerPrimingRecipe::payload)
).apply(it, ::ExplosiveHammerPrimingRecipe)
}
override fun getType(): RecipeSerializer<*> {
return Companion
}
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(
private val id: ResourceLocation,
override val ingredients: IIngredientMatrix,
override val matter: Decimal,
override val ticks: Double,
@ -73,10 +72,6 @@ open class MatterEntanglerRecipe(
return result
}
override fun getId(): ResourceLocation {
return id
}
override fun getSerializer(): RecipeSerializer<*> {
return SERIALIZER
}
@ -97,8 +92,8 @@ open class MatterEntanglerRecipe(
return true
}
fun toFinished(): FinishedRecipe {
return SERIALIZER.toFinished(this)
fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this, id)
}
fun energetic() = Energy(this)
@ -113,8 +108,8 @@ open class MatterEntanglerRecipe(
}
}
fun toFinished(): FinishedRecipe {
return ENERGY_SERIALIZER.toFinished(this)
fun toFinished(id: ResourceLocation): FinishedRecipe {
return ENERGY_SERIALIZER.toFinished(this, id)
}
override fun getSerializer(): RecipeSerializer<*> {
@ -131,8 +126,8 @@ open class MatterEntanglerRecipe(
}
}
fun toFinished(): FinishedRecipe {
return MATTER_SERIALIZER.toFinished(this)
fun toFinished(id: ResourceLocation): FinishedRecipe {
return MATTER_SERIALIZER.toFinished(this, id)
}
override fun getSerializer(): RecipeSerializer<*> {
@ -150,7 +145,7 @@ open class MatterEntanglerRecipe(
ItemStack.CODEC.fieldOf("result").forGetter(MatterEntanglerRecipe::result),
Codec.STRING.optionalFieldOf("uuidKey", "uuid").forGetter(MatterEntanglerRecipe::uuidKey),
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.RecipeType
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.container.get
import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.tagNotNull
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.minRange
import ru.dbotthepony.mc.otm.registry.MRecipes
@ -29,17 +27,15 @@ import java.util.EnumMap
import java.util.function.Predicate
class PainterRecipe(
private val id: ResourceLocation,
val input: Ingredient,
val output: ItemStack,
val dyes: Map<DyeColor, Int>
) : Recipe<Container> {
constructor(
id: ResourceLocation,
input: Ingredient,
output: ItemStack,
dyes: Set<DyeColor>
) : this(id, input, output, dyes.associateWith { 1 })
) : this(input, output, dyes.associateWith { 1 })
fun canCraft(storedDyes: Map<DyeColor, Int>): Boolean {
if (isIncomplete) return false
@ -96,10 +92,6 @@ class PainterRecipe(
return output
}
override fun getId(): ResourceLocation {
return id
}
override fun getSerializer(): RecipeSerializer<*> {
return SERIALIZER
}
@ -108,8 +100,8 @@ class PainterRecipe(
return MRecipes.PAINTER
}
fun toFinished(): FinishedRecipe {
return SERIALIZER.toFinished(this)
fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this, id)
}
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.unboundedMap(DyeColor.CODEC, Codec.INT.minRange(1)) to Predicate { true }
).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.core.registryName
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import ru.dbotthepony.mc.otm.data.IngredientCodec
import ru.dbotthepony.mc.otm.data.minRange
class PlatePressRecipe(
private val id: ResourceLocation,
val input: Ingredient,
val output: Ingredient,
val count: Int = 1,
@ -70,15 +68,13 @@ class PlatePressRecipe(
override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int) = true
override fun getResultItem(registry: RegistryAccess): ItemStack = outputStack
override fun getId() = id
override fun getSerializer(): RecipeSerializer<*> {
return SERIALIZER
}
override fun getType(): RecipeType<PlatePressRecipe> = MRecipes.PLATE_PRESS
fun toFinished() = SERIALIZER.toFinished(this)
fun toFinished(id: ResourceLocation) = SERIALIZER.toFinished(this, id)
companion object {
val SERIALIZER = Codec2RecipeSerializer<PlatePressRecipe> { context ->
@ -89,7 +85,7 @@ class PlatePressRecipe(
Codec.INT.minRange(1).optionalFieldOf("count", 1).forGetter(PlatePressRecipe::count),
Codec.INT.minRange(0).optionalFieldOf("workTime", 200).forGetter(PlatePressRecipe::workTime),
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.gson.JsonObject
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.RegistryAccess
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.GsonHelper
import net.minecraft.util.StringRepresentable
import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack
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.writeBinaryJson
import ru.dbotthepony.mc.otm.core.collect.stream
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import java.util.stream.Stream
class UpgradeRecipe(
@ -34,6 +38,8 @@ class UpgradeRecipe(
copyPaths: Stream<Op>,
val source: ResourceLocation,
) : 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 {
return parent.matches(p_44002_, p_44003_)
}
@ -70,10 +76,6 @@ class UpgradeRecipe(
return parent.toastSymbol
}
override fun getId(): ResourceLocation {
return parent.id
}
override fun isIncomplete(): Boolean {
return parent.isIncomplete
}
@ -86,42 +88,39 @@ class UpgradeRecipe(
return parent.category()
}
enum class OpType {
enum class OpType : StringRepresentable {
DIRECT {
override fun deserialize(obj: JsonObject): Op {
return Direct(GsonHelper.getAsString(obj, "path"))
override val codec: Codec<Direct> = RecordCodecBuilder.create {
it.group(
Codec.STRING.fieldOf("path").forGetter(Direct::path)
).apply(it, ::Direct)
}
}, INDIRECT {
override fun deserialize(obj: JsonObject): Op {
return Indirect(GsonHelper.getAsString(obj, "source"), GsonHelper.getAsString(obj, "destination"))
override val codec: Codec<Indirect> = RecordCodecBuilder.create {
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('.')
override val type: OpType
get() = OpType.DIRECT
override fun serialize(json: JsonObject) {
json["path"] = JsonPrimitive("path")
}
override fun apply(source: CompoundTag, destination: CompoundTag) {
var a = source
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 splitDestination = pathDestination.split('.')
override val type: OpType
get() = OpType.INDIRECT
override fun serialize(json: JsonObject) {
json["source"] = JsonPrimitive(pathSource)
json["destination"] = JsonPrimitive(pathDestination)
}
override fun apply(source: CompoundTag, destination: CompoundTag) {
var a = source
var b = destination
@ -219,36 +213,23 @@ class UpgradeRecipe(
}
override fun getSerializer(): RecipeSerializer<UpgradeRecipe> {
return Companion
return CODEC
}
companion object : RecipeSerializer<UpgradeRecipe> {
fun deserializeOp(json: JsonObject): Op {
return OpType.valueOf(GsonHelper.getAsString(json, "type")).deserialize(json)
companion object {
val COPY_PATHS_CODEC: Codec<List<Op>> = StringRepresentable
.fromEnum(OpType::values)
.dispatch({ it.type }, { it.codec })
.listOf()
val CODEC = Codec2RecipeSerializer<UpgradeRecipe> { p ->
RecordCodecBuilder.create {
it.group(
p.wrap(ShapedRecipe.Serializer.SHAPED_RECIPE).fieldOf("parent").forGetter(UpgradeRecipe::parent),
COPY_PATHS_CODEC.fieldOf("copyPaths").forGetter(UpgradeRecipe::copyPaths),
ResourceLocation.CODEC.fieldOf("source").forGetter(UpgradeRecipe::source)
).apply(it, ::UpgradeRecipe)
}
override fun fromJson(id: ResourceLocation, data: JsonObject): UpgradeRecipe {
return UpgradeRecipe(
ShapedRecipe.Serializer.SHAPED_RECIPE.fromJson(id, data),
GsonHelper.getAsJsonArray(data, "copyPaths").stream().map { deserializeOp(it as JsonObject) },
ResourceLocation(GsonHelper.getAsString(data, "source"))
)
}
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 {
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 PROCEDURAL_BATTERY: LootItemFunctionType by registry.register(MNames.PROCEDURAL_BATTERY) { LootItemFunctionType(ProceduralBatteryItem.Randomizer.SERIALIZER) }
val PROCEDURAL_EXOPACK_UPGRADE: LootItemFunctionType by registry.register("exopack_upgrade") { LootItemFunctionType(ProceduralExopackSlotUpgradeItem.Randomizer.SERIALIZER) }
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.CODEC) }
val PROCEDURAL_EXOPACK_UPGRADE: LootItemFunctionType by registry.register("exopack_upgrade") { LootItemFunctionType(ProceduralExopackSlotUpgradeItem.Randomizer.CODEC) }
internal fun register(bus: IEventBus) {
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.registries.DeferredRegister
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.HasExoPackCondition
import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition
@ -16,12 +17,12 @@ import ru.dbotthepony.mc.otm.data.condition.ChanceCondition
object MLootItemConditions {
private val registry = DeferredRegister.create(Registries.LOOT_CONDITION_TYPE, OverdriveThatMatters.MOD_ID)
val HAS_EXOPACK: LootItemConditionType by registry.register("has_exopack") { LootItemConditionType(HasExoPackCondition) }
val CHANCE_WITH_PLAYTIME: LootItemConditionType by registry.register("chance_with_playtime") { LootItemConditionType(ChanceWithPlaytimeCondition.SERIALIZER) }
val ITEM_IN_INVENTORY: LootItemConditionType by registry.register("item_in_inventory") { LootItemConditionType(ItemInInventoryCondition.SERIALIZER) }
val KILLED_BY_REAL_PLAYER: LootItemConditionType by registry.register("killed_by_real_player") { LootItemConditionType(KilledByRealPlayer) }
val KILLED_BY_REAL_PLAYER_OR_INDIRECTLY: LootItemConditionType by registry.register("killed_by_real_player_or_indirectly") { LootItemConditionType(KilledByRealPlayerOrIndirectly) }
val CHANCE: LootItemConditionType by registry.register("chance") { LootItemConditionType(ChanceCondition.SERIALIZER) }
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.CODEC) }
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(SingletonCodec(KilledByRealPlayer)) }
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.CODEC) }
internal fun register(bus: IEventBus) {
registry.register(bus)

View File

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

View File

@ -290,28 +290,28 @@ object MRegistry {
private fun initializeCommon(event: FMLCommonSetupEvent) {
event.enqueueWork {
CriteriaTriggers.register(BlackHoleTrigger)
CriteriaTriggers.register(BecomeAndroidTrigger)
CriteriaTriggers.register(BecomeAndroidDeathTrigger)
CriteriaTriggers.register(BecomeAndroidSleepTrigger)
CriteriaTriggers.register(BecomeHumaneTrigger)
CriteriaTriggers.register(AndroidResearchTrigger)
CriteriaTriggers.register(ShockwaveDamageMobTrigger)
CriteriaTriggers.register(ShockwaveTrigger)
CriteriaTriggers.register(AndroidBatteryTrigger)
CriteriaTriggers.register(NanobotsArmorTrigger)
CriteriaTriggers.register(FallDampenersSaveTrigger)
CriteriaTriggers.register(EnderTeleporterFallDeathTrigger)
CriteriaTriggers.register(KillAsAndroidTrigger)
CriteriaTriggers.register(AndroidTravelUnderwater)
CriteriaTriggers.register(NailedEntityTrigger)
CriteriaTriggers.register(ExopackObtainedTrigger)
CriteriaTriggers.register(ExopackGainedSmeltingTrigger)
CriteriaTriggers.register(ExopackGainedCraftingTrigger)
CriteriaTriggers.register(ExopackGainedEnderAccessTrigger)
CriteriaTriggers.register(ExopackSlotsExpandedTrigger)
CriteriaTriggers.register(ExopackBatterySlotTrigger)
CriteriaTriggers.register(TakeItemOutOfReplicatorTrigger)
CriteriaTriggers.register(BlackHoleTrigger.id.toString(), BlackHoleTrigger)
CriteriaTriggers.register(BecomeAndroidTrigger.id.toString(), BecomeAndroidTrigger)
CriteriaTriggers.register(BecomeAndroidDeathTrigger.id.toString(), BecomeAndroidDeathTrigger)
CriteriaTriggers.register(BecomeAndroidSleepTrigger.id.toString(), BecomeAndroidSleepTrigger)
CriteriaTriggers.register(BecomeHumaneTrigger.id.toString(), BecomeHumaneTrigger)
CriteriaTriggers.register(AndroidResearchTrigger.id.toString(), AndroidResearchTrigger)
CriteriaTriggers.register(ShockwaveDamageMobTrigger.id.toString(), ShockwaveDamageMobTrigger)
CriteriaTriggers.register(ShockwaveTrigger.id.toString(), ShockwaveTrigger)
CriteriaTriggers.register(AndroidBatteryTrigger.id.toString(), AndroidBatteryTrigger)
CriteriaTriggers.register(NanobotsArmorTrigger.id.toString(), NanobotsArmorTrigger)
CriteriaTriggers.register(FallDampenersSaveTrigger.id.toString(), FallDampenersSaveTrigger)
CriteriaTriggers.register(EnderTeleporterFallDeathTrigger.id.toString(), EnderTeleporterFallDeathTrigger)
CriteriaTriggers.register(KillAsAndroidTrigger.id.toString(), KillAsAndroidTrigger)
CriteriaTriggers.register(AndroidTravelUnderwater.id.toString(), AndroidTravelUnderwater)
CriteriaTriggers.register(NailedEntityTrigger.id.toString(), NailedEntityTrigger)
CriteriaTriggers.register(ExopackObtainedTrigger.id.toString(), ExopackObtainedTrigger)
CriteriaTriggers.register(ExopackGainedSmeltingTrigger.id.toString(), ExopackGainedSmeltingTrigger)
CriteriaTriggers.register(ExopackGainedCraftingTrigger.id.toString(), ExopackGainedCraftingTrigger)
CriteriaTriggers.register(ExopackGainedEnderAccessTrigger.id.toString(), ExopackGainedEnderAccessTrigger)
CriteriaTriggers.register(ExopackSlotsExpandedTrigger.id.toString(), ExopackSlotsExpandedTrigger)
CriteriaTriggers.register(ExopackBatterySlotTrigger.id.toString(), ExopackBatterySlotTrigger)
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.JsonPrimitive
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidResearchType
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.set
import java.util.Optional
import java.util.function.Predicate
object AndroidResearchTrigger : SimpleCriterionTrigger<AndroidResearchTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research")
override fun getId(): ResourceLocation {
return ID
}
val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research")
override fun createInstance(
p_66248_: JsonObject,
p_286603_: ContextAwarePredicate,
p_286603_: Optional<ContextAwarePredicate>,
p_66250_: DeserializationContext
): 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)
override fun test(t: AndroidResearchType): Boolean {
return research == null || t.id == research
}
override fun serializeToJson(p_16979_: SerializationContext): JsonObject {
return super.serializeToJson(p_16979_).also {
override fun serializeToJson(): JsonObject {
return super.serializeToJson().also {
if (research != null)
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.JsonParseException
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.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters
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>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_walk_underwater")
val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_walk_underwater")
override fun getId(): ResourceLocation {
return ID
}
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"))
override fun createInstance(pJson: JsonObject, pPlayer: Optional<ContextAwarePredicate>, pContext: DeserializationContext): Instance {
return codec.fromJson(pJson, pPlayer, pContext)
}
fun trigger(player: ServerPlayer, travelled: Double) {
@ -26,11 +29,20 @@ object AndroidTravelUnderwater : SimpleCriterionTrigger<AndroidTravelUnderwater.
}
}
class Instance(val distanceToTravel: Double) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) {
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
return super.serializeToJson(pConditions).also {
it["distance_to_travel"] = JsonPrimitive(distanceToTravel)
val codec = Codec2TriggerSerializer<Instance> { p ->
RecordCodecBuilder.create {
it.group(
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.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.SerializationContext
import net.minecraft.advancements.critereon.SimpleCriterionTrigger
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.fromJsonStrict
import ru.dbotthepony.mc.otm.core.toJsonStrict
import java.util.Optional
val ExopackObtainedTrigger = SingletonTrigger(ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_obtained"))
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"))
object ExopackSlotsExpandedTrigger : SimpleCriterionTrigger<ExopackSlotsExpandedTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_expanded")
override fun getId(): ResourceLocation {
return ID
}
val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "exopack_expanded")
val codec: Codec<Instance> = RecordCodecBuilder.create {
it.group(
@ -39,18 +36,20 @@ object ExopackSlotsExpandedTrigger : SimpleCriterionTrigger<ExopackSlotsExpanded
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_)
}
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 {
require(minGained >= 0) { "Invalid minGained $minGained" }
require(minTotal >= 0) { "Invalid minTotal $minTotal" }
}
override fun serializeToJson(p_16979_: SerializationContext): JsonObject {
override fun serializeToJson(): JsonObject {
return codec.toJsonStrict(this) as JsonObject
}
fun criterion() = Criterion(ExopackSlotsExpandedTrigger, this)
}
}

View File

@ -1,54 +1,62 @@
package ru.dbotthepony.mc.otm.triggers
import com.google.gson.JsonObject
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.LivingEntity
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 val ID: ResourceLocation
abstract val id: ResourceLocation
override fun getId(): ResourceLocation {
return ID
}
override fun createInstance(
final override fun createInstance(
p_66248_: JsonObject,
p_286603_: ContextAwarePredicate,
p_286603_: Optional<ContextAwarePredicate>,
p_66250_: DeserializationContext
): Instance {
return Instance(
EntityPredicate.fromJson(p_66248_, "entity_predicate", p_66250_),
(p_66248_["damage"] as? JsonObject)?.let(DamagePredicate::fromJson) ?: DamagePredicate.ANY
)
return codec.fromJson(p_66248_, p_286603_, p_66250_)
}
fun trigger(player: ServerPlayer, entity: LivingEntity, damage: Float, damageSource: DamageSource) {
val context = EntityPredicate.createContext(player, entity)
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(
val predicate: ContextAwarePredicate = ContextAwarePredicate.ANY,
val damagePredicate: DamagePredicate = DamagePredicate(
val predicate: Optional<ContextAwarePredicate> = Optional.empty(),
val damagePredicate: Optional<DamagePredicate> = Optional.of(DamagePredicate(
MinMaxBounds.Doubles.atLeast(1.0),
MinMaxBounds.Doubles.atLeast(1.0),
EntityPredicate.ANY,
null,
DamageSourcePredicate.ANY
)
) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) {
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
return super.serializeToJson(pConditions).also {
it["entity_predicate"] = predicate.toJson(pConditions)
it["damage"] = damagePredicate.serializeToJson()
}
Optional.empty(),
Optional.empty(),
Optional.empty()
)),
player: Optional<ContextAwarePredicate> = Optional.empty()
) : AbstractCriterionTriggerInstance(player) {
override fun serializeToJson(): JsonObject {
return codec.toJson(this)
}
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.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.advancements.critereon.SerializationContext
import net.minecraft.advancements.critereon.SimpleCriterionTrigger
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.core.fromJsonStrict
import ru.dbotthepony.mc.otm.core.toJsonStrict
import ru.dbotthepony.mc.otm.data.ItemPredicateCodec
class ItemTrigger(val ID: ResourceLocation) : SimpleCriterionTrigger<ItemTrigger.Instance>() {
override fun getId(): ResourceLocation {
return ID
}
import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import java.util.Optional
class ItemTrigger(val id: ResourceLocation) : SimpleCriterionTrigger<ItemTrigger.Instance>() {
fun trigger(player: ServerPlayer, item: ItemStack) {
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 ->
RecordCodecBuilder.create {
it.group(
ItemPredicateCodec.fieldOf("predicate").forGetter(Instance::predicate),
ItemPredicate.CODEC.fieldOf("predicate").forGetter(Instance::predicate),
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.JsonObject
import com.google.gson.JsonSyntaxException
import net.minecraft.advancements.Criterion
import net.minecraft.advancements.critereon.*
import net.minecraft.resources.ResourceLocation
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.stream
import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.Optional
import java.util.function.Predicate
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 {
return ID
}
override fun createInstance(pJson: JsonObject, pPlayer: ContextAwarePredicate, pContext: DeserializationContext): Instance {
override fun createInstance(pJson: JsonObject, pPlayer: Optional<ContextAwarePredicate>, pContext: DeserializationContext): Instance {
return Instance(
predicate = EntityPredicate.fromJson(pJson, "predicate", pContext),
playerPredicate = pPlayer,
@ -164,16 +162,18 @@ object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instan
}
class Instance(
val predicate: ContextAwarePredicate = ContextAwarePredicate.ANY,
val predicate: Optional<ContextAwarePredicate> = Optional.empty(),
val featurePredicate: FeaturePredicate = Always,
playerPredicate: ContextAwarePredicate = ContextAwarePredicate.ANY,
) : AbstractCriterionTriggerInstance(ID, playerPredicate) {
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
return super.serializeToJson(pConditions).also {
it["predicate"] = predicate.toJson(pConditions)
playerPredicate: Optional<ContextAwarePredicate> = Optional.empty(),
) : AbstractCriterionTriggerInstance(playerPredicate) {
override fun serializeToJson(): JsonObject {
return super.serializeToJson().also {
predicate.ifPresent { p -> it["predicate"] = p.toJson() }
it["feature_predicate"] = featurePredicate.toJson()
}
}
fun criterion() = Criterion(KillAsAndroidTrigger, this)
}
fun onKill(event: LivingDeathEvent) {
@ -187,7 +187,7 @@ object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instan
val context = EntityPredicate.createContext(killer, event.entity)
trigger(killer) {
it.predicate.matches(context) &&
it.predicate.map { it.matches(context) }.orElse(true) &&
it.featurePredicate.test(data)
}
}

View File

@ -17,8 +17,10 @@ import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.PlayerAdvancements
import net.minecraft.server.level.ServerPlayer
import net.minecraft.tags.TagKey
import net.minecraft.world.Container
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.matteryPlayer
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.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty
import java.util.Optional
import java.util.stream.Collectors
import kotlin.jvm.optionals.getOrNull
/**
* This object detours all necessary InventoryChangeTrigger methods
@ -86,14 +90,14 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
nodes.add(Node(
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 },
{ inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> mutableListOf(item.item) }))
nodes.add(Node(
DefaultStrategy,
{ predicates.map { it.tag } },
{ v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.`is`(v) },
{ predicates.map { it.tag as Optional<TagKey<Item>> } },
{ 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)) }))
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>) {
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>) {
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) {
for (l in v as Set<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>) {
// переделываем matches у InventoryTriggerInstance
with (l.triggerInstance) {
with (l.trigger) {
if (
this.slotsFull.matches(slotsFull) &&
this.slotsEmpty.matches(slotsEmpty) &&
@ -212,10 +216,6 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
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>) {
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
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
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.MinMaxBounds.Doubles
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import java.util.Optional
object NanobotsArmorTrigger : SimpleCriterionTrigger<NanobotsArmorTrigger.Instance>() {
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor")
override fun getId(): ResourceLocation {
return ID
}
val id = ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor")
override fun createInstance(
p_66248_: JsonObject,
p_286603_: ContextAwarePredicate,
p_286603_: Optional<ContextAwarePredicate>,
p_66250_: DeserializationContext
): Instance {
return Instance(
Doubles.fromJson(p_66248_["predicate"])
)
return codec.fromJson(p_66248_, p_286603_, p_66250_)
}
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) {
trigger(player) { it.predicate.matches(damageAbsorbed) }
}
class Instance(val predicate: Doubles) : AbstractCriterionTriggerInstance(ID, ContextAwarePredicate.ANY) {
override fun serializeToJson(p_16979_: SerializationContext): JsonObject {
return super.serializeToJson(p_16979_).also {
it["predicate"] = predicate.serializeToJson()
}
class Instance(val predicate: Doubles, player: Optional<ContextAwarePredicate> = Optional.empty()) : AbstractCriterionTriggerInstance(player) {
override fun serializeToJson(): JsonObject {
return codec.toJson((this))
}
fun criterion() = Criterion(NanobotsArmorTrigger, this)
}
}

View File

@ -4,5 +4,5 @@ import net.minecraft.resources.ResourceLocation
import ru.dbotthepony.mc.otm.OverdriveThatMatters
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
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.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.SimpleCriterionTrigger
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.mc.otm.data.Codec2TriggerSerializer
import java.util.Optional
class SingletonTrigger(val ID: ResourceLocation) : SimpleCriterionTrigger<AbstractCriterionTriggerInstance>() {
override fun getId(): ResourceLocation {
return ID
}
override fun createInstance(p_66248_: JsonObject, p_286603_: ContextAwarePredicate, p_66250_: DeserializationContext): AbstractCriterionTriggerInstance {
return instance
class SingletonTrigger(val id: ResourceLocation) : SimpleCriterionTrigger<AbstractCriterionTriggerInstance>() {
override fun createInstance(p_66248_: JsonObject, p_286603_: Optional<ContextAwarePredicate>, p_66250_: DeserializationContext): AbstractCriterionTriggerInstance {
return codec.fromJson(p_66248_, p_286603_, p_66250_)
}
fun trigger(player: ServerPlayer) {
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