aboutsummaryrefslogtreecommitdiff
path: root/src/texturePacks/java/moe/nea/firmament/features/texturepack/PredicateModel.kt
blob: e53c9c734982f2fdf4bb41e00ebc6089f40b2061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package moe.nea.firmament.features.texturepack

import com.google.gson.JsonObject
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.client.renderer.item.ItemModelResolver
import net.minecraft.client.renderer.item.ItemStackRenderState
import net.minecraft.client.renderer.item.BlockModelWrapper
import net.minecraft.client.renderer.item.ItemModel
import net.minecraft.client.renderer.item.ItemModels
import net.minecraft.client.resources.model.ResolvableModel
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemDisplayContext
import net.minecraft.world.item.ItemStack
import net.minecraft.world.entity.ItemOwner
import net.minecraft.resources.ResourceLocation
import moe.nea.firmament.features.texturepack.predicates.AndPredicate

class PredicateModel {
	data class Baked(
        val fallback: ItemModel,
        val overrides: List<Override>
	) : ItemModel {
		data class Override(
            val model: ItemModel,
            val predicate: FirmamentModelPredicate,
		)

		override fun update(
            state: ItemStackRenderState?,
            stack: ItemStack,
            resolver: ItemModelResolver?,
            displayContext: ItemDisplayContext?,
            world: ClientLevel?,
            heldItemContext: ItemOwner?,
            seed: Int
		) {
			val model =
				overrides
					.findLast { it.predicate.test(stack, heldItemContext?.asLivingEntity()) }
					?.model
					?: fallback
			model.update(state, stack, resolver, displayContext, world, heldItemContext, seed)
		}
	}

	data class Unbaked(
        val fallback: ItemModel.Unbaked,
        val overrides: List<Override>,
	) : ItemModel.Unbaked {
		companion object {
			@JvmStatic
			fun fromLegacyJson(jsonObject: JsonObject, fallback: ItemModel.Unbaked): ItemModel.Unbaked {
				val legacyOverrides = jsonObject.getAsJsonArray("overrides") ?: return fallback
				val newOverrides = ArrayList<Override>()
				for (legacyOverride in legacyOverrides) {
					legacyOverride as JsonObject
					val overrideModel = ResourceLocation.tryParse(legacyOverride.get("model")?.asString ?: continue) ?: continue
					val predicate = CustomModelOverrideParser.parsePredicates(legacyOverride.getAsJsonObject("predicate"))
					newOverrides.add(Override(
						BlockModelWrapper.Unbaked(overrideModel, listOf()),
						AndPredicate(predicate.toTypedArray())
					))
				}
				return Unbaked(fallback, newOverrides)
			}

			val OVERRIDE_CODEC: Codec<Override> = RecordCodecBuilder.create {
				it.group(
					ItemModels.CODEC.fieldOf("model").forGetter(Override::model),
					CustomModelOverrideParser.LEGACY_CODEC.fieldOf("predicate").forGetter(Override::predicate),
				).apply(it, Unbaked::Override)
			}
			val CODEC: MapCodec<Unbaked> =
				RecordCodecBuilder.mapCodec {
					it.group(
						ItemModels.CODEC.fieldOf("fallback").forGetter(Unbaked::fallback),
						OVERRIDE_CODEC.listOf().fieldOf("overrides").forGetter(Unbaked::overrides),
					).apply(it, ::Unbaked)
				}
		}

		data class Override(
            val model: ItemModel.Unbaked,
            val predicate: FirmamentModelPredicate,
		)

		override fun resolveDependencies(resolver: ResolvableModel.Resolver) {
			fallback.resolveDependencies(resolver)
			overrides.forEach { it.model.resolveDependencies(resolver) }
		}

		override fun type(): MapCodec<out Unbaked> {
			return CODEC
		}

		override fun bake(context: ItemModel.BakingContext): ItemModel {
			return Baked(
				fallback.bake(context),
				overrides.map { Baked.Override(it.model.bake(context), it.predicate) }
			)
		}
	}
}