Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OptiGUI Extra - OptiGUI integration with other mods #71

Draft
wants to merge 15 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions Extra/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
plugins {
id("fabric-loom")
kotlin("jvm")
}

evaluationDependsOn(":OptiGUI")
evaluationDependsOn(":Api")
evaluationDependsOn(":Properties")

base { archivesName.set(project.extra["archives_base_name"] as String) }

version = project.extra["mod_version"] as String
group = project.extra["maven_group"] as String

repositories {
mavenLocal()
exclusiveContent {
forRepository {
maven("https://api.modrinth.com/maven") { name = "Modrinth" }
}
filter {
includeGroup("maven.modrinth")
}
}
maven("https://cursemaven.com") {
name = "CurseForge"
content {
includeGroup("curse.maven")
}
}
}

val extractNestedJars by configurations.creating
val nestedJarsDir = buildDir.resolve("nestedJars")

dependencies {
minecraft("com.mojang", "minecraft", project.extra["minecraft_version"] as String)
mappings("net.fabricmc", "yarn", project.extra["yarn_mappings"] as String, classifier = "v2")
modImplementation("net.fabricmc", "fabric-loader", project.extra["loader_version"] as String)
modImplementation(
"net.fabricmc", "fabric-language-kotlin", project.extra["fabric_language_kotlin_version"] as String
)

modImplementation(fabricApi.module("fabric-events-interaction-v0", project.extra["fabric_version"] as String))
modLocalRuntime("net.fabricmc.fabric-api", "fabric-api", project.extra["fabric_version"] as String)

modImplementation(files(rootDir.resolve("lib/lilac-api-1.0.0-alpha.1-dev.jar")))
modLocalRuntime(files(rootDir.resolve("lib/lilac-1.0.0-alpha.1-dev.jar")))

localRuntime(project(":OptiGUI", configuration = "namedElements"))
implementation(project(":Api", configuration = "namedElements"))
implementation(project(":Properties", configuration = "namedElements"))

extractNestedJars(modImplementation("maven.modrinth", "quickshulker", "1.4.0-1.20"))
modImplementation("maven.modrinth", "more-chest-variants-lieonlion", "1.2.1-1.20.1-Fabric")
modLocalRuntime("curse.maven", "variant-barrels-fabric-576766", "4623658")
modLocalRuntime("curse.maven", "variant-crafting-tables-fabric-575271", "4723634")
extractNestedJars(modLocalRuntime("curse.maven", "variant-vanilla-blocks-866509", "4723107"))

// Gradle has skill issue and doesn't pull transitive deps.
// But it pulls a newer version of DFU through mavenLocal, which crashes Minecraft.
// Just as the founding fathers intended.
localRuntime("org.apache.commons", "commons-text", "1.10.0")
localRuntime("org.ini4j", "ini4j", "0.5.4")

modLocalRuntime(fileTree(nestedJarsDir))
}

tasks {
val javaVersion = JavaVersion.toVersion((project.extra["java_version"] as String).toInt())

withType<JavaCompile> {
options.encoding = "UTF-8"
sourceCompatibility = javaVersion.toString()
targetCompatibility = javaVersion.toString()
options.release.set(javaVersion.toString().toInt())
}

withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
jvmTarget = javaVersion.toString()
}
}

jar {
from(rootDir.resolve("LICENSE")) {
rename { "${it}_${base.archivesName.get()}" }
}
}

processResources {
filesMatching("fabric.mod.json") {
expand(
mutableMapOf(
"version" to version,
"fabricloader" to project.extra["loader_version"] as String,
"fabric_language_kotlin" to project.extra["fabric_language_kotlin_version"] as String,
"java" to project.extra["java_version"] as String
)
)
}
filesMatching("*.mixins.json") {
expand(mutableMapOf("java" to project.extra["java_version"] as String))
}
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(javaVersion.toString()))
}
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
withSourcesJar()
}
}

val prepareClientRun by tasks.creating {
nestedJarsDir.mkdirs()
outputs.dir(nestedJarsDir)

doLast {
val jars = extractNestedJars.files

jars.forEach { jar ->
zipTree(jar).visit {
if (path.startsWith("META-INF/jars/")) {
copyTo(nestedJarsDir.resolve(name))
}
}
}
}
}

tasks["generateRemapClasspath"].dependsOn(prepareClientRun)
11 changes: 11 additions & 0 deletions Extra/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
##########################################################################
# Standard Fabric Dependencies
# Check these on https://fabricmc.net/develop/
minecraft_version=1.20.1
yarn_mappings=1.20.1+build.1
# Fabric API
fabric_version=0.87.0+1.20.1
##########################################################################
# Mod Properties
archives_base_name=optigui-extra
##########################################################################
16 changes: 16 additions & 0 deletions Extra/src/main/java/opekope2/optigui/extra/Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package opekope2.optigui.extra;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

public class Util {
private Util() {
}

public static <TKey, TValue> Map<TKey, TValue> buildMap(Consumer<Map<TKey, TValue>> mapFiller) {
Map<TKey, TValue> map = new HashMap<>();
mapFiller.accept(map);
return map;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package opekope2.optigui.extra.quickshulker;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.kyrptonaught.quickshulker.QuickShulkerMod;
import net.kyrptonaught.quickshulker.api.Util;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World;
import opekope2.lilac.api.registry.IRegistryLookup;
import opekope2.optigui.api.IOptiGuiApi;
import opekope2.optigui.api.interaction.IInteractionTarget;
import opekope2.optigui.api.interaction.IInteractor;
import opekope2.optigui.properties.impl.CommonProperties;
import opekope2.optigui.properties.impl.GeneralProperties;
import opekope2.optigui.properties.impl.IndependentProperties;

import java.time.LocalDate;
import java.util.function.Consumer;

public class QuickShulkerCompat implements ClientModInitializer, UseItemCallback {
private static final IInteractor interactor = IOptiGuiApi.getImplementation().getInteractor();
private static final IRegistryLookup lookup = IRegistryLookup.getInstance();
private static Consumer<Screen> screenChangeHandler = QuickShulkerCompat::dummyScreenConsumer;

@Override
public void onInitializeClient() {
if (!FabricLoader.getInstance().isModLoaded("quickshulker")) return;

UseItemCallback.EVENT.register(this);
}

@Override
public TypedActionResult<ItemStack> interact(PlayerEntity player, World world, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
if (world.isClient) {
if (QuickShulkerMod.getConfig().rightClickToOpen && Util.isOpenableItem(stack) && Util.canOpenInHand(stack)) {
triggerInteraction(player, world, hand, stack);
}
}

return TypedActionResult.pass(stack);
}

public static void waitForScreen(Consumer<Screen> handler) {
screenChangeHandler = handler;
}

public static void onScreenChanged(Screen screen) {
screenChangeHandler.accept(screen);
screenChangeHandler = QuickShulkerCompat::dummyScreenConsumer;
}

private static void dummyScreenConsumer(Screen screen) {
}

public static void triggerInteraction(PlayerEntity player, World world, Hand hand, ItemStack stack) {
interactor.interact(
player,
world,
hand,
new IInteractionTarget.ComputedTarget(getInteractionTargetData(player, world, stack)),
null
);
}

private static Object getInteractionTargetData(PlayerEntity player, World world, ItemStack stack) {
Identifier biome = lookup.lookupBiomeId(world, player.getBlockPos());
String name = stack.hasCustomName() ? stack.getName().getString() : null;

return new CommonProperties(
new GeneralProperties(
Registries.ITEM.getId(stack.getItem()),
name,
biome,
player.getBlockY()
),
new IndependentProperties(
LocalDate.now()
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package opekope2.optigui.extra.quickshulker.mixin;

import net.kyrptonaught.quickshulker.client.ClientUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.*;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import opekope2.lilac.api.registry.IRegistryLookup;
import opekope2.optigui.extra.Util;
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.CallbackInfoReturnable;

import java.util.Map;
import java.util.Objects;

import static opekope2.optigui.extra.quickshulker.QuickShulkerCompat.triggerInteraction;
import static opekope2.optigui.extra.quickshulker.QuickShulkerCompat.waitForScreen;

@Mixin(ClientUtil.class)
public abstract class ClientUtilMixin {
@Unique
private static final MinecraftClient mc = MinecraftClient.getInstance();
@Unique
private static final IRegistryLookup lookup = IRegistryLookup.getInstance();

@Unique
private static final Map<Identifier, Class<? extends HandledScreen<?>>> containerScreenMapping = Util.buildMap(map -> {
map.put(new Identifier("shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("white_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("orange_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("magenta_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("light_blue_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("yellow_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("lime_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("pink_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("gray_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("light_gray_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("cyan_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("purple_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("blue_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("brown_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("green_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("red_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("black_shulker_box"), ShulkerBoxScreen.class);
map.put(new Identifier("ender_chest"), GenericContainerScreen.class);
map.put(new Identifier("crafting_table"), CraftingScreen.class);
map.put(new Identifier("stonecutter"), StonecutterScreen.class);
map.put(new Identifier("smithing_table"), SmithingScreen.class);
});

@Inject(
method = "CheckAndSend",
at = @At(value = "INVOKE", target = "Lnet/kyrptonaught/quickshulker/client/ClientUtil;SendOpenPacket(I)V")
)
private static void handlePacketSendFromOffHand(ItemStack stack, int slot, CallbackInfoReturnable<Boolean> cir) {
var player = Objects.requireNonNull(mc.player);
var world = Objects.requireNonNull(mc.world);
var screenClass = containerScreenMapping.get(lookup.lookupItemId(stack.getItem()));
if (screenClass == null) return;

waitForScreen(screen -> {
if (screenClass.equals(screen.getClass())) {
triggerInteraction(player, world, stack == mc.player.getOffHandStack() ? Hand.OFF_HAND : Hand.MAIN_HAND, stack);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package opekope2.optigui.extra.quickshulker.mixin;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import opekope2.optigui.extra.quickshulker.QuickShulkerCompat;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(value = MinecraftClient.class, priority = 925)
abstract class MinecraftClientMixin {
@Inject(method = "setScreen(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("TAIL"))
private void setScreenMixin(Screen screen, CallbackInfo ci) {
if (screen != null) {
QuickShulkerCompat.onScreenChanged(screen);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package opekope2.optigui.extra.more_chest_variants

import io.github.lieonlion.mcv.block.MoreChestBlockEntity
import net.minecraft.block.enums.ChestType
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.screen.ScreenHandler
import net.minecraft.state.property.EnumProperty
import opekope2.lilac.api.registry.IRegistryLookup
import opekope2.optigui.annotation.BlockEntityProcessor
import opekope2.optigui.api.interaction.IBlockEntityProcessor
import opekope2.optigui.properties.impl.*
import java.time.LocalDate

@BlockEntityProcessor(MoreChestBlockEntity::class)
object McvCompat : IBlockEntityProcessor<MoreChestBlockEntity> {
private val lookup = IRegistryLookup.getInstance()
private val chestTypeEnum = EnumProperty.of("type", ChestType::class.java)

override fun apply(chest: MoreChestBlockEntity): Any? {
val world = chest.world ?: return null
val state = world.getBlockState(chest.pos)
val type = state.entries[chestTypeEnum]
val screen = MinecraftClient.getInstance().currentScreen
val screenHandler = (screen as? HandledScreen<*>)?.screenHandler as? GenericContainerScreenHandler

return ChestProperties(
commonProperties = CommonProperties(
generalProperties = GeneralProperties(
container = lookup.lookupBlockId(state.block),
name = chest.customName?.string,
biome = lookup.lookupBiomeId(world, chest.pos),
height = chest.pos.y
),
independentProperties = IndependentProperties(
date = LocalDate.now()
)
),
redstoneComparatorProperties = RedstoneComparatorProperties(
comparatorOutput = ScreenHandler.calculateComparatorOutput(screenHandler?.inventory)
),
isLarge = type != ChestType.SINGLE
)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading