Skip to content

Commit

Permalink
Merge pull request #25 from Robustum/tag_update
Browse files Browse the repository at this point in the history
タグおよびレシピ回りの拡張を追加
  • Loading branch information
Hiiragi283 authored Dec 17, 2024
2 parents 00762a1 + 4c7e7c6 commit ca73c29
Show file tree
Hide file tree
Showing 39 changed files with 1,882 additions and 8 deletions.
24 changes: 22 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,24 @@ repositories {
}
}

val testAgent = configurations.create("testAgent") {
isCanBeConsumed = false
}

dependencies {
minecraft(libs.minecraft)
mappings("net.fabricmc:yarn:${libs.versions.fabric.yarn.get()}:v2")
modImplementation(libs.bundles.mods.fabric)
modLocalRuntime(libs.bundles.mods.debug)
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation(libs.fabric.loader.junit)
testImplementation(libs.bundles.kotest)
testAgent(project(path = ":test-agent", configuration = "agentJar"))
}

loom {
accessWidenerPath = file("src/main/resources/robustum_core.accesswidener")

mods {
create("robustum_core") {
sourceSet(sourceSets.main.get())
Expand All @@ -43,14 +52,14 @@ loom {
kotlin {
jvmToolchain(21)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)
jvmTarget.set(JvmTarget.JVM_21)
}
}

java {
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_21
}

ktlint {
Expand All @@ -68,6 +77,17 @@ ktlint {
tasks {
test {
useJUnitPlatform()
val runDir = file("build/test_run")
workingDir = runDir

// Workaround https://github.com/FabricMC/fabric-loader/issues/817
// Original: https://github.com/embeddedt/ModernFix/commit/03b23957827c42d5df5a11f3d07f807c5343e87e
jvmArgs("-javaagent:${testAgent.singleFile.absolutePath}")
dependsOn(testAgent)

doFirst {
runDir.mkdir()
}
}
processResources {
inputs.property("version", project.version)
Expand Down
11 changes: 11 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,29 @@ fabric-loader = "0.16.9"
fabric-api = "0.42.0+1.16"
fabric-yarn = "1.16.5+build.10"
fabric-kotlin = "1.12.3+kotlin.2.0.21"
asm = "9.1"
kotest = "5.9.1"

[libraries]
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
fabric-kotlin = { group = "net.fabricmc", name = "fabric-language-kotlin", version.ref = "fabric-kotlin"}
asm-tree = { group = "org.ow2.asm", name = "asm-tree", version.ref = "asm" }
asm-commons = { group = "org.ow2.asm", name = "asm-commons", version.ref = "asm" }
asm-util = { group = "org.ow2.asm", name = "asm-util", version.ref = "asm" }
# test libraries
fabric-loader-junit = { group = "net.fabricmc", name = "fabric-loader-junit", version.ref = "fabric-loader" }
kotest-runner-junit5 = { group = "io.kotest", name = "kotest-runner-junit5", version.ref = "kotest" }
kotest-assersions-core = { group = "io.kotest", name = "kotest-assertions-core", version.ref = "kotest" }

mod-modmenu = { group = "maven.modrinth", name = "modmenu", version = "1.16.23" }

[bundles]
mods-fabric = ["fabric-loader", "fabric-api", "fabric-kotlin"]
mods-debug = ["mod-modmenu"]
asm = [ "asm-tree", "asm-commons", "asm-util" ]
kotest = [ "kotest-runner-junit5", "kotest-assersions-core" ]

[plugins]
fabric-loom = { id = "fabric-loom", version.ref = "fabric-loom" }
Expand Down
Empty file modified gradlew
100644 → 100755
Empty file.
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
}
rootProject.name = "robustum-core"

include("test-agent")
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.robustum.core.mixin.codec;

import net.minecraft.recipe.Ingredient;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(Ingredient.class)
public interface IngredientAccessor {
@Accessor
Ingredient.Entry[] getEntries();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.robustum.core.mixin.tag;

import dev.robustum.core.tag.RobustumTagEvents;
import net.fabricmc.api.EnvType;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.packet.s2c.play.SynchronizeTagsS2CPacket;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ClientPlayNetworkHandler.class)
public abstract class ClientPlayNetworkHandlerMixin {
@Unique
private static final Logger LOGGER = LogManager.getLogger(ClientPlayNetworkHandlerMixin.class);

@Inject(method = "onSynchronizeTags", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;getSearchableContainer(Lnet/minecraft/client/search/SearchManager$Key;)Lnet/minecraft/client/search/SearchableContainer;"))
private void robustum$onSynchronizeTags(SynchronizeTagsS2CPacket packet, CallbackInfo ci) {
RobustumTagEvents.RELOAD.invoker().onReload(packet.getTagManager(), EnvType.CLIENT);
LOGGER.info("Client TagManager reloaded!");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.robustum.core.mixin.tag;

import dev.robustum.core.tag.RobustumTagEvents;
import net.fabricmc.api.EnvType;
import net.minecraft.tag.ServerTagManagerHolder;
import net.minecraft.tag.TagManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ServerTagManagerHolder.class)
public abstract class ServerTagManagerHolderMixin {
@Unique
private static final Logger LOGGER = LogManager.getLogger(ServerTagManagerHolderMixin.class);

@Inject(method = "setTagManager", at = @At("TAIL"))
private static void robustum$setTagManager(TagManager tagManager, CallbackInfo ci) {
RobustumTagEvents.RELOAD.invoker().onReload(tagManager, EnvType.SERVER);
LOGGER.info("Server TagManager reloaded!");
}
}
46 changes: 46 additions & 0 deletions src/main/java/dev/robustum/core/mixin/tag/TagGroupLoaderMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dev.robustum.core.mixin.tag;

import dev.robustum.core.RobustumCore;
import dev.robustum.core.tag.RobustumTagEvents;
import net.minecraft.resource.ResourceManager;
import net.minecraft.tag.Tag;
import net.minecraft.tag.TagGroupLoader;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Map;

@Mixin(TagGroupLoader.class)
public abstract class TagGroupLoaderMixin<T> {
@Final
@Shadow
private String entryType;

@Nullable
@Unique
private Registry<?> findRegistry() {
return switch (entryType) {
case "block" -> Registry.BLOCK;
case "item" -> Registry.ITEM;
case "fluid" -> Registry.FLUID;
case "entity_type" -> Registry.ENTITY_TYPE;
default -> null;
};
}

@Inject(method = "method_18243", at = @At("RETURN"))
private void robustum$method_18243(ResourceManager resourceManager, CallbackInfoReturnable<Map<Identifier, Tag.Builder>> cir) {
Registry<?> registry = findRegistry();
if (registry == null) return;
RobustumTagEvents.REGISTER.invoker().onRegister(new RobustumTagEvents.Helper(registry, (@NotNull Identifier tagId, Tag.@NotNull Entry entry) -> cir.getReturnValue().computeIfAbsent(tagId, k -> Tag.Builder.create()).add(entry, RobustumCore.MOD_NAME)));
}
}
18 changes: 13 additions & 5 deletions src/main/kotlin/dev/robustum/core/RobustumCore.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package dev.robustum.core

import dev.robustum.core.recipe.RobustumRecipeSerializers
import net.fabricmc.api.ModInitializer
import net.minecraft.util.Identifier
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger

class RobustumCore : ModInitializer {
companion object {
const val MOD_ID = "robustum_core"
private val logger = LogManager.getLogger(RobustumCore::class.java)
}
object RobustumCore : ModInitializer {
const val MOD_ID = "robustum_core"
const val MOD_NAME = "Robustum Core"

@JvmStatic
fun id(path: String): Identifier = Identifier(MOD_ID, path)

private val logger: Logger = LogManager.getLogger(RobustumCore::class.java)

override fun onInitialize() {
RobustumRecipeSerializers

logger.info("Robustum Core is loaded!")
}
}
81 changes: 81 additions & 0 deletions src/main/kotlin/dev/robustum/core/codec/KeyDispatchCodec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package dev.robustum.core.codec

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.MapCodec
import com.mojang.serialization.MapDecoder
import com.mojang.serialization.MapEncoder
import com.mojang.serialization.MapLike
import com.mojang.serialization.RecordBuilder
import dev.robustum.core.extensions.isErrored
import java.util.function.Function
import java.util.stream.Stream

class KeyDispatchCodec<K : Any, V : Any>(
val typeKey: String,
val keyCodec: Codec<K>,
val type: (V) -> DataResult<K>,
val decoder: (K) -> DataResult<out MapDecoder<V>>,
val encoder: (V) -> DataResult<out MapEncoder<V>>,
) : MapCodec<V>() {
companion object {
@JvmStatic
private fun <K : Any, V : Any> getCodec(
type: (V) -> DataResult<K>,
codec: (K) -> DataResult<MapCodec<V>>,
input: V,
): DataResult<MapEncoder<V>> = type(input)
.flatMap { key: K -> codec(key).map(Function.identity()) }
}

constructor(
typeKey: String,
keyCodec: Codec<K>,
type: (V) -> DataResult<K>,
codec: (K) -> DataResult<MapCodec<V>>,
) : this(typeKey, keyCodec, type, codec, { input: V -> getCodec(type, codec, input) })

private val valueKey = "value"

override fun <T : Any> keys(ops: DynamicOps<T>): Stream<T> = Stream.of(typeKey, valueKey).map(ops::createString)

override fun <T : Any> decode(ops: DynamicOps<T>, input: MapLike<T>): DataResult<V> {
val elementName: T =
input.get(typeKey) ?: return DataResult.error("Input does not contain a key [$typeKey]: $input")
return keyCodec.decode(ops, elementName).flatMap { type1: Pair<K, T> ->
decoder(type1.first).flatMap { elementDecoder: MapDecoder<V> ->
if (ops.compressMaps()) {
input
.get(ops.createString(valueKey))
?.let { value: T -> elementDecoder.decoder().parse(ops, value).map(Function.identity()) }
?: return@flatMap DataResult.error("Input does not have a \"value\" entry: $input")
} else {
elementDecoder.decode(ops, input).map(Function.identity())
}
}
}
}

override fun <T : Any> encode(input: V, ops: DynamicOps<T>, prefix: RecordBuilder<T>): RecordBuilder<T> {
val encodeResult: DataResult<out MapEncoder<V>> = encoder(input)
val builder: RecordBuilder<T> = prefix.withErrorsFrom(encodeResult)
if (encodeResult.isErrored) {
Result
return builder
}
val elementEncoder: MapEncoder<V> = encodeResult.result().get()
return when {
ops.compressMaps() ->
prefix
.add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) })
.add(valueKey, elementEncoder.encoder().encodeStart(ops, input))

else ->
elementEncoder
.encode(input, ops, prefix)
.add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) })
}
}
}
26 changes: 26 additions & 0 deletions src/main/kotlin/dev/robustum/core/codec/OptionalCodec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.robustum.core.codec

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.MapLike
import java.util.*

class OptionalCodec<A : Any>(val codec: Codec<A>) : Codec<Optional<A>> {
override fun <T : Any> encode(input: Optional<A>, ops: DynamicOps<T>, prefix: T): DataResult<T> = when (input.isEmpty) {
true -> DataResult.success(ops.emptyMap())
false -> codec.encode(input.get(), ops, prefix)
}

private fun <T : Any> isEmpty(ops: DynamicOps<T>, input: T): Boolean = ops
.getMap(input)
.result()
.map { mapLike: MapLike<T> -> mapLike.entries().findAny().isEmpty }
.orElse(false)

override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Optional<A>, T>> = when {
isEmpty(ops, input) -> DataResult.success(Pair.of(Optional.empty(), input))
else -> codec.decode(ops, input).map { pair: Pair<A, T> -> pair.mapFirst(Optional<A>::of) }
}
}
Loading

0 comments on commit ca73c29

Please sign in to comment.