Compare commits

...

81 Commits
1.21 ... 1.20.1

Author SHA1 Message Date
066418d7b2
https://i.dbotthepony.ru/2024/07/18/attachment-133_1.gif 2024-07-18 20:16:50 +07:00
c83476225d
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-06-01 20:16:05 +07:00
f8277e55c3
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-05-31 16:49:35 +07:00
49dd781a82
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-05-31 16:37:18 +07:00
65dbeeeb4f
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-05-31 11:22:02 +07:00
f6138671d2
How does CAR is for 1.20.2 on 1.20.1 branch 2024-05-31 11:19:15 +07:00
34b60be434
Post merge fixes for 1.20.1 2024-05-31 11:13:53 +07:00
6153c2e972
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-05-31 11:10:20 +07:00
376e548cec
Revert "what"
This reverts commit 87e64a102a.
2024-01-22 14:28:21 +07:00
653ecedafb
Proper backport "allow vanilla servers on otm modded clients" 2024-01-22 14:02:21 +07:00
87e64a102a
what 2024-01-22 11:45:56 +07:00
0b7e54b4ef
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-22 11:45:00 +07:00
f0dba4ccc3
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-22 11:39:06 +07:00
b35dfaeacd
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-14 00:29:02 +07:00
6a2eb3dec2
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-13 12:17:56 +07:00
ce94d22212
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-13 12:04:52 +07:00
21b84651a8
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-13 12:02:26 +07:00
80917f7d12
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-13 11:50:42 +07:00
12b10ee6fe
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-13 11:42:52 +07:00
a88549f17f
Post merge fixes for 1.20.1 2024-01-12 21:21:07 +07:00
5552be70d5
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-12 21:17:44 +07:00
cb386d39f5
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-09 18:25:48 +07:00
22c3c22081
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-09 17:54:17 +07:00
0da77bc453
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-09 13:53:32 +07:00
f2aade3a8e
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-09 13:42:01 +07:00
46820a311f
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-09 13:41:17 +07:00
3743a3402d
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-08 21:51:08 +07:00
055b9cc489
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-08 21:41:51 +07:00
640f62d63b
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-08 14:16:23 +07:00
d3423a6160
Post merge fixes for 1.20.1 2024-01-08 14:13:43 +07:00
55c0be74d3
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-08 14:13:04 +07:00
9d9b19da9d
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-07 12:07:19 +07:00
652acf3ce1
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-07 11:49:20 +07:00
101e57756a
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-06 16:45:21 +07:00
67dbcde6dc
Post merge fixes for 1.20.1 2024-01-06 11:41:44 +07:00
b4c994f02f
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-06 11:37:34 +07:00
8007c1757e
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-05 23:52:11 +07:00
8aafa38c27
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-05 23:07:36 +07:00
e51ba7015a
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-05 22:59:33 +07:00
1d0e24095a
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-05 22:20:09 +07:00
a7d405b5ea
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-05 22:13:36 +07:00
8ee5e94a78
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-05 21:42:09 +07:00
f9dcf43cc4
Fix compilation error 2024-01-04 20:12:29 +07:00
42fe77e6b4
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-04 20:10:11 +07:00
b28e180704
Downgrade worldedit 2024-01-02 20:33:42 +07:00
2deaef94aa
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-02 20:33:11 +07:00
78ac178526
Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1 2024-01-02 18:08:11 +07:00
92f2680feb
Use appropriate texture for status effect background 2024-01-02 15:16:28 +07:00
077e82064b
Merge branch '1.20.2' into 1.20.1 2024-01-02 15:05:25 +07:00
c821fa76a6
Merge branch '1.20.2' into 1.20.1 2024-01-02 14:19:25 +07:00
6e4bf4e7ec
Merge branch '1.20.2' into 1.20.1 2024-01-02 12:26:47 +07:00
5b45cf7d0a
Merge branch '1.20.2' into 1.20.1 2024-01-02 12:22:08 +07:00
edea36a8a6
Merge branch '1.20.2' into 1.20.1 2024-01-02 12:00:12 +07:00
34ef50f6ee
Merge branch '1.20.2' into 1.20.1 2024-01-01 17:31:29 +07:00
4c5c2362ce
Merge branch '1.20.2' into 1.20.1 2024-01-01 17:29:28 +07:00
54fa8a252e
Merge branch '1.20.2' into 1.20.1 2024-01-01 16:51:04 +07:00
a9cb2db3b4
Merge branch '1.20.2' into 1.20.1 2024-01-01 16:38:01 +07:00
748a232569
Merge branch 'master' into 1.20.1 2024-01-01 15:45:06 +07:00
86c426a504
Merge branch 'master' into 1.20.1 2024-01-01 11:45:14 +07:00
108b49bedb
Merge branch 'master' into 1.20.1 2024-01-01 02:55:55 +07:00
71850b38e5
Merge branch 'master' into 1.20.1 2024-01-01 00:58:18 +07:00
796f29127f
Merge branch 'master' into 1.20.1 2024-01-01 00:13:22 +07:00
8c43a3ec6d
Merge branch 'master' into 1.20.1 2023-12-31 23:18:46 +07:00
477e782c7c
*french disappointment* 2023-12-31 22:44:28 +07:00
65cf8bf9df
Fixes to data loading 2023-12-31 22:43:02 +07:00
e5a982ae13
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type int; not a subtype of implementation type class java.lang.Integer 2023-12-31 22:25:55 +07:00
f942093e4f
Don't embed condition json by default 2023-12-31 22:23:16 +07:00
5d15611f84
Update mods.toml 2023-12-31 22:20:48 +07:00
1803d687ab
Make mod compile against 1.20.1 2023-12-31 22:18:43 +07:00
347be35184
Make main source set compile 2023-12-31 22:08:15 +07:00
aa0a283e06
More backporting 2023-12-31 21:40:54 +07:00
98fcacc9a8
More backporting 2023-12-31 21:14:32 +07:00
422ae92303
More backporting 2023-12-31 21:02:52 +07:00
7683cacc29
More backporting 2023-12-31 20:42:20 +07:00
520112df77
Backport MCriterionTrigger to 1.20.1 2023-12-31 20:29:57 +07:00
5453c8c793
Merge branch 'master' into 1.20.1 2023-12-31 20:25:03 +07:00
3c5ea937a5
More backporting 2023-12-31 18:23:07 +07:00
f16483d7c0
Some recipe backporting 2023-12-31 17:46:56 +07:00
8072a7b135
Don't check for "chunk send" status because it is already sent during event fire 2023-12-31 17:08:45 +07:00
44c6d0c0cf
Merge branch 'master' into 1.20.1 2023-12-31 17:02:21 +07:00
27dce0bd31
Downgrade dependencies 2023-12-31 12:54:59 +07:00
78 changed files with 603 additions and 352 deletions

View File

@ -10,28 +10,28 @@ mod_version=1.4
use_commit_hash_in_version=true
mc_version=1.20.2
jei_mc_version=1.20.2
curios_mc_version=1.20.2
mc_version=1.20.1
jei_mc_version=1.20.1
curios_mc_version=1.20.1
forge_gradle_version=[6.0.14,6.2)
forge_version=48.1.0
forge_version=47.2.19
mixingradle_version=0.7.33
mixin_version=0.8.5
kommons_version=3.0.2
jei_version=16.0.0.28
jei_version=15.2.0.27
jupiter_version=5.9.2
curios_version=6.0.2
cosmetic_armor_reworked_id=4764779
curios_version=5.4.7
cosmetic_armor_reworked_id=4600191
ad_astra_id=4594155
botarium_id=4594094
resourceful_lib_id=4598948
resourceful_config_id=4576455
jade_id=4818518
jade_id=4986594
configured_id=4462894
worldedit_id=4807512
worldedit_id=4586218
kotlin_for_forge_version=4.7.0
kotlin_version=1.9.0

View File

@ -1,9 +1,8 @@
package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.AdvancementHolder
import net.minecraft.advancements.AdvancementRewards
import net.minecraft.advancements.FrameType
import net.minecraft.advancements.AdvancementRequirements.Strategy
import net.minecraft.advancements.RequirementsStrategy
import net.minecraft.advancements.critereon.InventoryChangeTrigger
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
@ -17,6 +16,8 @@ import ru.dbotthepony.mc.otm.triggers.BlackHoleTrigger
import ru.dbotthepony.mc.otm.triggers.NailedEntityTrigger
import java.util.function.Consumer
typealias Strategy = RequirementsStrategy
fun addAdvancements(serializer: Consumer<AdvancementHolder>, lang: MatteryLanguageProvider) {
val translation = lang.MultiBuilder("otm.advancements.regular")

View File

@ -1,7 +1,5 @@
package ru.dbotthepony.mc.otm.datagen.advancements
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.critereon.EntityPredicate

View File

@ -1,12 +1,9 @@
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
import net.minecraft.world.item.Items
import net.minecraftforge.common.data.ExistingFileHelper
import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider
import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.registry.MItems

View File

@ -16,6 +16,7 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.core.TextComponent
import java.util.function.Consumer
fun AdvancementBuilder(): Advancement.Builder = Advancement.Builder.advancement()
@ -58,7 +59,7 @@ fun predicate(tag: TagKey<Item>): ItemPredicate {
return ItemPredicate.Builder.item().of(tag).build()
}
fun criterion(tag: TagKey<Item>): Criterion<*> {
fun criterion(tag: TagKey<Item>): CriterionTriggerInstance {
return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(tag))
}
@ -66,8 +67,10 @@ fun predicate(item: ItemLike): ItemPredicate {
return ItemPredicate.Builder.item().of(item).build()
}
fun criterion(item: ItemLike): Criterion<*> {
fun criterion(item: ItemLike): CriterionTriggerInstance {
return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(item))
}
fun EntityPredicate.wrap(): ContextAwarePredicate = EntityPredicate.wrap(this)
fun Advancement.Builder.save(advancement: Consumer<Advancement>, name: ResourceLocation) = save(advancement, name.toString())

View File

@ -1,8 +1,8 @@
package ru.dbotthepony.mc.otm.datagen.advancements
import net.minecraft.advancements.AdvancementHolder
import net.minecraft.advancements.AdvancementRequirements
import net.minecraft.advancements.Advancement
import net.minecraft.advancements.FrameType
import net.minecraft.advancements.RequirementsStrategy
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
@ -16,6 +16,8 @@ import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.triggers.TakeItemOutOfReplicatorTrigger
import java.util.function.Consumer
typealias AdvancementHolder = Advancement
data class CraftEntry(
val item: Collection<Item>,
val englishName: String,
@ -59,7 +61,7 @@ data class CraftEntry(
it.addCriterion(i.toString(), criterion(item))
}
}
.requirements(AdvancementRequirements.Strategy.OR)
.requirements(RequirementsStrategy.OR)
.save(serializer, modLocation("machines/$path"))
}
}
@ -82,7 +84,7 @@ fun addMachineAdvancements(serializer: Consumer<AdvancementHolder>, lang: Matter
for ((i, v) in MItems.CHEMICAL_GENERATOR.values.withIndex())
it.addCriterion("has_machine_$i", criterion(v))
}
.requirements(AdvancementRequirements.Strategy.OR)
.requirements(RequirementsStrategy.OR)
.save(serializer, modLocation("machines/chemical_generator"))
val press = AdvancementBuilder()
@ -100,7 +102,7 @@ fun addMachineAdvancements(serializer: Consumer<AdvancementHolder>, lang: Matter
for ((i, m) in MItems.TWIN_PLATE_PRESS.values.withIndex())
it.addCriterion(i.toString(), criterion(m))
}
.requirements(AdvancementRequirements.Strategy.OR)
.requirements(RequirementsStrategy.OR)
.save(serializer, modLocation("machines/plate_press"))
CraftEntry(MItems.ENERGY_SERVO.values, "Power Goes In, Powered Things Go Out",

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.tags.ItemTags
import net.minecraftforge.common.Tags
import ru.dbotthepony.mc.otm.registry.MItemTags

View File

@ -1,14 +1,12 @@
package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.SimpleCookingRecipeBuilder
import net.minecraft.util.valueproviders.ConstantFloat
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
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.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems

View File

@ -1,8 +1,6 @@
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
@ -17,7 +15,6 @@ import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
import java.util.function.Consumer
fun addCraftingTableRecipes(consumer: RecipeOutput) {
val machinesCategory = RecipeCategory.DECORATIONS

View File

@ -1,6 +1,5 @@
package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.world.item.Items
import net.minecraftforge.common.Tags
import ru.dbotthepony.mc.otm.registry.MItemTags

View File

@ -1,6 +1,5 @@
package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
import net.minecraftforge.common.Tags
@ -14,6 +13,7 @@ import ru.dbotthepony.mc.otm.registry.MItems
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)),
@ -23,11 +23,12 @@ fun addMatterEntanglerRecipes(consumer: RecipeOutput) {
400.0,
ItemStack(MItems.QUANTUM_CAPACITOR, 2),
experience = 15f
).energetic().toFinished(modLocation("quantum_capacitor"))
).energetic().toFinished()
)
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)),
@ -37,6 +38,6 @@ fun addMatterEntanglerRecipes(consumer: RecipeOutput) {
600.0,
ItemStack(MItems.QUANTUM_BATTERY, 2),
experience = 20f
).energetic().toFinished(modLocation("quantum_battery"))
).energetic().toFinished()
)
}

View File

@ -7,7 +7,6 @@ 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
@ -62,10 +61,6 @@ private fun RecipeOutput.map(mapper: (FinishedRecipe) -> FinishedRecipe): Recipe
override fun accept(recipe: FinishedRecipe) {
this@map.accept(mapper(recipe))
}
override fun advancement(): Advancement.Builder {
return this@map.advancement()
}
}
}
@ -77,11 +72,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, Criterion<*>>>().also {
private val unlockedBy = ArrayList<Pair<String, CriterionTriggerInstance>>().also {
it.add("has_result" to has(result))
}
fun unlockedBy(name: String, trigger: Criterion<*>): MatteryRecipe {
fun unlockedBy(name: String, trigger: CriterionTriggerInstance): MatteryRecipe {
unlockedBy.add(name to trigger)
return this
}
@ -195,7 +190,7 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
pJson["source"] = upgradeSource!!.toString()
}
override fun type(): RecipeSerializer<*> {
override fun getType(): RecipeSerializer<*> {
return UpgradeRecipe.CODEC
}
}
@ -227,7 +222,7 @@ class MatteryRecipe(val result: ItemLike, val count: Int = 1, val category: Reci
fun buildEnergetic(consumer: RecipeOutput, name: String? = null) {
build(consumer.map {
object : FinishedRecipe by it {
override fun type(): RecipeSerializer<*> {
override fun getType(): RecipeSerializer<*> {
return EnergyContainerRecipe.Companion
}
}

View File

@ -1,17 +1,13 @@
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.CriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.InventoryChangeTrigger
import net.minecraft.advancements.critereon.ItemPredicate
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
@ -27,31 +23,30 @@ import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
import java.util.*
import java.util.function.Consumer
import java.util.stream.Stream
private typealias RecipeBuilderCallback = (MatteryRecipeProvider, consumer: RecipeOutput) -> Unit
fun has(p_176521_: MinMaxBounds.Ints, p_176522_: ItemLike): Criterion<InventoryChangeTrigger.TriggerInstance> {
fun has(p_176521_: MinMaxBounds.Ints, p_176522_: ItemLike): CriterionTriggerInstance {
return inventoryTrigger(ItemPredicate.Builder.item().of(p_176522_).withCount(p_176521_).build())
}
fun has(p_125978_: ItemLike): Criterion<InventoryChangeTrigger.TriggerInstance> {
fun has(p_125978_: ItemLike): CriterionTriggerInstance {
return inventoryTrigger(ItemPredicate.Builder.item().of(p_125978_).build())
}
fun has(p_125976_: TagKey<Item>): Criterion<InventoryChangeTrigger.TriggerInstance> {
fun has(p_125976_: TagKey<Item>): CriterionTriggerInstance {
return inventoryTrigger(ItemPredicate.Builder.item().of(p_125976_).build())
}
fun inventoryTrigger(vararg p_126012_: ItemPredicate): Criterion<InventoryChangeTrigger.TriggerInstance> {
return CriteriaTriggers.INVENTORY_CHANGED.createCriterion(InventoryChangeTrigger.TriggerInstance(
Optional.empty(),
fun inventoryTrigger(vararg p_126012_: ItemPredicate): CriterionTriggerInstance {
return InventoryChangeTrigger.TriggerInstance(
ContextAwarePredicate.ANY,
MinMaxBounds.Ints.ANY,
MinMaxBounds.Ints.ANY,
MinMaxBounds.Ints.ANY,
ImmutableList.copyOf(p_126012_)
))
p_126012_
)
}
fun multiIngredient(vararg items: Any) : Ingredient {
@ -104,24 +99,25 @@ 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(modLocation("plates/$id")))
).toFinished())
}
}
fun plate(id: String, ingredient: Ingredient, result: Ingredient, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) {
exec { it, callback ->
callback.accept(PlatePressRecipe(ingredient, result, count, workTicks, experience = experience).toFinished(modLocation("plate_$id")))
callback.accept(PlatePressRecipe(modLocation("plates/$id"), ingredient, result, count, workTicks, experience = experience).toFinished())
}
}
fun microwave(id: String, ingredient: Ingredient, result: Ingredient, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) {
exec { it, callback ->
callback.accept(MicrowaveRecipe(ingredient, result, count, workTicks, experience = experience).toFinished(modLocation("microwave/$id")))
callback.accept(MicrowaveRecipe(modLocation("microwave/$id"), ingredient, result, count, workTicks, experience = experience).toFinished())
}
}
}

View File

@ -1,20 +1,16 @@
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
import net.minecraft.world.item.Items
import net.minecraft.world.item.crafting.Ingredient
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.PainterArmorDyeRecipe
import ru.dbotthepony.mc.otm.recipe.PainterRecipe
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.function.Consumer
private val Item.recipeName get() = registryName!!.namespace + "/" + registryName!!.path
@ -23,10 +19,11 @@ private fun generate(consumer: RecipeOutput, items: Map<out DyeColor?, Item>, am
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(modLocation("painter/" + targetItem.recipeName)))
).toFinished())
}
}
@ -40,19 +37,21 @@ private fun generate(consumer: RecipeOutput, default: Item, items: Map<out DyeCo
if (k1 == null) continue
consumer.accept(PainterRecipe(
modLocation("painter/" + default.recipeName + "/" + v1.recipeName),
Ingredient.of(default),
ItemStack(v1),
mapOf(k1 to amount)
).toFinished(modLocation("painter/" + default.recipeName + "/" + v1.recipeName)))
).toFinished())
}
}
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),
mapOf(null to 15)
).toFinished(modLocation("painter/cleaning/" + to.recipeName)))
).toFinished())
}
private fun striped(consumer: RecipeOutput, name: String, items: List<Pair<Item, Pair<DyeColor, DyeColor>>>, base: Map<DyeColor, Item>) {
@ -60,10 +59,11 @@ private fun striped(consumer: RecipeOutput, name: String, items: List<Pair<Item,
val (baseColor, stripe) = colors
consumer.accept(PainterRecipe(
modLocation("painter/stripes_$name/${baseColor.getName()}/${stripe.getName()}"),
Ingredient.of(base[baseColor]),
ItemStack(stripeItem),
setOf(stripe)
).toFinished(modLocation("painter/stripes_$name/${baseColor.getName()}/${stripe.getName()}")))
).toFinished())
}
}
@ -318,32 +318,36 @@ fun addPainterRecipes(consumer: RecipeOutput) {
striped(consumer, "slabs", MRegistry.TRITANIUM_STRIPED_SLAB.itemsWithColor, MRegistry.TRITANIUM_SLAB.items)
for (color in DyeColor.entries) {
consumer.accept(PainterArmorDyeRecipe(mapOf(color to 1)).toFinished(modLocation("painter/armor_dye_" + color.getName().lowercase())))
consumer.accept(PainterArmorDyeRecipe(modLocation("painter/armor_dye_" + color.getName().lowercase()), mapOf(color to 1)).toFinished())
}
consumer.accept(PainterArmorDyeRecipe(mapOf(null to 15)).toFinished(modLocation("painter/armor_clear_dye")))
consumer.accept(PainterArmorDyeRecipe(modLocation("painter/armor_clear_dye"), mapOf(null to 15)).toFinished())
consumer.accept(PainterRecipe(
modLocation("painter/tritanium_yellow_stripe"),
Ingredient.of(MRegistry.TRITANIUM_BLOCK.item),
ItemStack(MItems.TRITANIUM_STRIPED_BLOCK),
mapOf(DyeColor.YELLOW to 1)
).toFinished(modLocation("painter/tritanium_yellow_stripe")))
).toFinished())
consumer.accept(PainterRecipe(
modLocation("painter/tritanium_yellow_stripe_stairs"),
Ingredient.of(MRegistry.TRITANIUM_STAIRS.item),
ItemStack(MItems.TRITANIUM_STRIPED_STAIRS),
mapOf(DyeColor.YELLOW to 1)
).toFinished(modLocation("painter/tritanium_yellow_stripe_stairs")))
).toFinished())
consumer.accept(PainterRecipe(
modLocation("painter/tritanium_yellow_stripe_slab"),
Ingredient.of(MRegistry.TRITANIUM_SLAB.item),
ItemStack(MItems.TRITANIUM_STRIPED_SLAB),
mapOf(DyeColor.YELLOW to 1)
).toFinished(modLocation("painter/tritanium_yellow_stripe_slab")))
).toFinished())
consumer.accept(PainterRecipe(
modLocation("painter/tritanium_yellow_stripe_wall"),
Ingredient.of(MRegistry.TRITANIUM_WALL.item),
ItemStack(MItems.TRITANIUM_STRIPED_WALL),
mapOf(DyeColor.YELLOW to 1)
).toFinished(modLocation("painter/tritanium_yellow_stripe_wall")))
).toFinished())
}

View File

@ -1,7 +1,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.TagKey
import net.minecraft.world.item.DyeColor
@ -16,6 +16,9 @@ import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.function.Consumer
typealias RecipeOutput = Consumer<FinishedRecipe>
fun hammerRecipe(output: ItemLike, input: ItemLike, consumer: RecipeOutput) {
ShapelessRecipeBuilder(RecipeCategory.MISC, output, 1)

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraftforge.common.Tags
import ru.dbotthepony.mc.otm.recipe.UpgradeRecipe
import ru.dbotthepony.mc.otm.registry.MItemTags

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.datagen.recipes
import net.minecraft.data.recipes.RecipeCategory
import net.minecraft.data.recipes.RecipeOutput
import net.minecraftforge.common.Tags
import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems

View File

@ -25,6 +25,7 @@ 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
@ -392,7 +393,7 @@ class AndroidResearchType(
ListCodec(
RecordCodecBuilder.create<Pair<Ingredient, Int>> {
it.group(
Ingredient.CODEC.fieldOf("item").forGetter { it.first },
IngredientCodec.fieldOf("item").forGetter { it.first },
Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter { it.second }
).apply(it, ::Pair)
}

View File

@ -594,14 +594,11 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
private fun recheckPlayer(player: ServerPlayer) {
sometimeServer {
if (player in players && !player.hasDisconnected()) {
if (player.connection.chunkSender.isPending(chunkPos)) {
recheckPlayer(player)
} else {
veto.remove(player)
veto.remove(player)
blockEntities.forEach {
it.synchers[player] = it.syncher.Remote()
}
blockEntities.forEach {
it.synchers[player] =
it.syncher.Remote()
}
} else if (player in players && player.hasDisconnected()) {
unsubscribe(player)

View File

@ -668,11 +668,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
}, DataFixTypes.LEVEL),
}, { ExplosionQueue(level) },
"otm_blackhole_explosion_queue"
)
}

View File

@ -29,6 +29,7 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.ShadowCraftingContainer
import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.data.DecimalCodec
import ru.dbotthepony.mc.otm.data.minRange
import ru.dbotthepony.mc.otm.graph.matter.MatterNode

View File

@ -49,6 +49,7 @@ import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
import ru.dbotthepony.mc.otm.core.value
interface IItemMonitorPlayerSettings {
var ingredientPriority: ItemMonitorPlayerSettings.IngredientPriority

View File

@ -36,6 +36,7 @@ import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.maybe
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.core.util.item
import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu
import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe

View File

@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.balance
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.maybe
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MRecipes

View File

@ -556,7 +556,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

@ -224,7 +224,7 @@ fun onMouseScrolled(event: MouseScrolled.Pre) {
for (widget in screen.renderables) {
if (widget is Panel2Widget<*, *>) {
if (widget.panel.mouseScrolledChecked(event.mouseX, event.mouseY, event.deltaX)) {
if (widget.panel.mouseScrolledChecked(event.mouseX, event.mouseY, event.scrollDelta)) {
event.isCanceled = true
return
}
@ -233,7 +233,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.deltaX)
widget.panel.mouseScrolledInner(event.mouseX, event.mouseY, event.scrollDelta)
event.isCanceled = true
return
}

View File

@ -569,7 +569,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
return super.mouseReleased(p_97812_, p_97813_, p_97814_)
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollY: Double): Boolean {
for (panel in panels) {
if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) {
return true
@ -653,7 +653,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
val mouseYf = mouseY.toFloat()
// dark background
this.renderBackground(graphics, mouseX, mouseY, partialTick)
this.renderBackground(graphics)
super.hoveredSlot = null
var hovered = false

View File

@ -30,6 +30,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.map
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) : MatteryScreen<PainterMenu>(menu, inventory, title) {

View File

@ -100,7 +100,7 @@ open class EditablePanel<out S : Screen>(
return this@EditablePanel.mouseDragged(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_)
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollY: Double): Boolean {
return this@EditablePanel.mouseScrolled(mouseX, mouseY, scrollY)
}

View File

@ -4,7 +4,7 @@ import com.mojang.blaze3d.systems.RenderSystem
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import net.minecraft.client.gui.screens.Screen
import net.minecraft.resources.ResourceLocation
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.entity.LivingEntity
@ -264,7 +264,7 @@ open class EffectListPanel<out S : Screen> @JvmOverloads constructor(
}
companion object {
val BAR = ResourceLocation("textures/gui/sprites/container/inventory/effect_background_large.png").sprite(0f, 0f, 120f, 32f, 120f, 32f)
val SQUARE_THIN = ResourceLocation("textures/gui/sprites/hud/effect_background.png").sprite(0f, 0f, 24f, 24f, 24f, 24f)
val BAR = AbstractContainerScreen.INVENTORY_LOCATION.sprite(0f, 166f, 120f, 32f)
val SQUARE_THIN = AbstractContainerScreen.INVENTORY_LOCATION.sprite(141f, 166f, 24f, 24f)
}
}

View File

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

View File

@ -49,7 +49,7 @@ 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(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollY: Double): Boolean {
return panel.mouseScrolledChecked(mouseX, mouseY, scrollY)
}

View File

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

View File

@ -56,7 +56,7 @@ object MatterBottlerProvider : IBlockComponentProvider, IServerDataProvider<Bloc
data.getFloat("workProgress"),
null,
elementHelper.progressStyle().color(RGBAColor.WHITE.toBGRA()),
BoxStyle.getNestedBox(),
BoxStyle.DEFAULT,
true
)
)

View File

@ -57,7 +57,7 @@ object MatterReconstructorProvider : IBlockComponentProvider, IServerDataProvide
maxDamage
),
elementHelper.progressStyle().color(RGBAColor.DARK_GREEN.toBGRA()).textColor(RGBAColor.WHITE.toBGRA()),
BoxStyle.getNestedBox(),
BoxStyle.DEFAULT,
true
)
)

View File

@ -69,7 +69,7 @@ object MatterStorageProvider : IBlockComponentProvider, IServerDataProvider<Bloc
maxStoredMatter.formatMatter()
),
elementHelper.progressStyle().color(JadeColors.MATTER_COLOR.toBGRA()).textColor(RGBAColor.WHITE.toBGRA()),
BoxStyle.getNestedBox(),
BoxStyle.DEFAULT,
true
)
)

View File

@ -67,7 +67,7 @@ object MatteryEnergyProvider : IBlockComponentProvider, IServerDataProvider<Bloc
maxBatteryLevel.formatPower()
),
elementHelper.progressStyle().color(JadeColors.ENERGY_COLOR.toBGRA(), JadeColors.ENERGY_COLOR2.toBGRA()).textColor(RGBAColor.WHITE.toBGRA()),
BoxStyle.getNestedBox(),
BoxStyle.DEFAULT,
true
)
)

View File

@ -75,7 +75,7 @@ object MatteryWorkerProvider : IBlockComponentProvider, IServerDataProvider<Bloc
progress,
null,
if (isUnableToProcess) styleError else style,
BoxStyle.getNestedBox(),
BoxStyle.DEFAULT,
true
)
)

View File

@ -14,15 +14,14 @@ 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, RecipeHolder<CraftingRecipe>> {
private val transfer = helper.createUnregisteredRecipeTransferHandler(object : IRecipeTransferInfo<ExopackInventoryMenu, RecipeHolder<CraftingRecipe>> {
class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandlerHelper) : IRecipeTransferHandler<ExopackInventoryMenu, CraftingRecipe> {
private val transfer = helper.createUnregisteredRecipeTransferHandler(object : IRecipeTransferInfo<ExopackInventoryMenu, CraftingRecipe> {
override fun getContainerClass(): Class<out ExopackInventoryMenu> {
return ExopackInventoryMenu::class.java
}
@ -31,24 +30,24 @@ class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandler
return Optional.empty()
}
override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<RecipeHolder<CraftingRecipe>> {
override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<CraftingRecipe> {
return RecipeTypes.CRAFTING
}
override fun canHandle(container: ExopackInventoryMenu, recipe: RecipeHolder<CraftingRecipe>): Boolean {
override fun canHandle(container: ExopackInventoryMenu, recipe: CraftingRecipe): Boolean {
return true
}
override fun getRecipeSlots(
container: ExopackInventoryMenu,
recipe: RecipeHolder<CraftingRecipe>
recipe: CraftingRecipe
): List<Slot> {
return container.craftingSlots
}
override fun getInventorySlots(
container: ExopackInventoryMenu,
recipe: RecipeHolder<CraftingRecipe>
recipe: CraftingRecipe
): List<Slot> {
return container.playerInventorySlots
}
@ -62,7 +61,7 @@ class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandler
return Optional.empty()
}
override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<RecipeHolder<CraftingRecipe>> {
override fun getRecipeType(): mezz.jei.api.recipe.RecipeType<CraftingRecipe> {
return RecipeTypes.CRAFTING
}
@ -89,7 +88,7 @@ class ExopackInventoryTransferHandler(private val helper: IRecipeTransferHandler
override fun transferRecipe(
container: ExopackInventoryMenu,
recipe: RecipeHolder<CraftingRecipe>,
recipe: CraftingRecipe,
recipeSlots: IRecipeSlotsView,
player: Player,
maxTransfer: Boolean,

View File

@ -26,6 +26,8 @@ import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.filterIsInstance
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.core.filterNotNull
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu

View File

@ -20,11 +20,13 @@ import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.ComponentContents
import net.minecraft.network.chat.contents.TranslatableContents
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.Container
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
@ -33,6 +35,8 @@ import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateHolder
import net.minecraft.world.level.block.state.properties.Property
import net.minecraft.world.level.saveddata.SavedData
import net.minecraft.world.level.storage.DimensionDataStorage
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.common.util.LazyOptional
@ -67,6 +71,7 @@ import java.util.UUID
import java.util.concurrent.Callable
import java.util.concurrent.Future
import java.util.function.Consumer
import java.util.function.Function
import java.util.function.Supplier
import java.util.stream.Stream
import java.util.stream.StreamSupport
@ -516,3 +521,4 @@ fun <A, B> lazy2(a: () -> A, b: A.() -> B): Supplier<B> {
return Supplier { b.invoke(first.value) }
}
inline val <R : Recipe<T>, T : Container> R.value get() = this

View File

@ -117,7 +117,7 @@ fun CompoundTag.putJson(key: String, json: JsonElement) {
putByteArray(key, bytes.array.copyOfRange(0, bytes.length))
}
fun CompoundTag.getJson(key: String, sizeLimit: NbtAccounter = NbtAccounter(1 shl 18, 512)): JsonElement? {
fun CompoundTag.getJson(key: String, sizeLimit: NbtAccounter = NbtAccounter(1 shl 18)): JsonElement? {
val bytes = getByteArray(key)
if (bytes.isEmpty())

View File

@ -8,9 +8,7 @@ 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
@ -24,15 +22,7 @@ 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>,
@ -40,45 +30,18 @@ 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)
}
}
}
}
val isNetwork: Boolean
get() = context.isNetwork > 0
}
private val codec = codec.invoke(Context())
@ -97,30 +60,45 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
}
}
override fun codec(): Codec<S> {
return this
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 fromNetwork(data: FriendlyByteBuf): S? {
override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): S? {
try {
context.idStack.addLast(id)
context.isNetwork++
return data.readBinaryJsonWithCodecIndirect(this)
.resultOrPartial { LOGGER.error("Failed to read recipe from network: $it") }.orElse(null)
.resultOrPartial { LOGGER.error("Failed to read recipe $id 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, id: ResourceLocation): FinishedRecipe {
fun toFinished(recipe: S): FinishedRecipe {
return object : FinishedRecipe {
override fun serializeRecipeData(p_125967_: JsonObject) {
encode(recipe, JsonOps.INSTANCE, p_125967_).get().map(
@ -137,15 +115,19 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
)
}
override fun id(): ResourceLocation {
return id
override fun getId(): ResourceLocation {
return recipe.id
}
override fun type(): RecipeSerializer<*> {
override fun getType(): RecipeSerializer<*> {
return this@Codec2RecipeSerializer
}
override fun advancement(): AdvancementHolder? {
override fun serializeAdvancement(): JsonObject? {
return null
}
override fun getAdvancementId(): ResourceLocation? {
return null
}
}
@ -156,7 +138,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) {
networkIngredientCodec.encode(input, ops, prefix)
} else {
Ingredient.CODEC.encode(input, ops, prefix)
IngredientCodec.encode(input, ops, prefix)
}
}
@ -164,7 +146,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) {
networkIngredientCodec.decode(ops, input)
} else {
Ingredient.CODEC.decode(ops, input)
IngredientCodec.decode(ops, input)
}
}
}
@ -178,14 +160,8 @@ 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 context by object : ThreadLocal<CurrentContext>() {
override fun initialValue(): CurrentContext {
return CurrentContext()
}
}
private val contextHolder = ThreadLocal<CurrentContext>()
private val context: CurrentContext
get() = contextHolder.getOrSet { CurrentContext() }
}
}
private operator fun <T> ThreadLocal<T>.getValue(companion: Codec2RecipeSerializer.Companion, property: KProperty<*>): T {
return get()
}

View File

@ -0,0 +1,38 @@
package ru.dbotthepony.mc.otm.data
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonNull
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 = false) : 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"] ?: JsonNull.INSTANCE)
}
}
}

View File

@ -1,29 +1,48 @@
package ru.dbotthepony.mc.otm.data
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.Dynamic
import com.mojang.serialization.DynamicOps
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 java.util.Optional
import kotlin.reflect.KProperty1
val DoublesCodec: Codec<MinMaxBounds.Doubles> = RecordCodecBuilder.create {
it.group(
Codec.DOUBLE.optionalFieldOf("min").forGetter { Optional.ofNullable(it.min) },
Codec.DOUBLE.optionalFieldOf("max").forGetter { Optional.ofNullable(it.max) },
).apply(it) { min, max ->
if (min.isEmpty && max.isEmpty)
MinMaxBounds.Doubles.ANY
else if (min.isEmpty)
MinMaxBounds.Doubles.atMost(max.get())
else if (max.isEmpty)
MinMaxBounds.Doubles.atLeast(min.get())
else
MinMaxBounds.Doubles.between(min.get(), max.get())
}
}
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 },
DoublesCodec.fieldOf("dealt").forGetter { it.first },
DoublesCodec.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) }
Codec.BOOL.optionalFieldOf("blocked").forGetter { Optional.ofNullable(it.blocked) },
Codec.PASSTHROUGH.xmap({ EntityPredicate.fromJson(it.cast(JsonOps.INSTANCE)) }, { Dynamic(JsonOps.INSTANCE, it.serializeToJson()) }).fieldOf("source_entity").forGetter { it.sourceEntity },
Codec.PASSTHROUGH.xmap({ DamageSourcePredicate.fromJson(it.cast(JsonOps.INSTANCE)) }, { Dynamic(JsonOps.INSTANCE, it.serializeToJson()) }).fieldOf("type").forGetter { it.type },
).apply(it) { damage, blocked, source, type -> DamagePredicate(damage.first, damage.second, source, blocked.orElse(null), type) }
}
fun <V, T1> simpleCodec(factory: (T1) -> V, field1: KProperty1<V, T1>, codec1: Codec<T1>): Codec<V> {

View File

@ -0,0 +1,23 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,49 @@
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 io.netty.buffer.UnpooledByteBufAllocator
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.item.crafting.RecipeSerializer
import java.nio.ByteBuffer
data class RecipePair<R : Recipe<*>>(val recipe: R, val data: JsonObject)
fun <R : Recipe<*>> RecipeSerializer<R>.codec(context: Codec2RecipeSerializer<*>.Context): Codec<RecipePair<R>> {
return object : Codec<RecipePair<R>> {
override fun <T : Any> encode(input: RecipePair<R>, ops: DynamicOps<T>, prefix: T): DataResult<T> {
if (context.isNetwork) {
val buffer = FriendlyByteBuf(UnpooledByteBufAllocator.DEFAULT.heapBuffer())
buffer.writeResourceLocation(input.recipe.id)
toNetwork(buffer, input.recipe)
buffer.readerIndex(0)
val array = ByteBuffer.allocate(buffer.readableBytes())
buffer.readBytes(array)
array.position(0)
return DataResult.success(ops.createByteList(array))
} else {
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.data))
}
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<RecipePair<R>, T>> {
if (context.isNetwork) {
return ops.getByteBuffer(input).map {
it.position(0)
val buffer = FriendlyByteBuf(UnpooledByteBufAllocator.DEFAULT.heapBuffer())
buffer.writeBytes(it)
buffer.readerIndex(0)
Pair(RecipePair(fromNetwork(buffer.readResourceLocation(), buffer)!!, JsonObject()), ops.empty())
}
} else {
val getJson = ops.convertTo(JsonOps.INSTANCE, input) as JsonObject
return DataResult.success(Pair(RecipePair(fromJson(context.id, getJson), getJson), ops.empty()))
}
}
}
}

View File

@ -16,6 +16,7 @@ import ru.dbotthepony.mc.otm.core.nbt.getJson
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
import java.util.Optional
import java.util.stream.Stream
@ -73,15 +74,17 @@ class CopyTileNbtFunction(filter: Stream<out String> = Stream.empty()) : LootIte
}
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)
}
val CODEC by lazy {
Codec2Serializer<CopyTileNbtFunction>(
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)
}
)
}
}
}

View File

@ -1,13 +1,20 @@
package ru.dbotthepony.mc.otm.data.loot
import com.google.common.collect.ImmutableList
import com.google.gson.JsonSyntaxException
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.*
@ -32,10 +39,51 @@ class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<L
}
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(
LootPool.CODEC.listOf().fieldOf("pools").forGetter(LootPoolAppender::pools)
lootPoolCodec.fieldOf("pools").forGetter(LootPoolAppender::pools)
).apply(it, ::LootPoolAppender)
}
}

View File

@ -102,7 +102,7 @@ class FluidCapsuleItem(val capacity: IntSupplier) : MatteryItem(Properties().sta
actionResult.result
} else {
val state = level.getBlockState(hitPos)
val placePos = if (state.block is LiquidBlockContainer && (state.block as LiquidBlockContainer).canPlaceLiquid(player, level, hitPos, state, fluid.fluid)) hitPos else nextPos
val placePos = if (state.block is LiquidBlockContainer && (state.block as LiquidBlockContainer).canPlaceLiquid(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
@ -9,17 +9,14 @@ import net.minecraft.world.InteractionResult
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.MinecartItem
import net.minecraft.world.item.context.UseOnContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.BaseRailBlock
import net.minecraft.world.level.block.DispenserBlock
import net.minecraft.world.level.block.state.properties.RailShape
import net.minecraft.world.level.gameevent.GameEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.entity.MinecartCargoCrate
import ru.dbotthepony.mc.otm.registry.MEntityTypes
import kotlin.math.floor
class MinecartCargoCrateItem(val color: DyeColor?) : MatteryItem(Properties().stacksTo(16)) {
init {
@ -68,7 +65,7 @@ class MinecartCargoCrateItem(val color: DyeColor?) : MatteryItem(Properties().st
private val default = DefaultDispenseItemBehavior()
override fun dispense(blockSource: BlockSource, itemStack: ItemStack): ItemStack {
val direction = blockSource.state.getValue(DispenserBlock.FACING)
val direction = blockSource.blockState.getValue(DispenserBlock.FACING)
val level: Level = blockSource.level
val x = blockSource.pos.x + direction.stepX.toDouble() * 1.125
val y = blockSource.pos.y + direction.stepY.toDouble()

View File

@ -24,6 +24,7 @@ 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,15 +120,17 @@ class ProceduralBatteryItem : MatteryItem(Properties().stacksTo(1)) {
}
companion object {
val CODEC: Codec<Randomizer> by lazy {
RecordCodecBuilder.create {
it.group(
DecimalProvider.CODEC.fieldOf("maxBatteryLevel").forGetter(Randomizer::maxBatteryLevel),
DecimalProvider.CODEC.optionalFieldOf("batteryLevel").forGetter(Randomizer::batteryLevel),
DecimalProvider.CODEC.fieldOf("maxInput").forGetter(Randomizer::maxInput),
DecimalProvider.CODEC.optionalFieldOf("maxOutput").forGetter(Randomizer::maxOutput),
).apply(it, ::Randomizer)
}
val CODEC by lazy {
Codec2Serializer<Randomizer>(
RecordCodecBuilder.create {
it.group(
DecimalProvider.CODEC.fieldOf("maxBatteryLevel").forGetter(Randomizer::maxBatteryLevel),
DecimalProvider.CODEC.optionalFieldOf("batteryLevel").forGetter(Randomizer::batteryLevel),
DecimalProvider.CODEC.fieldOf("maxInput").forGetter(Randomizer::maxInput),
DecimalProvider.CODEC.optionalFieldOf("maxOutput").forGetter(Randomizer::maxOutput),
).apply(it, ::Randomizer)
}
)
}
}
}

View File

@ -153,7 +153,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
val clientData = Object2ObjectOpenHashMap<UUID, IValues>()
val serverData: Data by lazyPerServer {
it.overworld().dataStorage.computeIfAbsent(SavedData.Factory(::Data, ::Data, DataFixTypes.SAVED_DATA_MAP_DATA), "otm_$savedataID")
it.overworld().dataStorage.computeIfAbsent(::Data, ::Data, "otm_$savedataID")
}
private inner class Power(private val stack: ItemStack) : IMatteryEnergyStorage, ICapabilityProvider {

View File

@ -15,6 +15,7 @@ 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,11 +35,15 @@ class ProceduralExopackSlotUpgradeItem : AbstractExopackSlotUpgradeItem(defaultP
}
companion object {
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)
val CODEC by lazy {
Codec2Serializer<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

@ -53,7 +53,6 @@ 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
@ -94,6 +93,7 @@ import ru.dbotthepony.mc.otm.core.util.readBinaryComponent
import ru.dbotthepony.mc.otm.core.util.readCollection
import ru.dbotthepony.mc.otm.core.util.writeBinaryComponent
import ru.dbotthepony.mc.otm.core.util.writeCollection
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.core.writeItemType
import ru.dbotthepony.mc.otm.milliTime
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
@ -1717,7 +1717,7 @@ object MatterManager {
if (event.player == null) {
syncRegistry(PacketDistributor.ALL.noArg())
} else {
syncRegistry(PacketDistributor.PLAYER.with(event.player!!))
syncRegistry(PacketDistributor.PLAYER.with { event.player!! })
}
}

View File

@ -304,9 +304,10 @@ abstract class MatteryMenu(
open inner class EquipmentSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot) : InventorySlot(container, index) {
constructor(type: net.minecraft.world.entity.EquipmentSlot) : this(inventory, 34 + type.ordinal, type)
override fun setByPlayer(newItem: ItemStack, oldItem: ItemStack) {
override fun setByPlayer(newItem: ItemStack) {
val oldItem = item
inventory.player.onEquipItem(type, oldItem, newItem)
super.setByPlayer(newItem, oldItem)
super.setByPlayer(newItem)
}
override fun mayPlace(itemStack: ItemStack): Boolean {
@ -333,9 +334,10 @@ abstract class MatteryMenu(
autoCreateInventoryFrame = autoFrame
offhandSlot = object : InventorySlot(inventory, 40) {
override fun setByPlayer(newItem: ItemStack, oldItem: ItemStack) {
override fun setByPlayer(newItem: ItemStack) {
val oldItem = this.item
inventory.player.onEquipItem(net.minecraft.world.entity.EquipmentSlot.OFFHAND, oldItem, newItem)
super.setByPlayer(newItem, oldItem)
super.setByPlayer(newItem)
}
override fun getNoItemIcon(): Pair<ResourceLocation, ResourceLocation> {

View File

@ -242,7 +242,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

@ -4,7 +4,6 @@ import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.*
import net.minecraft.world.item.crafting.RecipeHolder
import net.minecraft.world.level.material.Fluids
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.fluids.FluidStack
@ -23,6 +22,7 @@ import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.maybe
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.util.ResourceLocationValueCodec
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
@ -46,7 +46,7 @@ class PainterMenu(
val inputContainer = MatteryContainer(::rescan, 1)
val outputContainer = MatteryContainer(1)
private var lastRecipe: RecipeHolder<out AbstractPainterRecipe>? = null
private var lastRecipe: AbstractPainterRecipe? = null
var selectedRecipe by mSynchronizer.Slot(ListenableDelegate.Box(null), ResourceLocationValueCodec.nullable()).also { it.addListener(Runnable { rescan() }) }
val isBulk = BooleanInputWithFeedback(this, tile?.let { it::isBulk })
@ -128,7 +128,7 @@ class PainterMenu(
}
val listeners = Listenable.Void()
val possibleRecipes = ArrayList<RecipeHolder<out AbstractPainterRecipe>>()
val possibleRecipes = ArrayList<AbstractPainterRecipe>()
private fun rescan() {
possibleRecipes.clear()
@ -140,7 +140,7 @@ class PainterMenu(
if (inputContainer.isEmpty || selectedRecipe == null) {
outputContainer.clearContent()
} else {
val recipe = inventory.player.level().recipeManager.byKey(selectedRecipe!!).get() as RecipeHolder<AbstractPainterRecipe>?
val recipe = inventory.player.level().recipeManager.byKey(selectedRecipe!!).get() as AbstractPainterRecipe?
if (recipe == null || !recipe.value.canCraft(dyeStoredDirect) || !recipe.value.matches(inputContainer, inventory.player.level())) {
outputContainer.clearContent()

View File

@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.container.ShadowCraftingContainer
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.item.IQuantumLinked
import ru.dbotthepony.mc.otm.menu.OutputSlot
import ru.dbotthepony.mc.otm.menu.MatteryMenu

View File

@ -140,11 +140,11 @@ object GenericNetworkChannel : MatteryNetworkChannel(
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() {

View File

@ -5,12 +5,11 @@ 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.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.SimpleChannel
import net.minecraftforge.network.simple.SimpleChannel
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kommons.util.Delegate
import ru.dbotthepony.kommons.util.getValue
@ -22,6 +21,7 @@ import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.locks.LockSupport
import java.util.function.BiConsumer
import java.util.function.Function
import java.util.function.Supplier
import kotlin.reflect.KClass
class MNetworkContext(val sender: ServerPlayer?, packetHandled: Delegate<Boolean>, private val enqueuer: (Runnable) -> CompletableFuture<*>) {
@ -38,18 +38,14 @@ interface MatteryPacket {
}
abstract class MatteryNetworkChannel(val version: Int, val name: String) {
val channel: SimpleChannel = ChannelBuilder
.named(ResourceLocation(OverdriveThatMatters.MOD_ID, name))
.clientAcceptedVersions { status, version -> (status == Channel.VersionTest.Status.MISSING || status == Channel.VersionTest.Status.VANILLA) || version == this.version }
.serverAcceptedVersions { status, version -> status == Channel.VersionTest.Status.PRESENT || version == this.version }
.networkProtocolVersion(version)
.simpleChannel()
val channel: SimpleChannel = NetworkRegistry
.newSimpleChannel(ResourceLocation(OverdriveThatMatters.MOD_ID, name), { version.toString() }, { it == NetworkRegistry.ACCEPTVANILLA || it == NetworkRegistry.ABSENT.version || it == version.toString() }, { it == version.toString() })
fun sendToServer(packet: Any) = channel.send(packet, PacketDistributor.SERVER.noArg())
fun sendToServer(packet: Any) = channel.send(PacketDistributor.SERVER.noArg(), packet)
fun send(ply: Player, packet: Any) {
if (ply is ServerPlayer) {
channel.send(packet, PacketDistributor.PLAYER.with(ply))
channel.send(PacketDistributor.PLAYER.with { ply }, packet)
}
}
@ -58,7 +54,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) {
return
}
channel.send(packet, PacketDistributor.TRACKING_ENTITY.with(entity))
channel.send(PacketDistributor.TRACKING_ENTITY.with { entity }, packet)
}
fun sendTrackingAndSelf(entity: Entity, packet: Any) {
@ -66,11 +62,11 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) {
return
}
channel.send(packet, PacketDistributor.TRACKING_ENTITY_AND_SELF.with(entity))
channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with { entity }, packet)
}
fun send(distributor: PacketDistributor.PacketTarget, packet: Any) {
channel.send(packet, distributor)
channel.send(distributor, packet)
}
private var nextNetworkPacketID = 0
@ -87,8 +83,8 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) {
throw IndexOutOfBoundsException("Network message ID overflow!")
}
val builder = channel.messageBuilder(packetClass, direction)
val bridgeHandler = BiConsumer<T, CustomPayloadEvent.Context> { a, b -> handler(a, MNetworkContext(b.sender, Delegate.Of({ b.packetHandled }, { b.packetHandled = it }), b::enqueueWork)) }
val builder = channel.messageBuilder(packetClass, nextNetworkPacketID++)
val bridgeHandler = BiConsumer<T, Supplier<NetworkEvent.Context>> { a, b -> handler(a, MNetworkContext(b.get().sender, Delegate.Of({ b.get().packetHandled }, { b.get().packetHandled = it }), b.get()::enqueueWork)) }
if (handleOnMainThread) {
builder.consumerMainThread(bridgeHandler)

View File

@ -1,9 +1,11 @@
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
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingBookCategory
@ -99,16 +101,12 @@ class EnergyContainerRecipe(val parent: ShapedRecipe) : CraftingRecipe, IShapedR
}
companion object : RecipeSerializer<EnergyContainerRecipe> {
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 fromJson(p_44103_: ResourceLocation, p_44104_: JsonObject): EnergyContainerRecipe {
return EnergyContainerRecipe(ShapedRecipe.Serializer.SHAPED_RECIPE.fromJson(p_44103_, p_44104_))
}
override fun toNetwork(buff: FriendlyByteBuf, value: EnergyContainerRecipe) {

View File

@ -42,6 +42,7 @@ interface IMatterEntanglerRecipe : IMatteryRecipe<CraftingContainer> {
}
open class MatterEntanglerRecipe(
private val id: ResourceLocation,
override val ingredients: IIngredientMatrix,
override val matter: Decimal,
override val ticks: Double,
@ -50,6 +51,10 @@ open class MatterEntanglerRecipe(
val uuidKey: String = "uuid",
val fixedUuid: Optional<UUID> = Optional.empty()
) : IMatterEntanglerRecipe {
override fun getId(): ResourceLocation {
return id
}
override fun matches(container: CraftingContainer, level: Level): Boolean {
if (isIncomplete) return false
return ingredients.test(container)
@ -98,8 +103,8 @@ open class MatterEntanglerRecipe(
return ItemStack(MItems.MATTER_ENTANGLER)
}
fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this, id)
fun toFinished(): FinishedRecipe {
return SERIALIZER.toFinished(this)
}
fun energetic() = Energy(this)
@ -114,8 +119,8 @@ open class MatterEntanglerRecipe(
}
}
fun toFinished(id: ResourceLocation): FinishedRecipe {
return ENERGY_SERIALIZER.toFinished(this, id)
fun toFinished(): FinishedRecipe {
return ENERGY_SERIALIZER.toFinished(this)
}
override fun getSerializer(): RecipeSerializer<*> {
@ -132,8 +137,8 @@ open class MatterEntanglerRecipe(
}
}
fun toFinished(id: ResourceLocation): FinishedRecipe {
return MATTER_SERIALIZER.toFinished(this, id)
fun toFinished(): FinishedRecipe {
return MATTER_SERIALIZER.toFinished(this)
}
override fun getSerializer(): RecipeSerializer<*> {
@ -152,7 +157,7 @@ open class MatterEntanglerRecipe(
Codec.FLOAT.minRange(0f).optionalFieldOf("experience", 0f).forGetter(MatterEntanglerRecipe::experience),
Codec.STRING.optionalFieldOf("uuidKey", "uuid").forGetter(MatterEntanglerRecipe::uuidKey),
UUIDUtil.STRING_CODEC.optionalFieldOf("fixedUuid").forGetter(MatterEntanglerRecipe::fixedUuid)
).apply(it, ::MatterEntanglerRecipe)
).apply(it) { a, b, c, d, e, f, g -> MatterEntanglerRecipe(context.id, a, b, c, d, e, f, g) }
}
}

View File

@ -24,12 +24,17 @@ import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRecipes
abstract class MatteryCookingRecipe(
private val id: ResourceLocation,
val input: Ingredient,
val output: Ingredient,
val count: Int = 1,
val workTime: Int = 200,
val experience: FloatProvider = ConstantFloat.ZERO
) : Recipe<Container> {
override fun getId(): ResourceLocation {
return id
}
override fun matches(container: Container, level: Level): Boolean {
if (isIncomplete)
return false
@ -69,20 +74,21 @@ abstract class MatteryCookingRecipe(
override fun getResultItem(registry: RegistryAccess): ItemStack = outputStack
abstract fun toFinished(id: ResourceLocation): FinishedRecipe
abstract fun toFinished(): FinishedRecipe
}
class MicrowaveRecipe(
id: ResourceLocation,
input: Ingredient,
output: Ingredient,
count: Int = 1,
workTime: Int = 200,
experience: FloatProvider = ConstantFloat.ZERO
) : MatteryCookingRecipe(input, output, count, workTime, experience) {
) : MatteryCookingRecipe(id, input, output, count, workTime, experience) {
override fun getType(): RecipeType<*> = MRecipes.MICROWAVE
override fun getToastSymbol(): ItemStack = ItemStack(MItems.POWERED_SMOKER[null]!!)
override fun getSerializer(): RecipeSerializer<*> = SERIALIZER
override fun toFinished(id: ResourceLocation): FinishedRecipe = SERIALIZER.toFinished(this, id)
override fun toFinished(): FinishedRecipe = SERIALIZER.toFinished(this)
companion object {
val SERIALIZER = Codec2RecipeSerializer<MicrowaveRecipe> { context ->
@ -93,7 +99,7 @@ class MicrowaveRecipe(
Codec.INT.minRange(1).optionalFieldOf("count", 1).forGetter(MicrowaveRecipe::count),
Codec.INT.minRange(0).optionalFieldOf("workTime", 200).forGetter(MicrowaveRecipe::workTime),
FloatProvider.CODEC.optionalFieldOf("experience", ConstantFloat.ZERO).forGetter(MicrowaveRecipe::experience)
).apply(it, ::MicrowaveRecipe)
).apply(it) { a, b, c, d, e -> MicrowaveRecipe(context.id, a, b, c, d, e) }
}
}
}

View File

@ -31,8 +31,13 @@ import ru.dbotthepony.mc.otm.registry.MRecipes
import java.util.function.Predicate
abstract class AbstractPainterRecipe(
private val id: ResourceLocation,
dyes: Map<out DyeColor?, Int>
) : IMatteryRecipe<Container> {
override fun getId(): ResourceLocation {
return id
}
val dyes: Object2IntMap<DyeColor?> = Object2IntMaps.unmodifiable(Object2IntArrayMap(dyes))
abstract fun matches(value: ItemStack): Boolean
@ -106,15 +111,17 @@ abstract class AbstractPainterRecipe(
}
class PainterRecipe(
id: ResourceLocation,
val input: Ingredient,
val output: ItemStack,
dyes: Map<out DyeColor?, Int>
) : AbstractPainterRecipe(dyes) {
) : AbstractPainterRecipe(id, dyes) {
constructor(
id: ResourceLocation,
input: Ingredient,
output: ItemStack,
dyes: Set<DyeColor?>
) : this(input, output, Object2IntArrayMap<DyeColor?>().also { map -> dyes.forEach { map[it] = 1 } })
) : this(id, input, output, Object2IntArrayMap<DyeColor?>().also { map -> dyes.forEach { map[it] = 1 } })
override fun matches(value: ItemStack): Boolean {
return !isIncomplete && input.test(value)
@ -154,8 +161,8 @@ class PainterRecipe(
return MRecipes.PAINTER
}
fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this, id)
fun toFinished(): FinishedRecipe {
return SERIALIZER.toFinished(this)
}
override fun getOutput(container: Container): ItemStack {
@ -169,17 +176,19 @@ class PainterRecipe(
context.ingredients.fieldOf("input").forGetter(PainterRecipe::input),
ItemStack.CODEC.fieldOf("output").forGetter(PainterRecipe::output),
dyesFieldCodec.forGetter(AbstractPainterRecipe::dyes),
).apply(it, ::PainterRecipe)
).apply(it) { a, b, c -> PainterRecipe(context.id, a, b, c) }
}
}
}
}
class PainterArmorDyeRecipe(
id: ResourceLocation,
dyes: Map<out DyeColor?, Int>
) : AbstractPainterRecipe(dyes) {
) : AbstractPainterRecipe(id, dyes) {
constructor(
id: ResourceLocation,
dyes: Set<DyeColor?>
) : this(Object2IntArrayMap<DyeColor?>().also { map -> dyes.forEach { map[it] = 1 } })
) : this(id, Object2IntArrayMap<DyeColor?>().also { map -> dyes.forEach { map[it] = 1 } })
override fun matches(value: ItemStack): Boolean {
return !isIncomplete && value.item is DyeableArmorItem
@ -207,8 +216,8 @@ class PainterArmorDyeRecipe(
override fun isIncomplete(): Boolean = dyes.isEmpty()
fun toFinished(id: ResourceLocation): FinishedRecipe {
return SERIALIZER.toFinished(this, id)
fun toFinished(): FinishedRecipe {
return SERIALIZER.toFinished(this)
}
override fun getOutput(container: Container): ItemStack {
@ -228,11 +237,11 @@ class PainterArmorDyeRecipe(
}
companion object {
val SERIALIZER = Codec2RecipeSerializer<PainterArmorDyeRecipe> { _ ->
val SERIALIZER = Codec2RecipeSerializer<PainterArmorDyeRecipe> { context ->
RecordCodecBuilder.create {
it.group(
dyesFieldCodec.forGetter(AbstractPainterRecipe::dyes),
).apply(it, ::PainterArmorDyeRecipe)
).apply(it) { a -> PainterArmorDyeRecipe(context.id, a) }
}
}
}

View File

@ -24,12 +24,17 @@ import ru.dbotthepony.mc.otm.data.minRange
import ru.dbotthepony.mc.otm.registry.MItems
class PlatePressRecipe(
private val id: ResourceLocation,
val input: Ingredient,
val output: Ingredient,
val count: Int = 1,
val workTime: Int = 200,
val experience: FloatProvider = ConstantFloat.ZERO
) : Recipe<Container> {
override fun getId(): ResourceLocation {
return id
}
override fun matches(container: Container, p_44003_: Level): Boolean {
if (isIncomplete)
return false
@ -79,7 +84,7 @@ class PlatePressRecipe(
return ItemStack(MItems.TWIN_PLATE_PRESS[null]!!)
}
fun toFinished(id: ResourceLocation) = SERIALIZER.toFinished(this, id)
fun toFinished() = SERIALIZER.toFinished(this)
companion object {
val SERIALIZER = Codec2RecipeSerializer<PlatePressRecipe> { context ->
@ -90,7 +95,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, ::PlatePressRecipe)
).apply(it) { a, b, c, d, e -> PlatePressRecipe(context.id, a, b, c, d, e) }
}
}
}

View File

@ -1,16 +1,12 @@
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
@ -25,68 +21,66 @@ import net.minecraftforge.common.crafting.IShapedRecipe
import ru.dbotthepony.mc.otm.container.util.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.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 ru.dbotthepony.mc.otm.data.RecipePair
import ru.dbotthepony.mc.otm.data.codec
import ru.dbotthepony.mc.otm.data.SingletonCodec
import java.util.stream.Stream
class UpgradeRecipe(
val parent: ShapedRecipe,
val parent: RecipePair<ShapedRecipe>,
copyPaths: Stream<Op>,
val source: ResourceLocation,
) : CraftingRecipe, IShapedRecipe<CraftingContainer> by parent {
constructor(parent: ShapedRecipe, copyPaths: Collection<Op>, source: ResourceLocation) : this(parent, copyPaths.stream(), source)
) : CraftingRecipe, IShapedRecipe<CraftingContainer> by parent.recipe {
constructor(parent: RecipePair<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_)
return parent.recipe.matches(p_44002_, p_44003_)
}
override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int): Boolean {
return parent.canCraftInDimensions(p_43999_, p_44000_)
return parent.recipe.canCraftInDimensions(p_43999_, p_44000_)
}
override fun getResultItem(p_267052_: RegistryAccess): ItemStack {
return parent.getResultItem(p_267052_)
return parent.recipe.getResultItem(p_267052_)
}
override fun getRemainingItems(p_44004_: CraftingContainer): NonNullList<ItemStack> {
return parent.getRemainingItems(p_44004_)
return parent.recipe.getRemainingItems(p_44004_)
}
override fun getIngredients(): NonNullList<Ingredient> {
return parent.ingredients
return parent.recipe.ingredients
}
override fun isSpecial(): Boolean {
return parent.isSpecial
return parent.recipe.isSpecial
}
override fun showNotification(): Boolean {
return parent.showNotification()
return parent.recipe.showNotification()
}
override fun getGroup(): String {
return parent.group
return parent.recipe.group
}
override fun getToastSymbol(): ItemStack {
return parent.toastSymbol
return parent.recipe.toastSymbol
}
override fun isIncomplete(): Boolean {
return parent.isIncomplete
return parent.recipe.isIncomplete
}
override fun getType(): RecipeType<*> {
return parent.type
return parent.recipe.type
}
override fun category(): CraftingBookCategory {
return parent.category()
return parent.recipe.category()
}
enum class OpType : StringRepresentable {
@ -208,7 +202,7 @@ class UpgradeRecipe(
val copyPaths: ImmutableList<Op> = copyPaths.collect(ImmutableList.toImmutableList())
override fun assemble(pInv: CraftingContainer, registryAccess: RegistryAccess): ItemStack {
val result = parent.assemble(pInv, registryAccess)
val result = parent.recipe.assemble(pInv, registryAccess)
if (result.isEmpty) {
return result
@ -242,7 +236,7 @@ class UpgradeRecipe(
val CODEC = Codec2RecipeSerializer<UpgradeRecipe> { p ->
RecordCodecBuilder.create {
it.group(
p.wrap(ShapedRecipe.Serializer.SHAPED_RECIPE).fieldOf("parent").forGetter(UpgradeRecipe::parent),
ShapedRecipe.Serializer.SHAPED_RECIPE.codec(p).fieldOf("parent").forGetter(UpgradeRecipe::parent),
COPY_PATHS_CODEC.fieldOf("copyPaths").forGetter(UpgradeRecipe::copyPaths),
ResourceLocation.CODEC.fieldOf("source").forGetter(UpgradeRecipe::source)
).apply(it, ::UpgradeRecipe)

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.Codec2Serializer
import ru.dbotthepony.mc.otm.data.SingletonCodec
import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition
import ru.dbotthepony.mc.otm.data.condition.HasExoPackCondition
@ -17,12 +18,12 @@ import ru.dbotthepony.mc.otm.data.condition.ChanceCondition
object MLootItemConditions {
private val registry = MDeferredRegister(Registries.LOOT_CONDITION_TYPE, OverdriveThatMatters.MOD_ID)
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) }
val HAS_EXOPACK: LootItemConditionType by registry.register("has_exopack") { LootItemConditionType(Codec2Serializer(SingletonCodec(HasExoPackCondition))) }
val CHANCE_WITH_PLAYTIME: LootItemConditionType by registry.register("chance_with_playtime") { LootItemConditionType(Codec2Serializer(ChanceWithPlaytimeCondition.CODEC)) }
val ITEM_IN_INVENTORY: LootItemConditionType by registry.register("item_in_inventory") { LootItemConditionType(Codec2Serializer(ItemInInventoryCondition.CODEC)) }
val KILLED_BY_REAL_PLAYER: LootItemConditionType by registry.register("killed_by_real_player") { LootItemConditionType(Codec2Serializer(SingletonCodec(KilledByRealPlayer))) }
val KILLED_BY_REAL_PLAYER_OR_INDIRECTLY: LootItemConditionType by registry.register("killed_by_real_player_or_indirectly") { LootItemConditionType(Codec2Serializer(SingletonCodec(KilledByRealPlayerOrIndirectly))) }
val CHANCE: LootItemConditionType by registry.register("chance") { LootItemConditionType(Codec2Serializer(ChanceCondition.CODEC)) }
internal fun register(bus: IEventBus) {
registry.register(bus)

View File

@ -334,28 +334,28 @@ object MRegistry : IBlockItemRegistryAcceptor {
NanobotsArmorFeature.Companion
EnderTeleporterFeature.Companion
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)
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)
}
private fun initializeCommon(event: FMLCommonSetupEvent) {

View File

@ -4,6 +4,7 @@ import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.critereon.ContextAwarePredicate
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 net.minecraft.resources.ResourceLocation
@ -35,9 +36,9 @@ class HurtTrigger(id: ResourceLocation) : MCriterionTrigger<HurtTrigger.Instance
val damagePredicate: Optional<DamagePredicate> = Optional.of(DamagePredicate(
MinMaxBounds.Doubles.atLeast(1.0),
MinMaxBounds.Doubles.atLeast(1.0),
Optional.empty(),
Optional.empty(),
Optional.empty()
EntityPredicate.ANY,
null,
DamageSourcePredicate.ANY
)),
player: Optional<ContextAwarePredicate> = Optional.empty()
) : AbstractInstance(player)

View File

@ -7,6 +7,7 @@ import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.data.ItemPredicateCodec
import java.util.*
class ItemTrigger(id: ResourceLocation) : MCriterionTrigger<ItemTrigger.Instance>(id) {
@ -16,7 +17,7 @@ class ItemTrigger(id: ResourceLocation) : MCriterionTrigger<ItemTrigger.Instance
override val codec: Codec<Instance> = RecordCodecBuilder.create {
it.group(
ItemPredicate.CODEC.fieldOf("predicate").forGetter(Instance::predicate),
ItemPredicateCodec.fieldOf("predicate").forGetter(Instance::predicate),
Codec.BOOL.optionalFieldOf("invert", false).forGetter(Instance::invert),
playerPredicateCodec.forGetter(Instance::playerPredicate)
).apply(it, ::Instance)

View File

@ -17,6 +17,7 @@ import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.SerializationContext
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.PlayerAdvancements
import net.minecraft.server.level.ServerPlayer
@ -29,7 +30,11 @@ import java.util.function.Predicate
// allows to support both 1.20.1 and 1.20.2 with ease
// and has slightly less memory footprint than vanilla SimpleCriterionTrigger
abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(val id: ResourceLocation) : CriterionTrigger<T> {
abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(private val id: ResourceLocation) : CriterionTrigger<T> {
override fun getId(): ResourceLocation {
return id
}
private val listeners = Reference2ObjectOpenHashMap<PlayerAdvancements, ObjectOpenHashSet<CriterionTrigger.Listener<T>>>()
override fun addPlayerListener(advancements: PlayerAdvancements, listener: CriterionTrigger.Listener<T>) {
@ -62,16 +67,25 @@ abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(val
val context = EntityPredicate.createContext(player, player)
listeners.iterator()
.filter { predicate.test(it.trigger) && it.trigger.playerPredicate.map { it.matches(context) }.orElse(true) }
.filter { predicate.test(it.triggerInstance) && it.triggerInstance.playerPredicate.map { it.matches(context) }.orElse(true) }
.toImmutableList()
.forEach { it.run(advancements) }
}
abstract inner class AbstractInstance(val playerPredicate: Optional<ContextAwarePredicate>) : CriterionTriggerInstance {
fun criterion() = Criterion(this@MCriterionTrigger, this as T)
fun criterion() = Criterion(this as T)
final override fun serializeToJson(): JsonObject {
return codec.toJsonStrict(this as T) as JsonObject
override fun getCriterion(): ResourceLocation {
return id
}
final override fun serializeToJson(context: SerializationContext): JsonObject {
return try {
serializationContext.get().addLast(context)
codec.toJsonStrict(this as T) as JsonObject
} finally {
serializationContext.get().removeLast()
}
}
}
@ -82,17 +96,23 @@ abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(val
}
}
protected val serializationContext = object : ThreadLocal<ArrayDeque<SerializationContext>>() {
override fun initialValue(): ArrayDeque<SerializationContext> {
return ArrayDeque()
}
}
@JvmStatic
protected val predicateCodec: Codec<ContextAwarePredicate> = object : Codec<ContextAwarePredicate> {
override fun <T : Any?> encode(input: ContextAwarePredicate, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson()))
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson(serializationContext.get().lastOrNull() ?: return DataResult.error { "Not serializing trigger instance" })))
}
override fun <T : Any?> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<ContextAwarePredicate, T>> {
val context = deserializationContext.get().lastOrNull() ?: return DataResult.error { "Not current deserializing trigger instance" }
return try {
DataResult.success(Pair.of(EntityPredicate.fromJson(JsonObject().also { it["a"] = ops.convertTo(JsonOps.INSTANCE, input) }, "a", context).get(), ops.empty()))
DataResult.success(Pair.of(EntityPredicate.fromJson(JsonObject().also { it["a"] = ops.convertTo(JsonOps.INSTANCE, input) }, "a", context), ops.empty()))
} catch (err: Exception) {
DataResult.error { "Failed to deserialize ContextAwarePredicate: " + err.message }
}

View File

@ -14,6 +14,7 @@ import net.minecraft.advancements.CriterionTrigger
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.InventoryChangeTrigger
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.world.Container
@ -83,13 +84,13 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
nodes.add(Node(
DefaultStrategy,
{ predicates.iterator().flatMap { (it.items.map { it.map { it.value() } }.orElse(listOf(null))).iterator() }.toList() },
{ predicates.iterator().flatMap { (it.items ?: 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.orElse(null) } },
{ predicates.map { it.tag } },
{ v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.`is`(v) },
{ inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> item.tags.collect(Collectors.toCollection(::ArrayList)) }))
@ -133,13 +134,13 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
fun add(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
if (set.add(listener)) {
search(listener.trigger, tree, 0).forEach { it.add(listener) }
search(listener.triggerInstance, tree, 0).forEach { it.add(listener) }
}
}
fun remove(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
if (set.remove(listener)) {
search(listener.trigger, tree, 0).forEach { it.remove(listener) }
search(listener.triggerInstance, tree, 0).forEach { it.remove(listener) }
}
}
@ -165,7 +166,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.trigger) {
with (l.triggerInstance) {
if (
this.slotsFull.matches(slotsFull) &&
this.slotsEmpty.matches(slotsEmpty) &&
@ -217,6 +218,10 @@ object MatteryInventoryChangeTrigger : CriterionTrigger<InventoryChangeTrigger.T
listeners[advancements]?.remove(instance)
}
override fun getId(): ResourceLocation {
return CriteriaTriggers.INVENTORY_CHANGED.id
}
override fun removePlayerListeners(advancements: PlayerAdvancements) {
listeners.remove(advancements)
}

View File

@ -7,12 +7,13 @@ 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.data.DoublesCodec
import java.util.*
object NanobotsArmorTrigger : MCriterionTrigger<NanobotsArmorTrigger.Instance>(ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor")) {
override val codec: Codec<Instance> = RecordCodecBuilder.create {
it.group(
Doubles.CODEC.fieldOf("predicate").forGetter(Instance::predicate),
DoublesCodec.fieldOf("predicate").forGetter(Instance::predicate),
playerPredicateCodec.forGetter(Instance::playerPredicate),
).apply(it, ::Instance)
}

View File

@ -13,7 +13,7 @@ class SingletonTrigger(id: ResourceLocation) : MCriterionTrigger<SingletonTrigge
}
val empty = Instance()
val criterion = Criterion(this@SingletonTrigger, empty)
val criterion = Criterion(empty)
inner class Instance(player: Optional<ContextAwarePredicate> = Optional.empty()) : AbstractInstance(player)
}

View File

@ -172,3 +172,18 @@ public net.minecraft.advancements.critereon.InventoryChangeTrigger$TriggerInstan
#public-f net.minecraft.advancements.critereon.SimpleCriterionTrigger m_6467_(Lnet/minecraft/server/PlayerAdvancements;Lnet/minecraft/advancements/CriterionTrigger$Listener;)V # addPlayerListener
#public-f net.minecraft.advancements.critereon.SimpleCriterionTrigger m_6468_(Lnet/minecraft/server/PlayerAdvancements;Lnet/minecraft/advancements/CriterionTrigger$Listener;)V # removePlayerListener
#public-f net.minecraft.advancements.critereon.SimpleCriterionTrigger m_5656_(Lnet/minecraft/server/PlayerAdvancements;)V # removePlayerListeners
public net.minecraft.advancements.critereon.ItemPredicate f_45031_
public net.minecraft.advancements.critereon.ItemPredicate f_45032_
public net.minecraft.advancements.critereon.ItemPredicate f_45033_
public net.minecraft.advancements.critereon.ItemPredicate f_151427_
public net.minecraft.advancements.critereon.ItemPredicate f_45036_
public net.minecraft.advancements.critereon.ItemPredicate f_45035_
public net.minecraft.advancements.critereon.ItemPredicate f_45034_
public net.minecraft.advancements.critereon.ItemPredicate f_45029_
public net.minecraft.advancements.critereon.DamagePredicate f_24906_ # blocked
public net.minecraft.advancements.critereon.DamagePredicate f_24903_ # dealtDamage
public net.minecraft.advancements.critereon.DamagePredicate f_24905_ # sourceEntity
public net.minecraft.advancements.critereon.DamagePredicate f_24904_ # takenDamage
public net.minecraft.advancements.critereon.DamagePredicate f_24907_ # type

View File

@ -41,7 +41,7 @@ Matter. Energy. Combined.
# Does this dependency have to exist - if not, ordering below must be specified
mandatory=true #mandatory
# The version range of the dependency
versionRange="[48.0.0,)" #mandatory
versionRange="[47.0.0,)" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
@ -51,6 +51,6 @@ Matter. Energy. Combined.
modId="minecraft"
mandatory=true
# This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange="[1.20.2,1.21)"
versionRange="[1.20.1,1.20.2)"
ordering="NONE"
side="BOTH"