Compare commits

...

28 Commits
v0.2.0 ... main

Author SHA1 Message Date
Shadowfacts b64a05e0ad Fix P2P receiver constantly flooding network with request inventory packets 2023-03-13 11:24:55 -04:00
Shadowfacts 73de26387a Fix P2P receiver not invalidating target on netsplit 2023-03-13 11:21:53 -04:00
Shadowfacts 33614e0dc6 Tweak NetworkStackDispatcher behavior on incomplete insertions 2023-03-12 22:53:50 -04:00
Shadowfacts c18af9794b Store inventories as weak references in interface 2023-03-12 22:28:36 -04:00
Shadowfacts 6d97af8bdc Fix terminal not updating when all networked inventories are disconnected 2023-03-12 22:26:35 -04:00
Shadowfacts d527185888 Cache destination interfaces 2023-03-12 22:18:34 -04:00
Shadowfacts 82482ca9c6 Disable plugins 2023-03-12 22:15:32 -04:00
Shadowfacts 9200dea350 1.18.2 2022-06-16 10:45:32 -04:00
Shadowfacts e88ecd3215 Add P2P inventory system 2021-12-24 15:47:33 -05:00
Shadowfacts 9cbad193e2 fancy new java feature 2021-12-24 11:56:49 -05:00
Shadowfacts b416f98ef6 Fix not being able to place face devices by right-clicking non-full blocks 2021-12-23 14:41:55 -05:00
Shadowfacts b2e794e5a4 Add REI sync mode for terminal search field 2021-12-23 14:41:55 -05:00
Shadowfacts b21a45fbbb Fix twisted pair advancement not matching recipe 2021-12-23 12:53:22 -05:00
Shadowfacts ef9aa9e958 Fix terminal search field not unfocusing when REI focused 2021-12-23 11:36:46 -05:00
Shadowfacts c5ede3bd62 Add Cotton Resources tags 2021-12-22 22:35:28 -05:00
Shadowfacts 30300dbc40 Update REI plugin 2021-12-22 22:17:25 -05:00
Shadowfacts 5488cc295a Initial update to 1.18.1 2021-12-22 22:12:11 -05:00
Shadowfacts 172536cdb8 Fix magenta cable recipe 2021-11-08 18:19:44 -05:00
Shadowfacts 46e00cea97
Add Crafting Terminal loot table 2021-04-03 10:42:17 -04:00
Shadowfacts ce511e62e1
Fix dupe when shift-clicking crafting results out of terminal 2021-04-03 10:32:53 -04:00
Shadowfacts 5eb948802c
Fix crash when shift-clicking stack into terminal buffer but no slots available 2021-04-03 10:32:27 -04:00
Shadowfacts 7447c89394
TechReborn: Fix being client-only 2021-03-29 19:21:43 -04:00
Shadowfacts 87f0bdb85a
REI: Add support for filling recipes in the Crafting Terminal 2021-03-29 19:18:15 -04:00
Shadowfacts 236d6707f6
Don't show amount dialog if holding stack in cursor 2021-03-29 18:45:28 -04:00
Shadowfacts 961c74de34
Add Crafting Terminal recipe and advancement 2021-03-28 14:57:34 -04:00
Shadowfacts c278d137ef
Fix terminal model Z fighting 2021-03-28 14:57:34 -04:00
Shadowfacts 12e055d645
Add Crafting Terminal texture/model 2021-03-28 14:57:34 -04:00
Shadowfacts 9d98481ba5
Add Crafting Terminal 2021-03-28 14:57:32 -04:00
139 changed files with 2205 additions and 656 deletions

View File

@ -1,7 +1,7 @@
plugins {
id "fabric-loom" version "0.6.49"
id "fabric-loom" version "0.12.9"
id "maven-publish"
id "org.jetbrains.kotlin.jvm" version "1.4.30"
id "org.jetbrains.kotlin.jvm" version "1.6.10"
}
archivesBaseName = project.archives_base_name
@ -10,8 +10,8 @@ group = project.maven_group
allprojects {
pluginManager.withPlugin("java") {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}
@ -43,6 +43,8 @@ configure(allprojects.findAll { it.name != "kiwi-java" }) {
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
options.release = 17
}
java {
@ -55,43 +57,54 @@ configure(allprojects.findAll { it.name != "kiwi-java" }) {
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
compileKotlin {
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8
kotlinOptions.jvmTarget = JavaVersion.VERSION_17
}
}
}
minecraft {
loom {
log4jConfigs.from "PhyConDebugLogging.xml"
}
repositories {
maven { url "https://mod-buildcraft.com/maven" }
maven { url "http://server.bbkr.space:8081/artifactory/libs-release/" }
// maven { url "https://server.bbkr.space:8081/artifactory/libs-release/" }
maven { url "https://maven.terraformersmc.com/releases" }
jcenter()
maven { url "https://maven.shedaniel.me/" }
maven { url "https://maven.siphalor.de/" }
maven { url "https://jitpack.io" }
mavenCentral()
}
dependencies {
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.
modCompile "alexiil.mc.lib:libblockattributes-all:${project.libblockattributes_version}"
modImplementation "alexiil.mc.lib:libblockattributes-all:${project.libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-core:${project.libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-items:${project.libblockattributes_version}"
compile project(":kiwi-java")
implementation project(":kiwi-java")
include project(":kiwi-java")
runtimeOnly project(":plugin:mousewheelie")
include project(":plugin:mousewheelie")
runtimeOnly project(":plugin:rei")
include project(":plugin:rei")
runtimeOnly project(":plugin:techreborn")
include project(":plugin:techreborn")
// modRuntimeOnly "de.siphalor:mousewheelie-1.18:${project.mousewheelie_version}"
// runtimeOnly(project(":plugin:mousewheelie")) {
// transitive = false
// }
// include project(":plugin:mousewheelie")
//
// modRuntimeOnly "me.shedaniel:RoughlyEnoughItems-fabric:${project.rei_version}"
// runtimeOnly(project(":plugin:rei")) {
// transitive = false
// }
// include project(":plugin:rei")
modRuntime("io.github.cottonmc:cotton-resources:${project.cotton_resources_version}") {
exclude group: "net.fabricmc.fabric-api"
}
modRuntime("com.terraformersmc:modmenu:${project.modmenu_version}") {
// runtimeOnly project(":plugin:techreborn")
// include project(":plugin:techreborn")
// modRuntime("io.github.cottonmc:cotton-resources:${project.cotton_resources_version}") {
// exclude group: "net.fabricmc.fabric-api"
// }
modRuntimeOnly("com.terraformersmc:modmenu:${project.modmenu_version}") {
exclude group: "net.fabricmc.fabric-api"
}
@ -105,22 +118,22 @@ jar {
}
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(remapJar) {
builtBy remapJar
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
// publishing {
// publications {
// mavenJava(MavenPublication) {
// // add all the jars that should be included when publishing to maven
// artifact(remapJar) {
// builtBy remapJar
// }
// artifact(sourcesJar) {
// builtBy remapSourcesJar
// }
// }
// }
// select the repositories you want to publish to
repositories {
// uncomment to publish to the local maven
// mavenLocal()
}
}
// // select the repositories you want to publish to
// repositories {
// // uncomment to publish to the local maven
// // mavenLocal()
// }
// }

View File

@ -1,19 +1,21 @@
org.gradle.jvmargs=-Xmx1G
org.gradle.daemon=false
minecraft_version=1.16.5
yarn_mappings=1.16.5+build.4
loader_version=0.11.1
minecraft_version=1.18.2
yarn_mappings=1.18.2+build.3
loader_version=0.14.8
mod_version=0.2.0
maven_group=net.shadowfacts
archives_base_name=PhysicalConnectivity
fabric_version=0.30.0+1.16
fabric_kotlin_version=1.4.30+build.2
fabric_version=0.56.0+1.18.2
fabric_kotlin_version=1.8.0+kotlin.1.7.0
libblockattributes_version=0.8.5
cotton_resources_version=1.7.4
modmenu_version=1.16.8
libblockattributes_version=0.10.2
# cotton_resources_version=1.7.4
modmenu_version=3.2.2
rei_version=8.2.481
mousewheelie_version=1.9.0+mc1.18.2
junit_version = 5.4.0

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -3,7 +3,7 @@ plugins {
id "org.jetbrains.kotlin.jvm"
}
archivesBaseName = project.archives_base_name
archivesBaseName = "PhyCon-Plugin-MouseWheelie"
version = project.mod_version
group = project.maven_group
@ -11,13 +11,18 @@ repositories {
maven {
url = "https://maven.siphalor.de/"
}
jcenter()
maven {
url = "https://jitpack.io"
}
mavenCentral()
}
dependencies {
implementation project(":")
implementation(project(":")) {
transitive = false
}
modImplementation("de.siphalor:mousewheelie-1.16:${project.mousewheelie_version}") {
modImplementation("de.siphalor:mousewheelie-1.18:${project.mousewheelie_version}") {
exclude group: "net.fabricmc"
exclude group: "net.fabricmc.fabric-api"
exclude module: "modmenu"

View File

@ -1,4 +0,0 @@
archives_base_name=PhyCon-Plugin-MouseWheelie
mousewheelie_version=1.6.4+mc1.16.4

View File

@ -3,7 +3,7 @@ plugins {
id "org.jetbrains.kotlin.jvm"
}
archivesBaseName = project.archives_base_name
archivesBaseName = "PhyCon-Plugin-REI"
version = project.mod_version
group = project.maven_group
@ -11,16 +11,15 @@ repositories {
maven {
url = "https://maven.shedaniel.me/"
}
jcenter()
mavenCentral()
}
dependencies {
implementation project(":")
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api:${project.rei_version}") {
exclude group: "net.fabricmc.fabric-api"
implementation(project(":")) {
transitive = false
}
modRuntime("me.shedaniel:RoughlyEnoughItems:${project.rei_version}") {
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:${project.rei_version}") {
exclude group: "net.fabricmc.fabric-api"
}
}

View File

@ -1,3 +0,0 @@
archives_base_name=PhyCon-Plugin-REI
rei_version=5.10.184

View File

@ -1,44 +0,0 @@
package net.shadowfacts.phycon.plugin.rei
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.BaseBoundsHandler
import me.shedaniel.rei.api.DisplayHelper
import me.shedaniel.rei.api.REIHelper
import me.shedaniel.rei.api.plugins.REIPluginV0
import net.fabricmc.api.ClientModInitializer
import net.minecraft.client.MinecraftClient
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.block.terminal.AbstractTerminalScreen
/**
* @author shadowfacts
*/
object PhyConPlugin: ClientModInitializer, REIPluginV0 {
const val MODID = "phycon_rei"
override fun onInitializeClient() {
AbstractTerminalScreen.registerClickHandler { mouseX, mouseY, button ->
REIHelper.getInstance().searchTextField?.also {
if (it.bounds.contains(mouseX, mouseY)) {
this.terminalVC.searchField.resignFirstResponder()
} else {
this.terminalVC.searchField.becomeFirstResponder()
}
}
null
}
}
override fun getPluginIdentifier() = Identifier(MODID, "rei_plugin")
override fun registerBounds(helper: DisplayHelper) {
BaseBoundsHandler.getInstance().registerExclusionZones(AbstractTerminalScreen::class.java) {
val screen = MinecraftClient.getInstance().currentScreen as AbstractTerminalScreen<*, *>
val view = screen.terminalVC.settingsView
val rect = view.convert(view.bounds, to = null)
listOf(
Rectangle(rect.left.toInt(), rect.top.toInt(), 20, 20)
)
}
}
}

View File

@ -0,0 +1,87 @@
package net.shadowfacts.phycon.plugin.rei
import dev.architectury.event.EventResult
import dev.architectury.event.events.client.ClientScreenInputEvent
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.REIRuntime
import me.shedaniel.rei.api.client.plugins.REIClientPlugin
import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry
import net.fabricmc.api.ClientModInitializer
import net.minecraft.client.MinecraftClient
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.AbstractTerminalScreen
import org.apache.logging.log4j.LogManager
import java.lang.invoke.MethodHandle
import java.lang.invoke.MethodHandles
/**
* @author shadowfacts
*/
object PhyConPluginClient: ClientModInitializer, REIClientPlugin, AbstractTerminalScreen.SearchQueryListener {
private val logger = LogManager.getLogger()
private var isHighlightingHandle: MethodHandle? = null
override fun onInitializeClient() {
ClientScreenInputEvent.MOUSE_RELEASED_PRE.register { client, screen, mouseX, mouseY, button ->
if (screen is AbstractTerminalScreen<*, *>) {
REIRuntime.getInstance().searchTextField?.also {
if (it.isFocused) {
screen.terminalVC.searchField.resignFirstResponder()
} else {
screen.terminalVC.searchField.becomeFirstResponder()
}
}
}
EventResult.pass()
}
AbstractTerminalScreen.searchQueryListener = this
try {
val clazz = Class.forName("me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField")
isHighlightingHandle = MethodHandles.publicLookup().findStaticGetter(clazz, "isHighlighting", Boolean::class.java)
} catch (e: ReflectiveOperationException) {
logger.warn("Unable to find OverlaySearchField.isHighlighting, highlight sync will be disabled", e)
}
}
override fun registerScreens(registry: ScreenRegistry) {
registry.exclusionZones().register(AbstractTerminalScreen::class.java) {
val screen = MinecraftClient.getInstance().currentScreen as AbstractTerminalScreen<*, *>
val view = screen.terminalVC.settingsView
val rect = view.convert(view.bounds, to = null)
listOf(
Rectangle(rect.left.toInt(), rect.top.toInt(), view.bounds.width.toInt(), view.bounds.height.toInt())
)
}
}
override fun terminalSearchQueryChanged(newValue: String) {
if (shouldSync()) {
REIRuntime.getInstance().searchTextField?.text = newValue
}
}
override fun requestTerminalSearchFieldUpdate(): String? {
return if (shouldSync()) {
REIRuntime.getInstance().searchTextField?.text
} else {
null
}
}
private fun shouldSync(): Boolean {
return when (PhysicalConnectivityClient.terminalSettings[PhyConPluginCommon.REI_SYNC_KEY]) {
REISyncMode.OFF -> false
REISyncMode.ON -> true
REISyncMode.HIGHLIGHT_ONLY -> {
if (isHighlightingHandle != null) {
isHighlightingHandle!!.invoke() as Boolean
} else {
false
}
}
}
}
}

View File

@ -0,0 +1,68 @@
package net.shadowfacts.phycon.plugin.rei
import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.display.SimpleGridMenuDisplay
import me.shedaniel.rei.api.common.plugins.REIServerPlugin
import me.shedaniel.rei.api.common.transfer.info.MenuInfoContext
import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry
import me.shedaniel.rei.api.common.transfer.info.simple.SimpleGridMenuInfo
import me.shedaniel.rei.api.common.transfer.info.simple.SimpleMenuInfoProvider
import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessor
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.api.PhyConAPI
import net.shadowfacts.phycon.api.PhyConPlugin
import net.shadowfacts.phycon.api.TerminalSettingKey
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreenHandler
import java.util.stream.IntStream
/**
* @author shadowfacts
*/
object PhyConPluginCommon: REIServerPlugin, PhyConPlugin {
const val MODID = "phycon_rei"
lateinit var REI_SYNC_KEY: TerminalSettingKey<REISyncMode>
private set
override fun registerMenuInfo(registry: MenuInfoRegistry) {
registry.register(CategoryIdentifier.of("minecraft", "plugins/crafting"), CraftingTerminalScreenHandler::class.java, SimpleMenuInfoProvider.of(::TerminalInfo))
}
override fun initializePhyCon(api: PhyConAPI) {
REI_SYNC_KEY = api.registerTerminalSetting(Identifier(MODID, "rei_sync"), REISyncMode.OFF)
}
class TerminalInfo<D: SimpleGridMenuDisplay>(
private val display: D,
): SimpleGridMenuInfo<CraftingTerminalScreenHandler, D> {
override fun getCraftingResultSlotIndex(menu: CraftingTerminalScreenHandler): Int {
return menu.resultSlot.id
}
override fun getInputStackSlotIds(context: MenuInfoContext<CraftingTerminalScreenHandler, *, D>): IntStream {
return IntStream.range(context.menu.craftingSlotsStart, context.menu.craftingSlotsEnd)
}
override fun getInventorySlots(context: MenuInfoContext<CraftingTerminalScreenHandler, *, D>): Iterable<SlotAccessor> {
val slots = super.getInventorySlots(context).toMutableList()
for (i in (context.menu.bufferSlotsStart until context.menu.bufferSlotsEnd)) {
slots.add(SlotAccessor.fromSlot(context.menu.getSlot(i)))
}
return slots
}
override fun getCraftingWidth(menu: CraftingTerminalScreenHandler): Int {
return 3
}
override fun getCraftingHeight(menu: CraftingTerminalScreenHandler): Int {
return 3
}
override fun getDisplay(): D {
return display
}
}
}

View File

@ -0,0 +1,29 @@
package net.shadowfacts.phycon.plugin.rei
import net.minecraft.text.LiteralText
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.TerminalSetting
/**
* @author shadowfacts
*/
enum class REISyncMode: TerminalSetting {
OFF,
ON,
HIGHLIGHT_ONLY;
override fun getIconTexture() = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
override fun getUV() = when (this) {
OFF -> intArrayOf(0, 240)
ON -> intArrayOf(16, 240)
HIGHLIGHT_ONLY -> intArrayOf(32, 240)
}
override fun getTooltip() = when (this) {
OFF -> LiteralText("Don't sync with REI")
ON -> LiteralText("Sync with REI")
HIGHLIGHT_ONLY -> LiteralText("Sync in highlight mode")
}
}

View File

@ -12,18 +12,27 @@
"homepage": "https://git.shadowfacts.net/minecraft/PhysicalConnectivity"
},
"license": "LGPL-3.0",
"environment": "client",
"entrypoints": {
"client": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPlugin"
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginClient"
}
],
"rei_plugins": [
"rei": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPlugin"
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginClient"
},
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginCommon"
}
],
"phycon": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginCommon"
}
]
},
@ -34,7 +43,7 @@
"fabric": "*",
"fabric-language-kotlin": ">=1.3.50",
"phycon": "*",
"roughlyenoughitems": "*"
"roughlyenoughitems": ["^7.0.0", "^8.0.0"]
},
"custom": {

View File

@ -11,11 +11,13 @@ repositories {
maven {
url = "https://maven.modmuss50.me/"
}
jcenter()
mavenCentral()
}
dependencies {
implementation project(":")
implementation(project(":")) {
transitive = false
}
modImplementation("TechReborn:TechReborn-1.16:${project.techreborn_version}") {
exclude group: "net.fabricmc.fabric-api"

View File

@ -12,7 +12,6 @@
"homepage": "https://git.shadowfacts.net/minecraft/PhysicalConnectivity"
},
"license": "LGPL-3.0",
"environment": "client",
"entrypoints": {
"main": [
{

View File

@ -1,6 +1,6 @@
pluginManagement {
repositories {
jcenter()
mavenCentral()
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
@ -12,4 +12,4 @@ pluginManagement {
include("kiwi-java")
include("plugin:mousewheelie")
include("plugin:rei")
include("plugin:techreborn")
// include("plugin:techreborn")

View File

@ -16,4 +16,6 @@ public interface Interface {
void send(@NotNull EthernetFrame frame);
default void cableDisconnected() {}
}

View File

@ -1,10 +1,12 @@
package net.shadowfacts.phycon.api;
import org.jetbrains.annotations.NotNull;
/**
* @author shadowfacts
*/
public interface PhyConPlugin {
void initializePhyCon(PhyConAPI api);
void initializePhyCon(@NotNull PhyConAPI api);
}

View File

@ -11,4 +11,6 @@ public interface TerminalSettingKey<E extends Enum<E> & TerminalSetting> {
E getValue();
void setPriority(int priority);
}

View File

@ -26,8 +26,7 @@ public class MixinHandledScreen {
at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;enableDepthTest()V")
)
private void drawSlotUnderlay(MatrixStack matrixStack, Slot slot, CallbackInfo ci) {
if ((Object)this instanceof AbstractTerminalScreen) {
AbstractTerminalScreen<?, ?> self = (AbstractTerminalScreen<?, ?>)(Object)this;
if ((Object)this instanceof AbstractTerminalScreen<?, ?> self) {
self.drawSlotUnderlay(matrixStack, slot);
}
}
@ -37,11 +36,10 @@ public class MixinHandledScreen {
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderer;renderGuiItemOverlay(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V")
)
private void drawSlotAmount(ItemRenderer itemRenderer, TextRenderer textRenderer, ItemStack stack, int x, int y, @Nullable String countLabel, MatrixStack matrixStack, Slot slot) {
if ((Object)this instanceof AbstractTerminalScreen) {
AbstractTerminalScreen<?, ?> self = (AbstractTerminalScreen<?, ?>)(Object)this;
if ((Object)this instanceof AbstractTerminalScreen<?, ?> self) {
AbstractTerminalScreenHandler<?> handler = self.getScreenHandler();
if (slot.id < handler.getNetworkSlotsEnd() && stack.getCount() > 1) {
self.drawNetworkSlotAmount(stack, x, y, slot, matrixStack);
self.drawNetworkSlotAmount(stack, x, y);
return;
}
}

View File

@ -0,0 +1,28 @@
package net.shadowfacts.phycon.mixin.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.shadowfacts.cacao.AbstractCacaoScreen;
import org.objectweb.asm.Opcodes;
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;
/**
* @author shadowfacts
*/
@Mixin(MinecraftClient.class)
public class MixinMinecraftClient {
@Inject(
method = "setScreen(Lnet/minecraft/client/gui/screen/Screen;)V",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER)
)
private void setScreen(Screen screen, CallbackInfo ci) {
if (screen instanceof AbstractCacaoScreen cacaoScreen) {
cacaoScreen.screenWillAppear();
}
}
}

View File

@ -14,4 +14,6 @@ interface AbstractCacaoScreen {
fun removeWindow(window: Window)
}
fun screenWillAppear()
}

View File

@ -1,6 +1,6 @@
package net.shadowfacts.cacao
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory
@ -14,6 +14,7 @@ import net.shadowfacts.cacao.util.RenderHelper
import net.shadowfacts.cacao.window.ScreenHandlerWindow
import net.shadowfacts.cacao.window.Window
import org.lwjgl.glfw.GLFW
import org.lwjgl.opengl.GL11
import java.util.*
/**
@ -29,10 +30,16 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
override val windows: List<Window> = _windows
private var hasAppeared = false
override fun <T: Window> addWindow(window: T, index: Int): T {
if (window is ScreenHandlerWindow && window.screenHandler != handler) {
throw RuntimeException("Adding ScreenHandlerWindow to CacaoHandledScreen with different screen handler is not supported")
}
if (hasAppeared) {
window.viewController.viewWillAppear()
}
_windows.add(index, window)
@ -50,7 +57,13 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
override fun removeWindow(window: Window) {
_windows.remove(window)
if (windows.isEmpty()) {
onClose()
close()
}
}
override fun screenWillAppear() {
windows.forEach {
it.viewController.viewWillAppear()
}
}
@ -62,11 +75,12 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
}
}
override fun onClose() {
super.onClose()
override fun close() {
super.close()
windows.forEach {
// todo: VC callbacks
it.viewController.viewWillDisappear()
it.viewController.viewDidDisappear()
it.firstResponder = null
}
@ -82,8 +96,8 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
val mouse = Point(mouseX, mouseY)
RenderSystem.pushMatrix()
RenderSystem.translatef(0f, 0f, -350f)
matrixStack.push()
matrixStack.translate(0.0, 0.0, -350.0)
for (i in windows.indices) {
val it = windows[i]
@ -100,7 +114,7 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
super.render(matrixStack, -1, -1, delta)
}
RenderSystem.popMatrix()
matrixStack.pop()
}
it.draw(matrixStack, mouse, delta)

View File

@ -1,5 +1,6 @@
package net.shadowfacts.cacao
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.sound.SoundEvents
@ -32,6 +33,8 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
*/
override val windows: List<Window> = _windows
private var hasAppeared = false
/**
* Adds the given window to this screen's window list at the given position.
*
@ -40,6 +43,10 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
* @return The window that was added, as a convenience.
*/
override fun <T: Window> addWindow(window: T, index: Int): T {
if (hasAppeared) {
window.viewController.viewWillAppear()
}
_windows.add(index, window)
window.screen = this
@ -62,7 +69,13 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
override fun removeWindow(window: Window) {
_windows.remove(window)
if (windows.isEmpty()) {
onClose()
close()
}
}
override fun screenWillAppear() {
windows.forEach {
it.viewController.viewWillAppear()
}
}
@ -74,11 +87,12 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
}
}
override fun onClose() {
super.onClose()
override fun close() {
super.close()
windows.forEach {
// todo: VC callbacks
it.viewController.viewWillDisappear()
it.viewController.viewDidDisappear()
// resign the current first responder (if any)
it.firstResponder = null

View File

@ -1,20 +1,21 @@
package net.shadowfacts.cacao.util
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawableHelper
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.render.*
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.sound.SoundEvent
import net.minecraft.text.LiteralText
import net.minecraft.text.OrderedText
import net.minecraft.text.Text
import net.minecraft.util.math.Matrix4f
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.geometry.Rect
import net.shadowfacts.cacao.util.texture.Texture
import org.lwjgl.opengl.GL11
import kotlin.math.roundToInt
/**
* Helper methods for rendering using Minecraft's utilities from Cacao views.
@ -45,18 +46,18 @@ object RenderHelper: DrawableHelper() {
*/
fun draw(matrixStack: MatrixStack, rect: Rect, texture: Texture) {
if (disabled) return
color(1f, 1f, 1f, 1f)
MinecraftClient.getInstance().textureManager.bindTexture(texture.location)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
RenderSystem.setShaderTexture(0, texture.location)
draw(matrixStack, rect.left, rect.top, texture.u, texture.v, rect.width, rect.height, texture.width, texture.height)
}
fun drawLine(start: Point, end: Point, z: Double, width: Float, color: Color) {
if (disabled) return
GlStateManager.lineWidth(width)
RenderSystem.lineWidth(width)
val tessellator = Tessellator.getInstance()
val buffer = tessellator.buffer
buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR)
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.POSITION_COLOR)
buffer.vertex(start.x, start.y, z).color(color).next()
buffer.vertex(end.x, end.y, z).color(color).next()
tessellator.draw()
@ -71,19 +72,19 @@ object RenderHelper: DrawableHelper() {
val uEnd = (u + width).toFloat() / textureWidth
val vStart = v.toFloat() / textureHeight
val vEnd = (v + height).toFloat() / textureHeight
drawTexturedQuad(matrixStack.peek().model, x, x + width, y, y + height, 0.0, uStart, uEnd, vStart, vEnd)
drawTexturedQuad(matrixStack.peek().positionMatrix, x, x + width, y, y + height, 0.0, uStart, uEnd, vStart, vEnd)
}
// Copied from net.minecraft.client.gui.DrawableHelper
// TODO: use an access transformer to just call minecraft's impl
private fun drawTexturedQuad(matrix: Matrix4f, x0: Double, x1: Double, y0: Double, y1: Double, z: Double, u0: Float, u1: Float, v0: Float, v1: Float) {
val bufferBuilder = Tessellator.getInstance().buffer
bufferBuilder.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE)
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE)
bufferBuilder.vertex(matrix, x0.toFloat(), y1.toFloat(), z.toFloat()).texture(u0, v1).next()
bufferBuilder.vertex(matrix, x1.toFloat(), y1.toFloat(), z.toFloat()).texture(u1, v1).next()
bufferBuilder.vertex(matrix, x1.toFloat(), y0.toFloat(), z.toFloat()).texture(u1, v0).next()
bufferBuilder.vertex(matrix, x0.toFloat(), y0.toFloat(), z.toFloat()).texture(u0, v0).next()
bufferBuilder.end()
RenderSystem.enableAlphaTest()
BufferRenderer.draw(bufferBuilder)
}
@ -95,110 +96,22 @@ object RenderHelper: DrawableHelper() {
drawTooltip(matrixStack, texts.map(Text::asOrderedText), mouse)
}
// Based on Screen.renderOrderedTooltip
private val dummyScreen = object: Screen(LiteralText("")) {
init {
textRenderer = MinecraftClient.getInstance().textRenderer
itemRenderer = MinecraftClient.getInstance().itemRenderer
}
}
@JvmName("drawOrderedTooltip")
fun drawTooltip(matrixStack: MatrixStack, texts: List<OrderedText>, mouse: Point) {
if (disabled) return
if (texts.isEmpty()) return
val client = MinecraftClient.getInstance()
val textRenderer = client.textRenderer
val maxWidth = texts.maxOf(textRenderer::getWidth)
var x = mouse.x.toInt() + 12
var y = mouse.y.toInt() - 12
var p = 8
if (texts.size > 1) {
p += 2 + (texts.size - 1) * 8
}
if (x + maxWidth > client.window.scaledWidth) {
x -= 28 + maxWidth
}
if (y + p + 6 > client.window.scaledHeight) {
y = client.window.scaledHeight - p - 6
}
matrixStack.push()
val q = -267386864
val r = 1347420415
val s = 1344798847
val t = 1
val tessellator = Tessellator.getInstance()
val buffer = tessellator.buffer
buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR)
val matrix = matrixStack.peek().model
val z = 400
fillGradient(matrix, buffer, x - 3, y - 4, x + maxWidth + 3, y - 3, z, q, q)
fillGradient(matrix, buffer, x - 3, y + p + 3, x + maxWidth + 3, y + p + 4, z, q, q)
fillGradient(matrix, buffer, x - 3, y - 3, x + maxWidth + 3, y + p + 3, z, q, q)
fillGradient(matrix, buffer, x - 4, y - 3, x - 3, y + p + 3, z, q, q)
fillGradient(matrix, buffer, x + maxWidth + 3, y - 3, x + maxWidth + 4, y + p + 3, z, q, q)
fillGradient(matrix, buffer, x - 3, y - 3 + 1, x - 3 + 1, y + p + 3 - 1, z, r, s)
fillGradient(matrix, buffer, x + maxWidth + 2, y - 3 + 1, x + maxWidth + 3, y + p + 3 - 1, z, r, s)
fillGradient(matrix, buffer, x - 3, y - 3, x + maxWidth + 3, y - 3 + 1, z, r, r)
fillGradient(matrix, buffer, x - 3, y + p + 2, x + maxWidth + 3, y + p + 3, z, s, s)
RenderSystem.enableDepthTest()
RenderSystem.disableTexture()
RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc()
RenderSystem.shadeModel(7425)
buffer.end()
BufferRenderer.draw(buffer)
RenderSystem.shadeModel(7424)
RenderSystem.disableBlend()
RenderSystem.enableTexture()
val immediate = VertexConsumerProvider.immediate(buffer)
matrixStack.translate(0.0, 0.0, 400.0)
for (i in texts.indices) {
val text = texts[i]
textRenderer.draw(text, x.toFloat(), y.toFloat(), -1, true, matrix, immediate, false, 0, 15728880)
if (i == 0) {
y += 2
}
y += 10
}
immediate.draw()
matrixStack.pop()
}
/**
* @see org.lwjgl.opengl.GL11.glPushMatrix
*/
fun pushMatrix() {
if (disabled) return
RenderSystem.pushMatrix()
}
/**
* @see org.lwjgl.opengl.GL11.glPopMatrix
*/
fun popMatrix() {
if (disabled) return
RenderSystem.popMatrix()
}
/**
* @see org.lwjgl.opengl.GL11.glTranslated
*/
fun translate(x: Double, y: Double, z: Double = 0.0) {
if (disabled) return
RenderSystem.translated(x, y, z)
}
/**
* @see org.lwjgl.opengl.GL11.glScaled
*/
fun scale(x: Double, y: Double, z: Double = 1.0) {
if (disabled) return
RenderSystem.scaled(x, y, z)
dummyScreen.width = client.window.scaledWidth
dummyScreen.height = client.window.scaledHeight
dummyScreen.renderOrderedTooltip(matrixStack, texts, mouse.x.roundToInt(), mouse.y.roundToInt())
}
/**
@ -206,7 +119,7 @@ object RenderHelper: DrawableHelper() {
*/
fun color(r: Float, g: Float, b: Float, alpha: Float) {
if (disabled) return
RenderSystem.color4f(r, g, b, alpha)
RenderSystem.setShaderColor(r, g, b, alpha)
}
private fun VertexConsumer.color(color: Color): VertexConsumer {

View File

@ -26,11 +26,13 @@ class BezierCurveView(val curve: BezierCurve): View() {
var lineColor = Color.BLACK
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
RenderHelper.scale(bounds.width, bounds.height)
matrixStack.push()
matrixStack.scale(bounds.width.toFloat(), bounds.height.toFloat(), 1f)
for ((index, point) in points.withIndex()) {
val next = points.getOrNull(index + 1) ?: break
RenderHelper.drawLine(point, next, zIndex, lineWidth, lineColor)
}
matrixStack.pop()
}
}
}

View File

@ -29,7 +29,7 @@ class DialogView(
CANCEL, CONFIRM, OK, CLOSE;
override val localizedName: Text
get() = LiteralText(name.toLowerCase().capitalize()) // todo: actually localize me
get() = LiteralText(name.lowercase().replaceFirstChar(Char::titlecase)) // todo: actually localize me
}
private lateinit var background: NinePatchView

View File

@ -12,7 +12,6 @@ import no.birkett.kiwi.Constraint
import no.birkett.kiwi.Solver
import java.lang.RuntimeException
import java.util.*
import kotlin.collections.HashSet
import kotlin.math.floor
/**
@ -368,8 +367,8 @@ open class View(): Responder {
* @param delta The time since the last frame.
*/
open fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
RenderHelper.pushMatrix()
RenderHelper.translate(floor(frame.left), floor(frame.top))
matrixStack.push()
matrixStack.translate(frame.left, frame.top, 0.0)
RenderHelper.fill(matrixStack, bounds, backgroundColor)
@ -380,7 +379,7 @@ open class View(): Responder {
it.draw(matrixStack, mouseInView, delta)
}
RenderHelper.popMatrix()
matrixStack.pop()
}
/**

View File

@ -109,8 +109,8 @@ abstract class AbstractButton<Impl: AbstractButton<Impl>>(val content: View, val
}
override fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
RenderHelper.pushMatrix()
RenderHelper.translate(floor(frame.left), floor(frame.top))
matrixStack.push()
matrixStack.translate(frame.left, frame.top, 0.0)
RenderHelper.fill(matrixStack, bounds, backgroundColor)
@ -123,7 +123,7 @@ abstract class AbstractButton<Impl: AbstractButton<Impl>>(val content: View, val
// don't draw subviews, otherwise all background views + content will get drawn
RenderHelper.popMatrix()
matrixStack.pop()
if (tooltip != null && mouse in bounds) {
window!!.drawTooltip(listOf(tooltip!!))

View File

@ -1,15 +1,12 @@
package net.shadowfacts.cacao.view.textfield
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.TickableElement
import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.LiteralText
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.util.KeyModifiers
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.util.RenderHelper
import net.shadowfacts.cacao.view.View
import net.shadowfacts.phycon.mixin.client.TextFieldWidgetAccessor
import org.lwjgl.glfw.GLFW
@ -25,7 +22,7 @@ import org.lwjgl.glfw.GLFW
*/
abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
initialText: String
): View(), TickableElement {
): View() {
/**
* A function that is invoked when the text in this text field changes.
@ -70,7 +67,7 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
var drawBackground = true
set(value) {
field = value
minecraftWidget.setHasBorder(value)
minecraftWidget.setDrawsBackground(value)
}
private lateinit var originInWindow: Point
@ -79,7 +76,7 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
init {
minecraftWidget.text = initialText
minecraftWidget.setTextPredicate { this.validate(it) }
minecraftWidget.setHasBorder(drawBackground)
minecraftWidget.setDrawsBackground(drawBackground)
}
/**
@ -103,14 +100,14 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
}
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
RenderHelper.pushMatrix()
RenderHelper.translate(-originInWindow.x, -originInWindow.y)
matrixStack.push()
matrixStack.translate(-originInWindow.x, -originInWindow.y, 0.0)
val mouseXInWindow = (mouse.x + originInWindow.x).toInt()
val mouseYInWindow = (mouse.y + originInWindow.y).toInt()
minecraftWidget.render(matrixStack, mouseXInWindow, mouseYInWindow, delta)
RenderHelper.popMatrix()
matrixStack.pop()
}
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
@ -135,12 +132,12 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
override fun didBecomeFirstResponder() {
super.didBecomeFirstResponder()
minecraftWidget.setSelected(true)
minecraftWidget.setTextFieldFocused(true)
}
override fun didResignFirstResponder() {
super.didResignFirstResponder()
minecraftWidget.setSelected(false)
minecraftWidget.setTextFieldFocused(false)
}
override fun charTyped(char: Char, modifiers: KeyModifiers): Boolean {
@ -164,7 +161,7 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
return result || (isFirstResponder && keyCode != GLFW.GLFW_KEY_ESCAPE)
}
override fun tick() {
fun tick() {
minecraftWidget.tick()
}