Item repairer recipe

This commit is contained in:
DBotThePony 2023-03-24 23:28:06 +07:00
parent d1978d7e04
commit 66140d33a2
Signed by: DBot
GPG Key ID: DCC23B5715498507
6 changed files with 324 additions and 22 deletions

View File

@ -8,12 +8,14 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.item.crafting.Ingredient
import net.minecraftforge.common.Tags import net.minecraftforge.common.Tags
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.registry.MItemTags import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.modLocation import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
import java.util.function.Consumer import java.util.function.Consumer
fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) { fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
@ -295,4 +297,15 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.rowB(Tags.Items.RODS_WOODEN) .rowB(Tags.Items.RODS_WOODEN)
.rowB(Tags.Items.RODS_WOODEN) .rowB(Tags.Items.RODS_WOODEN)
.build(consumer) .build(consumer)
MatteryRecipe(MItems.ITEM_REPAIRER, category = machinesCategory)
.setUpgradeSource(MItems.MATTER_REPLICATOR)
.addUpgradeOps(
UpgradeRecipe.Indirect("BlockEntityTag.${MatteryBlockEntity.ENERGY_KEY}", "BlockEntityTag.energy"),
UpgradeRecipe.Indirect("BlockEntityTag.${MatteryBlockEntity.MATTER_STORAGE_KEY}", "BlockEntityTag.matter"),
)
.row(MItemTags.ADVANCED_CIRCUIT, Tags.Items.GEMS_EMERALD, MItemTags.ADVANCED_CIRCUIT)
.row(MItems.ELECTRIC_PARTS, MItems.MATTER_REPLICATOR, MItems.ELECTRIC_PARTS)
.row(MItems.ELECTROMAGNET, MItems.ELECTROMAGNET, MItems.ELECTROMAGNET)
.build(consumer)
} }

View File

@ -1,13 +1,11 @@
package ru.dbotthepony.mc.otm.datagen.recipes package ru.dbotthepony.mc.otm.datagen.recipes
import com.google.common.collect.ImmutableList import com.google.gson.JsonObject
import net.minecraft.advancements.CriterionTriggerInstance import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeBuilder
import net.minecraft.data.recipes.RecipeCategory import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.ShapedRecipeBuilder import net.minecraft.data.recipes.ShapedRecipeBuilder
import net.minecraft.data.recipes.ShapelessRecipeBuilder
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
@ -15,8 +13,11 @@ import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.item.crafting.RecipeSerializer import net.minecraft.world.item.crafting.RecipeSerializer
import net.minecraft.world.level.ItemLike import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.collect.JsonArrayCollector
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
import java.util.function.Consumer import java.util.function.Consumer
private interface RecipeCell { private interface RecipeCell {
@ -116,7 +117,7 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
} }
} }
fun build(consumer: Consumer<FinishedRecipe>, name: String? = null) { private fun buildRegular(): ShapedRecipeBuilder {
if (index == 0) { if (index == 0) {
throw NoSuchElementException("No recipe rows were defined") throw NoSuchElementException("No recipe rows were defined")
} }
@ -140,15 +141,62 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
builder.unlockedBy(a, b) builder.unlockedBy(a, b)
} }
return builder
}
private var source: ResourceLocation? = null
private val copyPaths = ArrayList<UpgradeRecipe.Op>()
fun setUpgradeSource(source: ResourceLocation): MatteryRecipe {
this.source = source
return this
}
fun setUpgradeSource(source: ItemLike): MatteryRecipe {
this.source = source.asItem().registryName!!
return this
}
fun addUpgradeOps(vararg operations: UpgradeRecipe.Op): MatteryRecipe {
for (op in operations) copyPaths.add(op)
return this
}
private fun filter(consumer: Consumer<FinishedRecipe>): Consumer<FinishedRecipe> {
if (source != null) {
check(copyPaths.isNotEmpty()) { "Defined upgrade recipe without nbt migration operations" }
return Consumer {
consumer.accept(object : FinishedRecipe by it {
override fun serializeRecipeData(pJson: JsonObject) {
it.serializeRecipeData(pJson)
pJson["copyPaths"] = copyPaths.stream().map { it.serialize() }.collect(JsonArrayCollector)
pJson["source"] = source!!.toString()
}
override fun getType(): RecipeSerializer<*> {
return UpgradeRecipe.Companion
}
})
}
}
return consumer
}
fun build(consumer: Consumer<FinishedRecipe>, name: String? = null) {
val builder = buildRegular()
if (name != null) { if (name != null) {
builder.save(consumer, ResourceLocation(OverdriveThatMatters.MOD_ID, builder.save(filter(consumer), ResourceLocation(OverdriveThatMatters.MOD_ID,
if (result.asItem().registryName!!.namespace == OverdriveThatMatters.MOD_ID) if (result.asItem().registryName!!.namespace == OverdriveThatMatters.MOD_ID)
"${result.asItem().registryName!!.path}_$name" "${result.asItem().registryName!!.path}_$name"
else else
"${result.asItem().registryName!!.namespace}_${result.asItem().registryName!!.path}_$name" "${result.asItem().registryName!!.namespace}_${result.asItem().registryName!!.path}_$name"
)) ))
} else { } else {
builder.save(consumer) builder.save(filter(consumer))
} }
} }

View File

@ -11,6 +11,7 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe; import ru.dbotthepony.mc.otm.recipe.EnergyContainerRecipe;
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe; import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe;
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipeFactory; import ru.dbotthepony.mc.otm.recipe.PlatePressRecipeFactory;
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe;
public class MRecipes { public class MRecipes {
public static class MatteryRecipeType<T extends Recipe<?>> implements RecipeType<T> { public static class MatteryRecipeType<T extends Recipe<?>> implements RecipeType<T> {
@ -28,6 +29,7 @@ public class MRecipes {
public static final MatteryRecipeType<PlatePressRecipe> PLATE_PRESS = new MatteryRecipeType<>(OverdriveThatMatters.loc(MNames.PLATE_PRESS)); public static final MatteryRecipeType<PlatePressRecipe> PLATE_PRESS = new MatteryRecipeType<>(OverdriveThatMatters.loc(MNames.PLATE_PRESS));
public static final MatteryRecipeType<PlatePressRecipe> ENERGY_CONTAINER = new MatteryRecipeType<>(OverdriveThatMatters.loc("energy_container")); public static final MatteryRecipeType<PlatePressRecipe> ENERGY_CONTAINER = new MatteryRecipeType<>(OverdriveThatMatters.loc("energy_container"));
public static final MatteryRecipeType<PlatePressRecipe> UPGRADE = new MatteryRecipeType<>(OverdriveThatMatters.loc("upgrade"));
private static final DeferredRegister<RecipeSerializer<?>> serializerRegistry = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, OverdriveThatMatters.MOD_ID); private static final DeferredRegister<RecipeSerializer<?>> serializerRegistry = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, OverdriveThatMatters.MOD_ID);
private static final DeferredRegister<RecipeType<?>> typeRegistry = DeferredRegister.create(ForgeRegistries.RECIPE_TYPES, OverdriveThatMatters.MOD_ID); private static final DeferredRegister<RecipeType<?>> typeRegistry = DeferredRegister.create(ForgeRegistries.RECIPE_TYPES, OverdriveThatMatters.MOD_ID);
@ -35,8 +37,11 @@ public class MRecipes {
static { static {
serializerRegistry.register(MNames.PLATE_PRESS, () -> PlatePressRecipeFactory.INSTANCE); serializerRegistry.register(MNames.PLATE_PRESS, () -> PlatePressRecipeFactory.INSTANCE);
serializerRegistry.register(ENERGY_CONTAINER.name.getPath(), () -> EnergyContainerRecipe.Companion); serializerRegistry.register(ENERGY_CONTAINER.name.getPath(), () -> EnergyContainerRecipe.Companion);
serializerRegistry.register(UPGRADE.name.getPath(), () -> UpgradeRecipe.Companion);
typeRegistry.register(MNames.PLATE_PRESS, () -> PLATE_PRESS); typeRegistry.register(MNames.PLATE_PRESS, () -> PLATE_PRESS);
typeRegistry.register(ENERGY_CONTAINER.name.getPath(), () -> ENERGY_CONTAINER); typeRegistry.register(ENERGY_CONTAINER.name.getPath(), () -> ENERGY_CONTAINER);
typeRegistry.register(UPGRADE.name.getPath(), () -> UPGRADE);
} }
public static void register(IEventBus bus) { public static void register(IEventBus bus) {

View File

@ -0,0 +1,31 @@
package ru.dbotthepony.mc.otm.core.collect
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import java.util.function.BiConsumer
import java.util.function.BinaryOperator
import java.util.function.Function
import java.util.function.Supplier
import java.util.stream.Collector
object JsonArrayCollector : Collector<JsonElement, JsonArray, JsonArray> {
override fun supplier(): Supplier<JsonArray> {
return Supplier { JsonArray() }
}
override fun accumulator(): BiConsumer<JsonArray, JsonElement> {
return BiConsumer { t, u -> t.add(u) }
}
override fun combiner(): BinaryOperator<JsonArray> {
return BinaryOperator { t, u -> t.addAll(u); t }
}
override fun finisher(): Function<JsonArray, JsonArray> {
return Function.identity()
}
override fun characteristics(): Set<Collector.Characteristics> {
return setOf(Collector.Characteristics.IDENTITY_FINISH)
}
}

View File

@ -17,14 +17,14 @@ import ru.dbotthepony.mc.otm.container.stream
import ru.dbotthepony.mc.otm.core.filterNotNull import ru.dbotthepony.mc.otm.core.filterNotNull
class EnergyContainerRecipe( class EnergyContainerRecipe(
p_44153_: ResourceLocation, id: ResourceLocation,
p_44154_: String, group: String,
category: CraftingBookCategory, category: CraftingBookCategory,
p_44155_: Int, width: Int,
p_44156_: Int, height: Int,
p_44157_: NonNullList<Ingredient>, ingredients: NonNullList<Ingredient>,
p_44158_: ItemStack, result: ItemStack,
) : ShapedRecipe(p_44153_, p_44154_, category, p_44155_, p_44156_, p_44157_, p_44158_) { ) : ShapedRecipe(id, group, category, width, height, ingredients, result) {
constructor(parent: ShapedRecipe) : this(parent.id, parent.group, parent.category(), parent.width, parent.height, parent.ingredients, parent.resultItem) constructor(parent: ShapedRecipe) : this(parent.id, parent.group, parent.category(), parent.width, parent.height, parent.ingredients, parent.resultItem)
override fun assemble(container: CraftingContainer): ItemStack { override fun assemble(container: CraftingContainer): ItemStack {
@ -53,25 +53,25 @@ class EnergyContainerRecipe(
return itemStack return itemStack
} }
override fun matches(p_44002_: CraftingContainer, p_44003_: Level): Boolean { override fun matches(container: CraftingContainer, level: Level): Boolean {
return super.matches(p_44002_, p_44003_) && !p_44002_.stream().anyMatch { it.isDamaged } return super.matches(container, level) && !container.stream().anyMatch { it.isDamaged }
} }
override fun getSerializer(): RecipeSerializer<*> { override fun getSerializer(): RecipeSerializer<EnergyContainerRecipe> {
return Companion return Companion
} }
companion object : RecipeSerializer<EnergyContainerRecipe> { companion object : RecipeSerializer<EnergyContainerRecipe> {
override fun fromJson(p_44103_: ResourceLocation, p_44104_: JsonObject): EnergyContainerRecipe { override fun fromJson(id: ResourceLocation, data: JsonObject): EnergyContainerRecipe {
return EnergyContainerRecipe(Serializer.SHAPED_RECIPE.fromJson(p_44103_, p_44104_)) return EnergyContainerRecipe(Serializer.SHAPED_RECIPE.fromJson(id, data))
} }
override fun fromNetwork(p_44105_: ResourceLocation, p_44106_: FriendlyByteBuf): EnergyContainerRecipe? { override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): EnergyContainerRecipe? {
return Serializer.SHAPED_RECIPE.fromNetwork(p_44105_, p_44106_)?.let(::EnergyContainerRecipe) return Serializer.SHAPED_RECIPE.fromNetwork(id, data)?.let(::EnergyContainerRecipe)
} }
override fun toNetwork(p_44101_: FriendlyByteBuf, p_44102_: EnergyContainerRecipe) { override fun toNetwork(buff: FriendlyByteBuf, value: EnergyContainerRecipe) {
Serializer.SHAPED_RECIPE.toNetwork(p_44101_, p_44102_) Serializer.SHAPED_RECIPE.toNetwork(buff, value)
} }
} }
} }

View File

@ -0,0 +1,205 @@
package ru.dbotthepony.mc.otm.recipe
import com.google.common.collect.ImmutableList
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import net.minecraft.core.NonNullList
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.GsonHelper
import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingBookCategory
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.item.crafting.RecipeSerializer
import net.minecraft.world.item.crafting.ShapedRecipe
import ru.dbotthepony.mc.otm.container.stream
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.core.util.readJson
import ru.dbotthepony.mc.otm.core.util.writeJson
import ru.dbotthepony.mc.otm.data.stream
import java.util.stream.Stream
class UpgradeRecipe(
id: ResourceLocation,
group: String,
category: CraftingBookCategory,
width: Int,
height: Int,
ingredients: NonNullList<Ingredient>,
result: ItemStack,
copyPaths: Stream<Op>,
val source: ResourceLocation,
) : ShapedRecipe(id, group, category, width, height, ingredients, result) {
constructor(parent: ShapedRecipe, copyPaths: Stream<Op>, source: ResourceLocation) : this(parent.id, parent.group, parent.category(), parent.width, parent.height, parent.ingredients, parent.resultItem, copyPaths, source)
enum class OpType {
DIRECT {
override fun deserialize(obj: JsonObject): Op {
return Direct(GsonHelper.getAsString(obj, "path"))
}
}, INDIRECT {
override fun deserialize(obj: JsonObject): Op {
return Indirect(GsonHelper.getAsString(obj, "source"), GsonHelper.getAsString(obj, "destination"))
}
};
abstract fun deserialize(obj: JsonObject): Op
}
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)
}
}
}
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
for (i in 0 until split.size - 1) {
val value = split[i]
if (value !in a) {
a[value] = CompoundTag()
}
if (value !in b) {
b[value] = CompoundTag()
}
a = a[value] as CompoundTag
b = b[value] as CompoundTag
}
val value = split.last()
if (value in a) {
b[value] = a[value]!!.copy()
}
}
}
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
for (i in 0 until splitSource.size - 1) {
val value = splitSource[i]
if (value !in a) {
a[value] = CompoundTag()
}
a = a[value] as CompoundTag
}
for (i in 0 until splitDestination.size - 1) {
val value = splitDestination[i]
if (value !in b) {
b[value] = CompoundTag()
}
b = b[value] as CompoundTag
}
val valueA = splitSource.last()
val valueB = splitDestination.last()
if (valueA in a) {
b[valueB] = a[valueA]!!.copy()
}
}
}
val copyPaths: ImmutableList<Op> = copyPaths.collect(ImmutableList.toImmutableList())
override fun assemble(pInv: CraftingContainer): ItemStack {
val result = super.assemble(pInv)
if (result.isEmpty) {
return result
}
val sources = pInv.stream().filter { !it.isEmpty && it.item.registryName == source }.toList()
if (sources.size != 1) {
return ItemStack.EMPTY
}
val source = sources.first()
for (op in copyPaths) {
op.apply(source.tagNotNull, result.tagNotNull)
}
return result
}
override fun getSerializer(): RecipeSerializer<UpgradeRecipe> {
return Companion
}
companion object : RecipeSerializer<UpgradeRecipe> {
fun deserializeOp(json: JsonObject): Op {
return OpType.valueOf(GsonHelper.getAsString(json, "type")).deserialize(json)
}
override fun fromJson(id: ResourceLocation, data: JsonObject): UpgradeRecipe {
return UpgradeRecipe(
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 = Serializer.SHAPED_RECIPE.fromNetwork(id, buff) ?: return null
return UpgradeRecipe(
recipe,
buff.readCollection({ ArrayList<Op>(it) }, { deserializeOp(it.readJson() as JsonObject) }).stream(),
buff.readResourceLocation()
)
}
override fun toNetwork(buff: FriendlyByteBuf, value: UpgradeRecipe) {
Serializer.SHAPED_RECIPE.toNetwork(buff, value)
buff.writeCollection(value.copyPaths) { it, v -> it.writeJson(v.serialize()) }
buff.writeResourceLocation(value.source)
}
}
}