Compare commits
28 Commits
Author | SHA1 | Date |
---|---|---|
Shadowfacts | b64a05e0ad | |
Shadowfacts | 73de26387a | |
Shadowfacts | 33614e0dc6 | |
Shadowfacts | c18af9794b | |
Shadowfacts | 6d97af8bdc | |
Shadowfacts | d527185888 | |
Shadowfacts | 82482ca9c6 | |
Shadowfacts | 9200dea350 | |
Shadowfacts | e88ecd3215 | |
Shadowfacts | 9cbad193e2 | |
Shadowfacts | b416f98ef6 | |
Shadowfacts | b2e794e5a4 | |
Shadowfacts | b21a45fbbb | |
Shadowfacts | ef9aa9e958 | |
Shadowfacts | c5ede3bd62 | |
Shadowfacts | 30300dbc40 | |
Shadowfacts | 5488cc295a | |
Shadowfacts | 172536cdb8 | |
Shadowfacts | 46e00cea97 | |
Shadowfacts | ce511e62e1 | |
Shadowfacts | 5eb948802c | |
Shadowfacts | 7447c89394 | |
Shadowfacts | 87f0bdb85a | |
Shadowfacts | 236d6707f6 | |
Shadowfacts | 961c74de34 | |
Shadowfacts | c278d137ef | |
Shadowfacts | 12e055d645 | |
Shadowfacts | 9d98481ba5 |
89
build.gradle
89
build.gradle
|
@ -1,7 +1,7 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "fabric-loom" version "0.6.49"
|
id "fabric-loom" version "0.12.9"
|
||||||
id "maven-publish"
|
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
|
archivesBaseName = project.archives_base_name
|
||||||
|
@ -10,8 +10,8 @@ group = project.maven_group
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
pluginManager.withPlugin("java") {
|
pluginManager.withPlugin("java") {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
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
|
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
|
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
|
||||||
|
options.release = 17
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
@ -55,43 +57,54 @@ configure(allprojects.findAll { it.name != "kiwi-java" }) {
|
||||||
|
|
||||||
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
|
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
|
||||||
compileKotlin {
|
compileKotlin {
|
||||||
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8
|
kotlinOptions.jvmTarget = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
minecraft {
|
loom {
|
||||||
log4jConfigs.from "PhyConDebugLogging.xml"
|
log4jConfigs.from "PhyConDebugLogging.xml"
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven { url "https://mod-buildcraft.com/maven" }
|
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" }
|
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 {
|
dependencies {
|
||||||
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||||
// You may need to force-disable transitiveness on them.
|
// 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-core:${project.libblockattributes_version}"
|
||||||
include "alexiil.mc.lib:libblockattributes-items:${project.libblockattributes_version}"
|
include "alexiil.mc.lib:libblockattributes-items:${project.libblockattributes_version}"
|
||||||
|
|
||||||
compile project(":kiwi-java")
|
implementation project(":kiwi-java")
|
||||||
include project(":kiwi-java")
|
include project(":kiwi-java")
|
||||||
|
|
||||||
runtimeOnly project(":plugin:mousewheelie")
|
// modRuntimeOnly "de.siphalor:mousewheelie-1.18:${project.mousewheelie_version}"
|
||||||
include project(":plugin:mousewheelie")
|
// runtimeOnly(project(":plugin:mousewheelie")) {
|
||||||
runtimeOnly project(":plugin:rei")
|
// transitive = false
|
||||||
include project(":plugin:rei")
|
// }
|
||||||
runtimeOnly project(":plugin:techreborn")
|
// include project(":plugin:mousewheelie")
|
||||||
include project(":plugin:techreborn")
|
//
|
||||||
|
// 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}") {
|
// runtimeOnly project(":plugin:techreborn")
|
||||||
exclude group: "net.fabricmc.fabric-api"
|
// include project(":plugin:techreborn")
|
||||||
}
|
|
||||||
modRuntime("com.terraformersmc:modmenu:${project.modmenu_version}") {
|
// 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"
|
exclude group: "net.fabricmc.fabric-api"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,22 +118,22 @@ jar {
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure the maven publication
|
// configure the maven publication
|
||||||
publishing {
|
// publishing {
|
||||||
publications {
|
// publications {
|
||||||
mavenJava(MavenPublication) {
|
// mavenJava(MavenPublication) {
|
||||||
// add all the jars that should be included when publishing to maven
|
// // add all the jars that should be included when publishing to maven
|
||||||
artifact(remapJar) {
|
// artifact(remapJar) {
|
||||||
builtBy remapJar
|
// builtBy remapJar
|
||||||
}
|
// }
|
||||||
artifact(sourcesJar) {
|
// artifact(sourcesJar) {
|
||||||
builtBy remapSourcesJar
|
// builtBy remapSourcesJar
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// select the repositories you want to publish to
|
// // select the repositories you want to publish to
|
||||||
repositories {
|
// repositories {
|
||||||
// uncomment to publish to the local maven
|
// // uncomment to publish to the local maven
|
||||||
// mavenLocal()
|
// // mavenLocal()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
org.gradle.jvmargs=-Xmx1G
|
org.gradle.jvmargs=-Xmx1G
|
||||||
org.gradle.daemon=false
|
org.gradle.daemon=false
|
||||||
|
|
||||||
minecraft_version=1.16.5
|
minecraft_version=1.18.2
|
||||||
yarn_mappings=1.16.5+build.4
|
yarn_mappings=1.18.2+build.3
|
||||||
loader_version=0.11.1
|
loader_version=0.14.8
|
||||||
|
|
||||||
mod_version=0.2.0
|
mod_version=0.2.0
|
||||||
maven_group=net.shadowfacts
|
maven_group=net.shadowfacts
|
||||||
archives_base_name=PhysicalConnectivity
|
archives_base_name=PhysicalConnectivity
|
||||||
|
|
||||||
fabric_version=0.30.0+1.16
|
fabric_version=0.56.0+1.18.2
|
||||||
fabric_kotlin_version=1.4.30+build.2
|
fabric_kotlin_version=1.8.0+kotlin.1.7.0
|
||||||
|
|
||||||
libblockattributes_version=0.8.5
|
libblockattributes_version=0.10.2
|
||||||
cotton_resources_version=1.7.4
|
# cotton_resources_version=1.7.4
|
||||||
modmenu_version=1.16.8
|
modmenu_version=3.2.2
|
||||||
|
rei_version=8.2.481
|
||||||
|
mousewheelie_version=1.9.0+mc1.18.2
|
||||||
|
|
||||||
junit_version = 5.4.0
|
junit_version = 5.4.0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
id "org.jetbrains.kotlin.jvm"
|
id "org.jetbrains.kotlin.jvm"
|
||||||
}
|
}
|
||||||
|
|
||||||
archivesBaseName = project.archives_base_name
|
archivesBaseName = "PhyCon-Plugin-MouseWheelie"
|
||||||
version = project.mod_version
|
version = project.mod_version
|
||||||
group = project.maven_group
|
group = project.maven_group
|
||||||
|
|
||||||
|
@ -11,13 +11,18 @@ repositories {
|
||||||
maven {
|
maven {
|
||||||
url = "https://maven.siphalor.de/"
|
url = "https://maven.siphalor.de/"
|
||||||
}
|
}
|
||||||
jcenter()
|
maven {
|
||||||
|
url = "https://jitpack.io"
|
||||||
|
}
|
||||||
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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"
|
||||||
exclude group: "net.fabricmc.fabric-api"
|
exclude group: "net.fabricmc.fabric-api"
|
||||||
exclude module: "modmenu"
|
exclude module: "modmenu"
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
archives_base_name=PhyCon-Plugin-MouseWheelie
|
|
||||||
|
|
||||||
mousewheelie_version=1.6.4+mc1.16.4
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
id "org.jetbrains.kotlin.jvm"
|
id "org.jetbrains.kotlin.jvm"
|
||||||
}
|
}
|
||||||
|
|
||||||
archivesBaseName = project.archives_base_name
|
archivesBaseName = "PhyCon-Plugin-REI"
|
||||||
version = project.mod_version
|
version = project.mod_version
|
||||||
group = project.maven_group
|
group = project.maven_group
|
||||||
|
|
||||||
|
@ -11,16 +11,15 @@ repositories {
|
||||||
maven {
|
maven {
|
||||||
url = "https://maven.shedaniel.me/"
|
url = "https://maven.shedaniel.me/"
|
||||||
}
|
}
|
||||||
jcenter()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":")
|
implementation(project(":")) {
|
||||||
|
transitive = false
|
||||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api:${project.rei_version}") {
|
|
||||||
exclude group: "net.fabricmc.fabric-api"
|
|
||||||
}
|
}
|
||||||
modRuntime("me.shedaniel:RoughlyEnoughItems:${project.rei_version}") {
|
|
||||||
|
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:${project.rei_version}") {
|
||||||
exclude group: "net.fabricmc.fabric-api"
|
exclude group: "net.fabricmc.fabric-api"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
archives_base_name=PhyCon-Plugin-REI
|
|
||||||
|
|
||||||
rei_version=5.10.184
|
|
|
@ -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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,18 +12,27 @@
|
||||||
"homepage": "https://git.shadowfacts.net/minecraft/PhysicalConnectivity"
|
"homepage": "https://git.shadowfacts.net/minecraft/PhysicalConnectivity"
|
||||||
},
|
},
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"environment": "client",
|
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"client": [
|
"client": [
|
||||||
{
|
{
|
||||||
"adapter": "kotlin",
|
"adapter": "kotlin",
|
||||||
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPlugin"
|
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginClient"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rei_plugins": [
|
"rei": [
|
||||||
{
|
{
|
||||||
"adapter": "kotlin",
|
"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": "*",
|
||||||
"fabric-language-kotlin": ">=1.3.50",
|
"fabric-language-kotlin": ">=1.3.50",
|
||||||
"phycon": "*",
|
"phycon": "*",
|
||||||
"roughlyenoughitems": "*"
|
"roughlyenoughitems": ["^7.0.0", "^8.0.0"]
|
||||||
},
|
},
|
||||||
|
|
||||||
"custom": {
|
"custom": {
|
||||||
|
|
|
@ -11,11 +11,13 @@ repositories {
|
||||||
maven {
|
maven {
|
||||||
url = "https://maven.modmuss50.me/"
|
url = "https://maven.modmuss50.me/"
|
||||||
}
|
}
|
||||||
jcenter()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":")
|
implementation(project(":")) {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
|
||||||
modImplementation("TechReborn:TechReborn-1.16:${project.techreborn_version}") {
|
modImplementation("TechReborn:TechReborn-1.16:${project.techreborn_version}") {
|
||||||
exclude group: "net.fabricmc.fabric-api"
|
exclude group: "net.fabricmc.fabric-api"
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
"homepage": "https://git.shadowfacts.net/minecraft/PhysicalConnectivity"
|
"homepage": "https://git.shadowfacts.net/minecraft/PhysicalConnectivity"
|
||||||
},
|
},
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"environment": "client",
|
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"main": [
|
"main": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
mavenCentral()
|
||||||
maven {
|
maven {
|
||||||
name = 'Fabric'
|
name = 'Fabric'
|
||||||
url = 'https://maven.fabricmc.net/'
|
url = 'https://maven.fabricmc.net/'
|
||||||
|
@ -12,4 +12,4 @@ pluginManagement {
|
||||||
include("kiwi-java")
|
include("kiwi-java")
|
||||||
include("plugin:mousewheelie")
|
include("plugin:mousewheelie")
|
||||||
include("plugin:rei")
|
include("plugin:rei")
|
||||||
include("plugin:techreborn")
|
// include("plugin:techreborn")
|
||||||
|
|
|
@ -16,4 +16,6 @@ public interface Interface {
|
||||||
|
|
||||||
void send(@NotNull EthernetFrame frame);
|
void send(@NotNull EthernetFrame frame);
|
||||||
|
|
||||||
|
default void cableDisconnected() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package net.shadowfacts.phycon.api;
|
package net.shadowfacts.phycon.api;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
public interface PhyConPlugin {
|
public interface PhyConPlugin {
|
||||||
|
|
||||||
void initializePhyCon(PhyConAPI api);
|
void initializePhyCon(@NotNull PhyConAPI api);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,4 +11,6 @@ public interface TerminalSettingKey<E extends Enum<E> & TerminalSetting> {
|
||||||
|
|
||||||
E getValue();
|
E getValue();
|
||||||
|
|
||||||
|
void setPriority(int priority);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,7 @@ public class MixinHandledScreen {
|
||||||
at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;enableDepthTest()V")
|
at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;enableDepthTest()V")
|
||||||
)
|
)
|
||||||
private void drawSlotUnderlay(MatrixStack matrixStack, Slot slot, CallbackInfo ci) {
|
private void drawSlotUnderlay(MatrixStack matrixStack, Slot slot, CallbackInfo ci) {
|
||||||
if ((Object)this instanceof AbstractTerminalScreen) {
|
if ((Object)this instanceof AbstractTerminalScreen<?, ?> self) {
|
||||||
AbstractTerminalScreen<?, ?> self = (AbstractTerminalScreen<?, ?>)(Object)this;
|
|
||||||
self.drawSlotUnderlay(matrixStack, slot);
|
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")
|
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) {
|
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) {
|
if ((Object)this instanceof AbstractTerminalScreen<?, ?> self) {
|
||||||
AbstractTerminalScreen<?, ?> self = (AbstractTerminalScreen<?, ?>)(Object)this;
|
|
||||||
AbstractTerminalScreenHandler<?> handler = self.getScreenHandler();
|
AbstractTerminalScreenHandler<?> handler = self.getScreenHandler();
|
||||||
if (slot.id < handler.getNetworkSlotsEnd() && stack.getCount() > 1) {
|
if (slot.id < handler.getNetworkSlotsEnd() && stack.getCount() > 1) {
|
||||||
self.drawNetworkSlotAmount(stack, x, y, slot, matrixStack);
|
self.drawNetworkSlotAmount(stack, x, y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,4 +14,6 @@ interface AbstractCacaoScreen {
|
||||||
|
|
||||||
fun removeWindow(window: Window)
|
fun removeWindow(window: Window)
|
||||||
|
|
||||||
|
fun screenWillAppear()
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package net.shadowfacts.cacao
|
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.gui.screen.ingame.HandledScreen
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
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.ScreenHandlerWindow
|
||||||
import net.shadowfacts.cacao.window.Window
|
import net.shadowfacts.cacao.window.Window
|
||||||
import org.lwjgl.glfw.GLFW
|
import org.lwjgl.glfw.GLFW
|
||||||
|
import org.lwjgl.opengl.GL11
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,10 +30,16 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
|
|
||||||
override val windows: List<Window> = _windows
|
override val windows: List<Window> = _windows
|
||||||
|
|
||||||
|
private var hasAppeared = false
|
||||||
|
|
||||||
|
|
||||||
override fun <T: Window> addWindow(window: T, index: Int): T {
|
override fun <T: Window> addWindow(window: T, index: Int): T {
|
||||||
if (window is ScreenHandlerWindow && window.screenHandler != handler) {
|
if (window is ScreenHandlerWindow && window.screenHandler != handler) {
|
||||||
throw RuntimeException("Adding ScreenHandlerWindow to CacaoHandledScreen with different screen handler is not supported")
|
throw RuntimeException("Adding ScreenHandlerWindow to CacaoHandledScreen with different screen handler is not supported")
|
||||||
}
|
}
|
||||||
|
if (hasAppeared) {
|
||||||
|
window.viewController.viewWillAppear()
|
||||||
|
}
|
||||||
|
|
||||||
_windows.add(index, window)
|
_windows.add(index, window)
|
||||||
|
|
||||||
|
@ -50,7 +57,13 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
override fun removeWindow(window: Window) {
|
override fun removeWindow(window: Window) {
|
||||||
_windows.remove(window)
|
_windows.remove(window)
|
||||||
if (windows.isEmpty()) {
|
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() {
|
override fun close() {
|
||||||
super.onClose()
|
super.close()
|
||||||
|
|
||||||
windows.forEach {
|
windows.forEach {
|
||||||
// todo: VC callbacks
|
it.viewController.viewWillDisappear()
|
||||||
|
it.viewController.viewDidDisappear()
|
||||||
|
|
||||||
it.firstResponder = null
|
it.firstResponder = null
|
||||||
}
|
}
|
||||||
|
@ -82,8 +96,8 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
val mouse = Point(mouseX, mouseY)
|
val mouse = Point(mouseX, mouseY)
|
||||||
|
|
||||||
RenderSystem.pushMatrix()
|
matrixStack.push()
|
||||||
RenderSystem.translatef(0f, 0f, -350f)
|
matrixStack.translate(0.0, 0.0, -350.0)
|
||||||
|
|
||||||
for (i in windows.indices) {
|
for (i in windows.indices) {
|
||||||
val it = windows[i]
|
val it = windows[i]
|
||||||
|
@ -100,7 +114,7 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
super.render(matrixStack, -1, -1, delta)
|
super.render(matrixStack, -1, -1, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderSystem.popMatrix()
|
matrixStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
it.draw(matrixStack, mouse, delta)
|
it.draw(matrixStack, mouse, delta)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.shadowfacts.cacao
|
package net.shadowfacts.cacao
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.screen.Screen
|
import net.minecraft.client.gui.screen.Screen
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.sound.SoundEvents
|
import net.minecraft.sound.SoundEvents
|
||||||
|
@ -32,6 +33,8 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
|
||||||
*/
|
*/
|
||||||
override val windows: List<Window> = _windows
|
override val windows: List<Window> = _windows
|
||||||
|
|
||||||
|
private var hasAppeared = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given window to this screen's window list at the given position.
|
* 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.
|
* @return The window that was added, as a convenience.
|
||||||
*/
|
*/
|
||||||
override fun <T: Window> addWindow(window: T, index: Int): T {
|
override fun <T: Window> addWindow(window: T, index: Int): T {
|
||||||
|
if (hasAppeared) {
|
||||||
|
window.viewController.viewWillAppear()
|
||||||
|
}
|
||||||
|
|
||||||
_windows.add(index, window)
|
_windows.add(index, window)
|
||||||
|
|
||||||
window.screen = this
|
window.screen = this
|
||||||
|
@ -62,7 +69,13 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
|
||||||
override fun removeWindow(window: Window) {
|
override fun removeWindow(window: Window) {
|
||||||
_windows.remove(window)
|
_windows.remove(window)
|
||||||
if (windows.isEmpty()) {
|
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() {
|
override fun close() {
|
||||||
super.onClose()
|
super.close()
|
||||||
|
|
||||||
windows.forEach {
|
windows.forEach {
|
||||||
// todo: VC callbacks
|
it.viewController.viewWillDisappear()
|
||||||
|
it.viewController.viewDidDisappear()
|
||||||
|
|
||||||
// resign the current first responder (if any)
|
// resign the current first responder (if any)
|
||||||
it.firstResponder = null
|
it.firstResponder = null
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
package net.shadowfacts.cacao.util
|
package net.shadowfacts.cacao.util
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.DrawableHelper
|
import net.minecraft.client.gui.DrawableHelper
|
||||||
|
import net.minecraft.client.gui.screen.Screen
|
||||||
import net.minecraft.client.render.*
|
import net.minecraft.client.render.*
|
||||||
import net.minecraft.client.sound.PositionedSoundInstance
|
import net.minecraft.client.sound.PositionedSoundInstance
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.sound.SoundEvent
|
import net.minecraft.sound.SoundEvent
|
||||||
|
import net.minecraft.text.LiteralText
|
||||||
import net.minecraft.text.OrderedText
|
import net.minecraft.text.OrderedText
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.minecraft.util.math.Matrix4f
|
import net.minecraft.util.math.Matrix4f
|
||||||
import net.shadowfacts.cacao.geometry.Point
|
import net.shadowfacts.cacao.geometry.Point
|
||||||
import net.shadowfacts.cacao.geometry.Rect
|
import net.shadowfacts.cacao.geometry.Rect
|
||||||
import net.shadowfacts.cacao.util.texture.Texture
|
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.
|
* 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) {
|
fun draw(matrixStack: MatrixStack, rect: Rect, texture: Texture) {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
color(1f, 1f, 1f, 1f)
|
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||||
MinecraftClient.getInstance().textureManager.bindTexture(texture.location)
|
RenderSystem.setShaderTexture(0, texture.location)
|
||||||
draw(matrixStack, rect.left, rect.top, texture.u, texture.v, rect.width, rect.height, texture.width, texture.height)
|
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) {
|
fun drawLine(start: Point, end: Point, z: Double, width: Float, color: Color) {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
|
|
||||||
GlStateManager.lineWidth(width)
|
RenderSystem.lineWidth(width)
|
||||||
val tessellator = Tessellator.getInstance()
|
val tessellator = Tessellator.getInstance()
|
||||||
val buffer = tessellator.buffer
|
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(start.x, start.y, z).color(color).next()
|
||||||
buffer.vertex(end.x, end.y, z).color(color).next()
|
buffer.vertex(end.x, end.y, z).color(color).next()
|
||||||
tessellator.draw()
|
tessellator.draw()
|
||||||
|
@ -71,19 +72,19 @@ object RenderHelper: DrawableHelper() {
|
||||||
val uEnd = (u + width).toFloat() / textureWidth
|
val uEnd = (u + width).toFloat() / textureWidth
|
||||||
val vStart = v.toFloat() / textureHeight
|
val vStart = v.toFloat() / textureHeight
|
||||||
val vEnd = (v + height).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
|
// 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) {
|
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
|
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, 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(), y1.toFloat(), z.toFloat()).texture(u1, v1).next()
|
||||||
bufferBuilder.vertex(matrix, x1.toFloat(), y0.toFloat(), z.toFloat()).texture(u1, v0).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.vertex(matrix, x0.toFloat(), y0.toFloat(), z.toFloat()).texture(u0, v0).next()
|
||||||
bufferBuilder.end()
|
bufferBuilder.end()
|
||||||
RenderSystem.enableAlphaTest()
|
|
||||||
BufferRenderer.draw(bufferBuilder)
|
BufferRenderer.draw(bufferBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,110 +96,22 @@ object RenderHelper: DrawableHelper() {
|
||||||
drawTooltip(matrixStack, texts.map(Text::asOrderedText), mouse)
|
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")
|
@JvmName("drawOrderedTooltip")
|
||||||
fun drawTooltip(matrixStack: MatrixStack, texts: List<OrderedText>, mouse: Point) {
|
fun drawTooltip(matrixStack: MatrixStack, texts: List<OrderedText>, mouse: Point) {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
if (texts.isEmpty()) return
|
if (texts.isEmpty()) return
|
||||||
|
|
||||||
val client = MinecraftClient.getInstance()
|
val client = MinecraftClient.getInstance()
|
||||||
val textRenderer = client.textRenderer
|
dummyScreen.width = client.window.scaledWidth
|
||||||
|
dummyScreen.height = client.window.scaledHeight
|
||||||
val maxWidth = texts.maxOf(textRenderer::getWidth)
|
dummyScreen.renderOrderedTooltip(matrixStack, texts, mouse.x.roundToInt(), mouse.y.roundToInt())
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -206,7 +119,7 @@ object RenderHelper: DrawableHelper() {
|
||||||
*/
|
*/
|
||||||
fun color(r: Float, g: Float, b: Float, alpha: Float) {
|
fun color(r: Float, g: Float, b: Float, alpha: Float) {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
RenderSystem.color4f(r, g, b, alpha)
|
RenderSystem.setShaderColor(r, g, b, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun VertexConsumer.color(color: Color): VertexConsumer {
|
private fun VertexConsumer.color(color: Color): VertexConsumer {
|
||||||
|
|
|
@ -26,11 +26,13 @@ class BezierCurveView(val curve: BezierCurve): View() {
|
||||||
var lineColor = Color.BLACK
|
var lineColor = Color.BLACK
|
||||||
|
|
||||||
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
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()) {
|
for ((index, point) in points.withIndex()) {
|
||||||
val next = points.getOrNull(index + 1) ?: break
|
val next = points.getOrNull(index + 1) ?: break
|
||||||
RenderHelper.drawLine(point, next, zIndex, lineWidth, lineColor)
|
RenderHelper.drawLine(point, next, zIndex, lineWidth, lineColor)
|
||||||
}
|
}
|
||||||
|
matrixStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -29,7 +29,7 @@ class DialogView(
|
||||||
CANCEL, CONFIRM, OK, CLOSE;
|
CANCEL, CONFIRM, OK, CLOSE;
|
||||||
|
|
||||||
override val localizedName: Text
|
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
|
private lateinit var background: NinePatchView
|
||||||
|
|
|
@ -12,7 +12,6 @@ import no.birkett.kiwi.Constraint
|
||||||
import no.birkett.kiwi.Solver
|
import no.birkett.kiwi.Solver
|
||||||
import java.lang.RuntimeException
|
import java.lang.RuntimeException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.HashSet
|
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -368,8 +367,8 @@ open class View(): Responder {
|
||||||
* @param delta The time since the last frame.
|
* @param delta The time since the last frame.
|
||||||
*/
|
*/
|
||||||
open fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
open fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||||
RenderHelper.pushMatrix()
|
matrixStack.push()
|
||||||
RenderHelper.translate(floor(frame.left), floor(frame.top))
|
matrixStack.translate(frame.left, frame.top, 0.0)
|
||||||
|
|
||||||
RenderHelper.fill(matrixStack, bounds, backgroundColor)
|
RenderHelper.fill(matrixStack, bounds, backgroundColor)
|
||||||
|
|
||||||
|
@ -380,7 +379,7 @@ open class View(): Responder {
|
||||||
it.draw(matrixStack, mouseInView, delta)
|
it.draw(matrixStack, mouseInView, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderHelper.popMatrix()
|
matrixStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -109,8 +109,8 @@ abstract class AbstractButton<Impl: AbstractButton<Impl>>(val content: View, val
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
override fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||||
RenderHelper.pushMatrix()
|
matrixStack.push()
|
||||||
RenderHelper.translate(floor(frame.left), floor(frame.top))
|
matrixStack.translate(frame.left, frame.top, 0.0)
|
||||||
|
|
||||||
RenderHelper.fill(matrixStack, bounds, backgroundColor)
|
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
|
// don't draw subviews, otherwise all background views + content will get drawn
|
||||||
|
|
||||||
RenderHelper.popMatrix()
|
matrixStack.pop()
|
||||||
|
|
||||||
if (tooltip != null && mouse in bounds) {
|
if (tooltip != null && mouse in bounds) {
|
||||||
window!!.drawTooltip(listOf(tooltip!!))
|
window!!.drawTooltip(listOf(tooltip!!))
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
package net.shadowfacts.cacao.view.textfield
|
package net.shadowfacts.cacao.view.textfield
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.screen.TickableElement
|
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget
|
import net.minecraft.client.gui.widget.TextFieldWidget
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.text.LiteralText
|
import net.minecraft.text.LiteralText
|
||||||
import net.shadowfacts.cacao.geometry.Point
|
import net.shadowfacts.cacao.geometry.Point
|
||||||
import net.shadowfacts.cacao.util.Color
|
|
||||||
import net.shadowfacts.cacao.util.KeyModifiers
|
import net.shadowfacts.cacao.util.KeyModifiers
|
||||||
import net.shadowfacts.cacao.util.MouseButton
|
import net.shadowfacts.cacao.util.MouseButton
|
||||||
import net.shadowfacts.cacao.util.RenderHelper
|
|
||||||
import net.shadowfacts.cacao.view.View
|
import net.shadowfacts.cacao.view.View
|
||||||
import net.shadowfacts.phycon.mixin.client.TextFieldWidgetAccessor
|
import net.shadowfacts.phycon.mixin.client.TextFieldWidgetAccessor
|
||||||
import org.lwjgl.glfw.GLFW
|
import org.lwjgl.glfw.GLFW
|
||||||
|
@ -25,7 +22,7 @@ import org.lwjgl.glfw.GLFW
|
||||||
*/
|
*/
|
||||||
abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
||||||
initialText: String
|
initialText: String
|
||||||
): View(), TickableElement {
|
): View() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that is invoked when the text in this text field changes.
|
* 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
|
var drawBackground = true
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
minecraftWidget.setHasBorder(value)
|
minecraftWidget.setDrawsBackground(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var originInWindow: Point
|
private lateinit var originInWindow: Point
|
||||||
|
@ -79,7 +76,7 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
||||||
init {
|
init {
|
||||||
minecraftWidget.text = initialText
|
minecraftWidget.text = initialText
|
||||||
minecraftWidget.setTextPredicate { this.validate(it) }
|
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) {
|
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||||
RenderHelper.pushMatrix()
|
matrixStack.push()
|
||||||
RenderHelper.translate(-originInWindow.x, -originInWindow.y)
|
matrixStack.translate(-originInWindow.x, -originInWindow.y, 0.0)
|
||||||
|
|
||||||
val mouseXInWindow = (mouse.x + originInWindow.x).toInt()
|
val mouseXInWindow = (mouse.x + originInWindow.x).toInt()
|
||||||
val mouseYInWindow = (mouse.y + originInWindow.y).toInt()
|
val mouseYInWindow = (mouse.y + originInWindow.y).toInt()
|
||||||
minecraftWidget.render(matrixStack, mouseXInWindow, mouseYInWindow, delta)
|
minecraftWidget.render(matrixStack, mouseXInWindow, mouseYInWindow, delta)
|
||||||
|
|
||||||
RenderHelper.popMatrix()
|
matrixStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
||||||
|
@ -135,12 +132,12 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
||||||
|
|
||||||
override fun didBecomeFirstResponder() {
|
override fun didBecomeFirstResponder() {
|
||||||
super.didBecomeFirstResponder()
|
super.didBecomeFirstResponder()
|
||||||
minecraftWidget.setSelected(true)
|
minecraftWidget.setTextFieldFocused(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun didResignFirstResponder() {
|
override fun didResignFirstResponder() {
|
||||||
super.didResignFirstResponder()
|
super.didResignFirstResponder()
|
||||||
minecraftWidget.setSelected(false)
|
minecraftWidget.setTextFieldFocused(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun charTyped(char: Char, modifiers: KeyModifiers): Boolean {
|
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)
|
return result || (isFirstResponder && keyCode != GLFW.GLFW_KEY_ESCAPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
fun tick() {
|
||||||
minecraftWidget.tick()
|
minecraftWidget.tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,11 +147,6 @@ class TabViewController<T: TabViewController.Tab>(
|
||||||
currentTabController.viewWillAppear()
|
currentTabController.viewWillAppear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun viewDidAppear() {
|
|
||||||
super.viewDidAppear()
|
|
||||||
currentTabController.viewDidAppear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun viewWillDisappear() {
|
override fun viewWillDisappear() {
|
||||||
super.viewWillDisappear()
|
super.viewWillDisappear()
|
||||||
currentTabController.viewWillDisappear()
|
currentTabController.viewWillDisappear()
|
||||||
|
@ -225,7 +220,6 @@ class TabViewController<T: TabViewController.Tab>(
|
||||||
embedChild(currentTabController, tabVCContainer)
|
embedChild(currentTabController, tabVCContainer)
|
||||||
currentTabController.didMoveTo(this)
|
currentTabController.didMoveTo(this)
|
||||||
currentTabController.viewWillAppear()
|
currentTabController.viewWillAppear()
|
||||||
currentTabController.viewDidAppear()
|
|
||||||
|
|
||||||
onTabChange?.invoke(currentTab)
|
onTabChange?.invoke(currentTab)
|
||||||
|
|
||||||
|
|
|
@ -122,12 +122,12 @@ abstract class ViewController {
|
||||||
children.forEach(ViewController::viewWillAppear)
|
children.forEach(ViewController::viewWillAppear)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Called immediately after the VC's view has first been displayed on screen.
|
// * Called immediately after the VC's view has first been displayed on screen.
|
||||||
*/
|
// */
|
||||||
open fun viewDidAppear() {
|
// open fun viewDidAppear() {
|
||||||
children.forEach(ViewController::viewDidAppear)
|
// children.forEach(ViewController::viewDidAppear)
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before the view will disappear from the screen, either because the VC has been removed from it's parent/screen
|
* Called before the view will disappear from the screen, either because the VC has been removed from it's parent/screen
|
||||||
|
|
|
@ -16,6 +16,7 @@ object DefaultPlugin: PhyConPlugin {
|
||||||
|
|
||||||
override fun initializePhyCon(api: PhyConAPI) {
|
override fun initializePhyCon(api: PhyConAPI) {
|
||||||
SORT_MODE = api.registerTerminalSetting(Identifier(PhysicalConnectivity.MODID, "sort"), SortMode.COUNT_HIGH_FIRST)
|
SORT_MODE = api.registerTerminalSetting(Identifier(PhysicalConnectivity.MODID, "sort"), SortMode.COUNT_HIGH_FIRST)
|
||||||
|
SORT_MODE.setPriority(Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@ package net.shadowfacts.phycon
|
||||||
|
|
||||||
import net.fabricmc.api.ModInitializer
|
import net.fabricmc.api.ModInitializer
|
||||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
|
||||||
import net.fabricmc.loader.api.FabricLoader
|
import net.fabricmc.loader.api.FabricLoader
|
||||||
import net.shadowfacts.phycon.api.PhyConPlugin
|
import net.shadowfacts.phycon.api.PhyConPlugin
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
import net.shadowfacts.phycon.init.PhyBlocks
|
||||||
import net.shadowfacts.phycon.init.PhyItems
|
import net.shadowfacts.phycon.init.PhyItems
|
||||||
|
@ -26,9 +28,12 @@ object PhysicalConnectivity: ModInitializer {
|
||||||
PhyItems.init()
|
PhyItems.init()
|
||||||
PhyScreens.init()
|
PhyScreens.init()
|
||||||
|
|
||||||
|
registerGlobalReceiver(C2SConfigureDevice)
|
||||||
|
registerGlobalReceiver(C2STerminalCraftingButton)
|
||||||
registerGlobalReceiver(C2STerminalRequestItem)
|
registerGlobalReceiver(C2STerminalRequestItem)
|
||||||
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
||||||
registerGlobalReceiver(C2SConfigureDevice)
|
|
||||||
|
ItemStorage.SIDED.registerForBlockEntity(P2PReceiverBlockEntity::provideItemStorage, PhyBlockEntities.P2P_RECEIVER)
|
||||||
|
|
||||||
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
|
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
|
||||||
it.initializePhyCon(PhyConAPIImpl)
|
it.initializePhyCon(PhyConAPIImpl)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import net.fabricmc.fabric.api.renderer.v1.RendererAccess
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial
|
||||||
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreen
|
||||||
import net.shadowfacts.phycon.init.PhyScreens
|
import net.shadowfacts.phycon.init.PhyScreens
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalScreen
|
import net.shadowfacts.phycon.block.terminal.TerminalScreen
|
||||||
import net.shadowfacts.phycon.client.PhyExtendedModelProvider
|
import net.shadowfacts.phycon.client.PhyExtendedModelProvider
|
||||||
|
@ -40,6 +41,7 @@ object PhysicalConnectivityClient: ClientModInitializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenRegistry.register(PhyScreens.TERMINAL, ::TerminalScreen)
|
ScreenRegistry.register(PhyScreens.TERMINAL, ::TerminalScreen)
|
||||||
|
ScreenRegistry.register(PhyScreens.CRAFTING_TERMINAL, ::CraftingTerminalScreen)
|
||||||
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
||||||
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,20 @@ package net.shadowfacts.phycon.block
|
||||||
|
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.block.BlockEntityProvider
|
import net.minecraft.block.BlockEntityProvider
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntityTicker
|
||||||
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.world.BlockView
|
import net.minecraft.world.BlockView
|
||||||
|
import net.minecraft.world.World
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class BlockWithEntity<T: BlockEntity>(settings: Settings): Block(settings), BlockEntityProvider {
|
abstract class BlockWithEntity<T: BlockEntity>(settings: Settings): Block(settings), BlockEntityProvider {
|
||||||
abstract override fun createBlockEntity(world: BlockView): T?
|
abstract override fun createBlockEntity(pos: BlockPos, state: BlockState): T?
|
||||||
|
|
||||||
fun getBlockEntity(world: BlockView, pos: BlockPos): T? {
|
fun getBlockEntity(world: BlockView, pos: BlockPos): T? {
|
||||||
val entity = world.getBlockEntity(pos)
|
val entity = world.getBlockEntity(pos)
|
||||||
return if (entity != null) {
|
return if (entity != null) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package net.shadowfacts.phycon.block
|
package net.shadowfacts.phycon.block
|
||||||
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntityTicker
|
||||||
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
@ -25,4 +28,14 @@ abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithE
|
||||||
getBlockEntity(world, pos)!!.onBreak()
|
getBlockEntity(world, pos)!!.onBreak()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun <T: BlockEntity> getTicker(world: World, state: BlockState, type: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||||
|
return if (world.isClient) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
BlockEntityTicker { world, blockPos, blockState, blockEntity ->
|
||||||
|
(blockEntity as DeviceBlockEntity).tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
package net.shadowfacts.phycon.block
|
package net.shadowfacts.phycon.block
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.util.Tickable
|
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.PacketSink
|
|
||||||
import net.shadowfacts.phycon.api.PacketSource
|
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
|
import net.shadowfacts.phycon.api.PacketSink
|
||||||
|
import net.shadowfacts.phycon.api.PacketSource
|
||||||
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
import net.shadowfacts.phycon.util.NetworkUtil
|
|
||||||
import net.shadowfacts.phycon.frame.ARPQueryFrame
|
import net.shadowfacts.phycon.frame.ARPQueryFrame
|
||||||
import net.shadowfacts.phycon.frame.ARPResponseFrame
|
import net.shadowfacts.phycon.frame.ARPResponseFrame
|
||||||
import net.shadowfacts.phycon.frame.BasePacketFrame
|
import net.shadowfacts.phycon.frame.BasePacketFrame
|
||||||
|
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state),
|
||||||
BlockEntityClientSerializable,
|
|
||||||
Tickable,
|
|
||||||
PacketSink,
|
PacketSink,
|
||||||
PacketSource,
|
PacketSource,
|
||||||
Interface {
|
Interface {
|
||||||
|
@ -45,6 +45,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
|
|
||||||
private val arpTable = mutableMapOf<IPAddress, MACAddress>()
|
private val arpTable = mutableMapOf<IPAddress, MACAddress>()
|
||||||
private val packetQueue = LinkedList<PendingPacket>()
|
private val packetQueue = LinkedList<PendingPacket>()
|
||||||
|
private var cachedDestination: WeakReference<Interface>? = null
|
||||||
|
|
||||||
var counter: Long = 0
|
var counter: Long = 0
|
||||||
|
|
||||||
|
@ -59,6 +60,9 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
is DeviceRemovedPacket -> {
|
is DeviceRemovedPacket -> {
|
||||||
arpTable.remove(packet.source)
|
arpTable.remove(packet.source)
|
||||||
}
|
}
|
||||||
|
is PingPacket -> {
|
||||||
|
sendPacket(PongPacket(ipAddress, packet.source))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handle(packet)
|
handle(packet)
|
||||||
}
|
}
|
||||||
|
@ -72,6 +76,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
when (frame) {
|
when (frame) {
|
||||||
is ARPQueryFrame -> handleARPQuery(frame)
|
is ARPQueryFrame -> handleARPQuery(frame)
|
||||||
is ARPResponseFrame -> handleARPResponse(frame)
|
is ARPResponseFrame -> handleARPResponse(frame)
|
||||||
|
is NetworkSplitFrame -> handleNetworkSplit()
|
||||||
is PacketFrame -> {
|
is PacketFrame -> {
|
||||||
if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) {
|
if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) {
|
||||||
doHandlePacket(frame.packet)
|
doHandlePacket(frame.packet)
|
||||||
|
@ -104,6 +109,11 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
packetQueue.removeAll(toRemove)
|
packetQueue.removeAll(toRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun handleNetworkSplit() {
|
||||||
|
arpTable.clear()
|
||||||
|
cachedDestination = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun sendPacket(packet: Packet) {
|
override fun sendPacket(packet: Packet) {
|
||||||
if (packet.destination.isBroadcast) {
|
if (packet.destination.isBroadcast) {
|
||||||
send(BasePacketFrame(packet, macAddress, MACAddress.BROADCAST))
|
send(BasePacketFrame(packet, macAddress, MACAddress.BROADCAST))
|
||||||
|
@ -118,15 +128,29 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun findDestination(): Interface? {
|
open fun findDestination(): Interface? {
|
||||||
|
val cachedDestination = this.cachedDestination?.get()
|
||||||
|
if (cachedDestination != null) {
|
||||||
|
return cachedDestination
|
||||||
|
}
|
||||||
|
|
||||||
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
|
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
|
||||||
return when (sides.size) {
|
return when (sides.size) {
|
||||||
0 -> null
|
0 -> null
|
||||||
1 -> NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
|
1 -> {
|
||||||
|
NetworkUtil.findConnectedInterface(world!!, pos, sides.first())?.also {
|
||||||
|
this.cachedDestination = WeakReference(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun cableDisconnected() {
|
||||||
|
cachedDestination = null
|
||||||
|
handleNetworkSplit()
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun tick() {
|
||||||
counter++
|
counter++
|
||||||
|
|
||||||
if (!world!!.isClient) {
|
if (!world!!.isClient) {
|
||||||
|
@ -148,33 +172,50 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun toCommonTag(tag: CompoundTag) {
|
protected open fun toCommonTag(tag: NbtCompound) {
|
||||||
tag.putInt("IPAddress", ipAddress.address)
|
tag.putInt("IPAddress", ipAddress.address)
|
||||||
tag.putLong("MACAddress", macAddress.address)
|
tag.putLong("MACAddress", macAddress.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun fromCommonTag(tag: CompoundTag) {
|
protected open fun fromCommonTag(tag: NbtCompound) {
|
||||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
override fun writeNbt(tag: NbtCompound) {
|
||||||
|
super.writeNbt(tag)
|
||||||
toCommonTag(tag)
|
toCommonTag(tag)
|
||||||
return super.toTag(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun readNbt(tag: NbtCompound) {
|
||||||
super.fromTag(state, tag)
|
super.readNbt(tag)
|
||||||
fromCommonTag(tag)
|
fromCommonTag(tag)
|
||||||
|
if (tag.getBoolean("_SyncPacket")) {
|
||||||
|
fromClientTag(tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
override fun toUpdatePacket(): BlockEntityUpdateS2CPacket {
|
||||||
|
return BlockEntityUpdateS2CPacket.create(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toInitialChunkDataNbt(): NbtCompound {
|
||||||
|
val tag = NbtCompound()
|
||||||
|
tag.putBoolean("_SyncPacket", true)
|
||||||
|
return toClientTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun toClientTag(tag: NbtCompound): NbtCompound {
|
||||||
toCommonTag(tag)
|
toCommonTag(tag)
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromClientTag(tag: CompoundTag) {
|
open fun fromClientTag(tag: NbtCompound) {
|
||||||
fromCommonTag(tag)
|
}
|
||||||
|
|
||||||
|
fun markUpdate() {
|
||||||
|
markDirty()
|
||||||
|
world!!.updateListeners(pos, cachedState, cachedState, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onBreak() {
|
fun onBreak() {
|
||||||
|
|
|
@ -2,8 +2,10 @@ package net.shadowfacts.phycon.block.cable
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings
|
import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings
|
||||||
import net.minecraft.block.*
|
import net.minecraft.block.*
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.state.StateManager
|
import net.minecraft.state.StateManager
|
||||||
import net.minecraft.state.property.EnumProperty
|
import net.minecraft.state.property.EnumProperty
|
||||||
import net.minecraft.util.ActionResult
|
import net.minecraft.util.ActionResult
|
||||||
|
@ -23,9 +25,11 @@ import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.NetworkCableBlock
|
import net.shadowfacts.phycon.api.NetworkCableBlock
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.init.PhyItems
|
import net.shadowfacts.phycon.init.PhyItems
|
||||||
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
|
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
|
||||||
import net.shadowfacts.phycon.util.CableConnection
|
import net.shadowfacts.phycon.util.CableConnection
|
||||||
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import net.shadowfacts.phycon.util.containsInclusive
|
import net.shadowfacts.phycon.util.containsInclusive
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -38,11 +42,10 @@ class CableBlock(
|
||||||
FabricBlockSettings.of(CABLE_MATERIAL)
|
FabricBlockSettings.of(CABLE_MATERIAL)
|
||||||
.strength(0.3f)
|
.strength(0.3f)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
.breakByHand(true)
|
|
||||||
), NetworkCableBlock {
|
), NetworkCableBlock {
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
|
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
|
||||||
val CABLE_MATERIAL = Material.Builder(MaterialColor.BLUE).build()
|
val CABLE_MATERIAL = Material.Builder(MapColor.BLUE).build()
|
||||||
val CENTER_SHAPE = createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 10.0)
|
val CENTER_SHAPE = createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 10.0)
|
||||||
val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
|
val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
|
||||||
Direction.DOWN to createCuboidShape(6.0, 0.0, 6.0, 10.0, 6.0, 10.0),
|
Direction.DOWN to createCuboidShape(6.0, 0.0, 6.0, 10.0, 6.0, 10.0),
|
||||||
|
@ -196,4 +199,18 @@ class CableBlock(
|
||||||
return getShape(state)
|
return getShape(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
|
||||||
|
super.onBreak(world, pos, state, player)
|
||||||
|
if (!world.isClient) {
|
||||||
|
world.server?.execute {
|
||||||
|
// notify devices on either end that the connection was broken (i.e., unset the cached receivers)
|
||||||
|
val connectedSides = getNetworkConnectedSides(state, world, pos)
|
||||||
|
for (side in connectedSides) {
|
||||||
|
val dest = NetworkUtil.findConnectedInterface(world, pos, side)
|
||||||
|
dest?.cableDisconnected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -57,7 +59,7 @@ class ExtractorBlock: FaceDeviceBlock<ExtractorBlockEntity>(
|
||||||
arr[i] = 16.0 - arr[i]
|
arr[i] = 16.0 - arr[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createCuboidShape(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5])
|
createCuboidShape(min(arr[0], arr[3]), min(arr[1], arr[4]), min(arr[2], arr[5]), max(arr[0], arr[3]), max(arr[1], arr[4]), max(arr[2], arr[5]))
|
||||||
}
|
}
|
||||||
EXTRACTOR_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
EXTRACTOR_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
||||||
}
|
}
|
||||||
|
@ -67,7 +69,7 @@ class ExtractorBlock: FaceDeviceBlock<ExtractorBlockEntity>(
|
||||||
override val faceThickness = 6.0
|
override val faceThickness = 6.0
|
||||||
override val faceShapes: Map<Direction, VoxelShape> = EXTRACTOR_SHAPES
|
override val faceShapes: Map<Direction, VoxelShape> = EXTRACTOR_SHAPES
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = ExtractorBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
|
|
|
@ -5,8 +5,10 @@ import alexiil.mc.lib.attributes.Simulation
|
||||||
import alexiil.mc.lib.attributes.item.FixedItemInv
|
import alexiil.mc.lib.attributes.item.FixedItemInv
|
||||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter
|
import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
@ -26,7 +28,7 @@ import kotlin.properties.Delegates
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
class ExtractorBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.EXTRACTOR, pos, state),
|
||||||
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
||||||
ActivationController.ActivatableDevice,
|
ActivationController.ActivatableDevice,
|
||||||
ClientConfigurableDevice {
|
ClientConfigurableDevice {
|
||||||
|
@ -106,21 +108,21 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
loadDeviceConfiguration(tag)
|
loadDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
tag.putString("ActivationMode", controller.activationMode.name)
|
tag.putString("ActivationMode", controller.activationMode.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -66,7 +68,7 @@ class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
|
||||||
arr[i] = 16.0 - arr[i]
|
arr[i] = 16.0 - arr[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createCuboidShape(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5])
|
createCuboidShape(min(arr[0], arr[3]), min(arr[1], arr[4]), min(arr[2], arr[5]), max(arr[0], arr[3]), max(arr[1], arr[4]), max(arr[2], arr[5]))
|
||||||
}
|
}
|
||||||
INSERTER_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
INSERTER_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,7 @@ class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
|
||||||
override val faceThickness = 6.0
|
override val faceThickness = 6.0
|
||||||
override val faceShapes: Map<Direction, VoxelShape> = INSERTER_SHAPES
|
override val faceShapes: Map<Direction, VoxelShape> = INSERTER_SHAPES
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = InserterBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = InserterBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
|
@ -94,7 +96,7 @@ class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
val be = getBlockEntity(world, pos)!!
|
val be = getBlockEntity(world, pos)!!
|
||||||
|
|
||||||
be.sync()
|
be.markUpdate()
|
||||||
|
|
||||||
val factory = object: ExtendedScreenHandlerFactory {
|
val factory = object: ExtendedScreenHandlerFactory {
|
||||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||||
|
|
|
@ -5,8 +5,10 @@ import alexiil.mc.lib.attributes.Simulation
|
||||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
import alexiil.mc.lib.attributes.item.ItemInsertable
|
import alexiil.mc.lib.attributes.item.ItemInsertable
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
|
@ -25,7 +27,7 @@ import kotlin.math.min
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
|
class InserterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.INSERTER, pos, state),
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
ActivationController.ActivatableDevice,
|
ActivationController.ActivatableDevice,
|
||||||
ClientConfigurableDevice,
|
ClientConfigurableDevice,
|
||||||
|
@ -132,24 +134,24 @@ class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
|
||||||
currentRequest = null
|
currentRequest = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
tag.put("StackToExtract", stackToExtract.toTag(CompoundTag()))
|
tag.put("StackToExtract", stackToExtract.writeNbt(NbtCompound()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
loadDeviceConfiguration(tag)
|
loadDeviceConfiguration(tag)
|
||||||
stackToExtract = ItemStack.fromTag(tag.getCompound("StackToExtract"))
|
stackToExtract = ItemStack.fromNbt(tag.getCompound("StackToExtract"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
tag.putString("ActivationMode", controller.activationMode.name)
|
tag.putString("ActivationMode", controller.activationMode.name)
|
||||||
tag.putInt("AmountToExtract", amountToExtract)
|
tag.putInt("AmountToExtract", amountToExtract)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||||
amountToExtract = tag.getInt("AmountToExtract")
|
amountToExtract = tag.getInt("AmountToExtract")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package net.shadowfacts.phycon.block.inserter
|
||||||
import com.mojang.blaze3d.systems.RenderSystem
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget
|
import net.minecraft.client.gui.widget.TextFieldWidget
|
||||||
|
import net.minecraft.client.render.GameRenderer
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.screen.slot.Slot
|
import net.minecraft.screen.slot.Slot
|
||||||
|
@ -44,9 +45,9 @@ class InserterScreen(
|
||||||
|
|
||||||
amountField = TextFieldWidget(textRenderer, x + 57, y + 24, 80, 9, LiteralText("Amount"))
|
amountField = TextFieldWidget(textRenderer, x + 57, y + 24, 80, 9, LiteralText("Amount"))
|
||||||
amountField.text = handler.inserter.amountToExtract.toString()
|
amountField.text = handler.inserter.amountToExtract.toString()
|
||||||
amountField.setHasBorder(false)
|
amountField.setDrawsBackground(false)
|
||||||
amountField.isVisible = true
|
amountField.isVisible = true
|
||||||
amountField.setSelected(true)
|
amountField.setTextFieldFocused(true)
|
||||||
amountField.setEditableColor(0xffffff)
|
amountField.setEditableColor(0xffffff)
|
||||||
amountField.setTextPredicate {
|
amountField.setTextPredicate {
|
||||||
if (it.isEmpty()) {
|
if (it.isEmpty()) {
|
||||||
|
@ -60,7 +61,7 @@ class InserterScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addChild(amountField)
|
addDrawableChild(amountField)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun amountUpdated() {
|
fun amountUpdated() {
|
||||||
|
@ -70,16 +71,16 @@ class InserterScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun handledScreenTick() {
|
||||||
super.tick()
|
super.handledScreenTick()
|
||||||
amountField.tick()
|
amountField.tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
renderBackground(matrixStack)
|
renderBackground(matrixStack)
|
||||||
|
|
||||||
RenderSystem.color4f(1f, 1f, 1f, 1f)
|
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||||
client!!.textureManager.bindTexture(BACKGROUND)
|
RenderSystem.setShaderTexture(0, BACKGROUND)
|
||||||
val x = (width - backgroundWidth) / 2
|
val x = (width - backgroundWidth) / 2
|
||||||
val y = (height - backgroundHeight) / 2
|
val y = (height - backgroundHeight) / 2
|
||||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||||
|
@ -96,7 +97,7 @@ class InserterScreen(
|
||||||
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, slotActionType: SlotActionType?) {
|
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, slotActionType: SlotActionType?) {
|
||||||
super.onMouseClick(slot, invSlot, clickData, slotActionType)
|
super.onMouseClick(slot, invSlot, clickData, slotActionType)
|
||||||
|
|
||||||
amountField.setSelected(true)
|
amountField.setTextFieldFocused(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun charTyped(c: Char, i: Int): Boolean {
|
override fun charTyped(c: Char, i: Int): Boolean {
|
||||||
|
|
|
@ -60,17 +60,17 @@ class InserterScreenHandler(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
|
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity) {
|
||||||
// fake slot
|
// fake slot
|
||||||
if (slotId == 0) {
|
if (slotId == 0) {
|
||||||
if (player.inventory.cursorStack.isEmpty) {
|
if (cursorStack.isEmpty) {
|
||||||
inserter.stackToExtract = ItemStack.EMPTY
|
inserter.stackToExtract = ItemStack.EMPTY
|
||||||
} else {
|
} else {
|
||||||
inserter.stackToExtract = player.inventory.cursorStack.copyWithCount(1)
|
inserter.stackToExtract = cursorStack.copyWithCount(1)
|
||||||
}
|
}
|
||||||
stackToExtractChanged()
|
stackToExtractChanged()
|
||||||
}
|
}
|
||||||
return super.onSlotClick(slotId, clickData, actionType, player)
|
super.onSlotClick(slotId, clickData, actionType, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||||
|
|
|
@ -51,7 +51,7 @@ class MinerBlock: DeviceBlock<MinerBlockEntity>(
|
||||||
builder.add(FACING)
|
builder.add(FACING)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = MinerBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = MinerBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
|
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
|
||||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
||||||
|
|
|
@ -7,7 +7,7 @@ import net.minecraft.block.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.item.Items
|
import net.minecraft.item.Items
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.server.world.ServerWorld
|
import net.minecraft.server.world.ServerWorld
|
||||||
import net.minecraft.text.TranslatableText
|
import net.minecraft.text.TranslatableText
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
|
@ -27,7 +27,7 @@ import kotlin.math.min
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
class MinerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.MINER, pos, state),
|
||||||
NetworkStackProvider,
|
NetworkStackProvider,
|
||||||
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion>,
|
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion>,
|
||||||
ActivationController.ActivatableDevice,
|
ActivationController.ActivatableDevice,
|
||||||
|
@ -57,10 +57,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||||
if (minerMode != MinerMode.ON_DEMAND) {
|
if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
|
sendPacket(ReadGroupedInventoryPacket(invProxy, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||||
|
@ -156,23 +156,23 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
return minerMode == MinerMode.ON_DEMAND
|
return minerMode == MinerMode.ON_DEMAND
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
loadDeviceConfiguration(tag)
|
loadDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
tag.putString("MinerMode", minerMode.name)
|
tag.putString("MinerMode", minerMode.name)
|
||||||
tag.putString("ActivationMode", controller.activationMode.name)
|
tag.putString("ActivationMode", controller.activationMode.name)
|
||||||
tag.putInt("ProviderPriority", providerPriority)
|
tag.putInt("ProviderPriority", providerPriority)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
|
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
|
||||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||||
providerPriority = tag.getInt("ProviderPriority")
|
providerPriority = tag.getInt("ProviderPriority")
|
||||||
|
@ -181,7 +181,7 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
enum class MinerMode {
|
enum class MinerMode {
|
||||||
ON_DEMAND, AUTOMATIC;
|
ON_DEMAND, AUTOMATIC;
|
||||||
|
|
||||||
val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.toLowerCase()}")
|
val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.lowercase()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
|
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
|
||||||
|
@ -205,7 +205,8 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
|
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
|
||||||
if (cachedDrops == null || realState != cachedState || recalculate) {
|
if (cachedDrops == null || realState != cachedState || recalculate) {
|
||||||
cachedState = realState
|
cachedState = realState
|
||||||
val be = if (realState.block.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
|
||||||
|
val be = if (realState.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
||||||
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL)
|
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL)
|
||||||
}
|
}
|
||||||
return cachedDrops!!
|
return cachedDrops!!
|
||||||
|
|
|
@ -40,7 +40,7 @@ class InterfaceBlock: FaceDeviceBlock<InterfaceBlockEntity>(
|
||||||
Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0)
|
Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = InterfaceBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
|
|
|
@ -6,7 +6,8 @@ import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
@ -18,12 +19,13 @@ import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||||
import net.shadowfacts.phycon.component.handleItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
class InterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.INTERFACE, pos, state),
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
NetworkStackProvider,
|
NetworkStackProvider,
|
||||||
NetworkStackReceiver,
|
NetworkStackReceiver,
|
||||||
|
@ -36,20 +38,21 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||||
override var receiverPriority = 0
|
override var receiverPriority = 0
|
||||||
var syncPriorities = true
|
var syncPriorities = true
|
||||||
|
|
||||||
// todo: should this be a weak ref?
|
private var inventory: WeakReference<GroupedItemInv>? = null
|
||||||
private var inventory: GroupedItemInv? = null
|
|
||||||
|
|
||||||
fun updateInventory() {
|
fun updateInventory() {
|
||||||
val offsetPos = pos.offset(facing)
|
val offsetPos = pos.offset(facing)
|
||||||
val option = SearchOptions.inDirection(facing)
|
val option = SearchOptions.inDirection(facing)
|
||||||
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
|
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option).let {
|
||||||
|
WeakReference(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInventory(): GroupedItemInv? {
|
private fun getInventory(): GroupedItemInv? {
|
||||||
// if we don't have an inventory, try to get one
|
// if we don't have an inventory, try to get one
|
||||||
// this happens when readAll is called before a neighbor state changes, such as immediately after world load
|
// this happens when readAll is called before a neighbor state changes, such as immediately after world load
|
||||||
if (inventory == null) updateInventory()
|
if (inventory?.get() == null) updateInventory()
|
||||||
return inventory
|
return inventory?.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
|
@ -63,8 +66,11 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||||
|
if (packet.kind != RequestInventoryPacket.Kind.GROUPED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source))
|
sendPacket(ReadGroupedInventoryPacket(inv, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,23 +115,23 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
loadDeviceConfiguration(tag)
|
loadDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
tag.putInt("ProviderPriority", providerPriority)
|
tag.putInt("ProviderPriority", providerPriority)
|
||||||
tag.putInt("ReceiverPriority", receiverPriority)
|
tag.putInt("ReceiverPriority", receiverPriority)
|
||||||
tag.putBoolean("SyncPriorities", syncPriorities)
|
tag.putBoolean("SyncPriorities", syncPriorities)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
providerPriority = tag.getInt("ProviderPriority")
|
providerPriority = tag.getInt("ProviderPriority")
|
||||||
receiverPriority = tag.getInt("ReceiverPriority")
|
receiverPriority = tag.getInt("ReceiverPriority")
|
||||||
syncPriorities = tag.getBoolean("SyncPriorities")
|
syncPriorities = tag.getBoolean("SyncPriorities")
|
||||||
|
|
|
@ -4,6 +4,9 @@ import alexiil.mc.lib.attributes.AttributeList
|
||||||
import alexiil.mc.lib.attributes.AttributeProvider
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.Material
|
import net.minecraft.block.Material
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntityTicker
|
||||||
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.sound.BlockSoundGroup
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
|
@ -40,7 +43,17 @@ class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(
|
||||||
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
|
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = SwitchBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = SwitchBlockEntity(pos, state)
|
||||||
|
|
||||||
|
override fun <T: BlockEntity> getTicker(world: World, state: BlockState, type: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||||
|
return if (world.isClient) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
BlockEntityTicker { world, blockPos, blockState, blockEntity ->
|
||||||
|
(blockEntity as SwitchBlockEntity).tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||||
to.offer(getBlockEntity(world, pos))
|
to.offer(getBlockEntity(world, pos))
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package net.shadowfacts.phycon.block.netswitch
|
package net.shadowfacts.phycon.block.netswitch
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.nbt.ListTag
|
import net.minecraft.nbt.NbtList
|
||||||
import net.minecraft.util.Tickable
|
import net.minecraft.network.Packet
|
||||||
|
import net.minecraft.network.listener.ClientPlayPacketListener
|
||||||
|
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
|
@ -15,6 +17,7 @@ import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
import net.shadowfacts.phycon.frame.BasePacketFrame
|
import net.shadowfacts.phycon.frame.BasePacketFrame
|
||||||
|
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import net.shadowfacts.phycon.util.NetworkUtil
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
|
@ -25,9 +28,7 @@ import java.util.LinkedList
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
class SwitchBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(PhyBlockEntities.SWITCH, pos, state) {
|
||||||
BlockEntityClientSerializable,
|
|
||||||
Tickable {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var SWITCHING_CAPACITY = 256 // 256 packets/tick
|
var SWITCHING_CAPACITY = 256 // 256 packets/tick
|
||||||
|
@ -36,6 +37,7 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) }
|
val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) }
|
||||||
|
|
||||||
private val macTable = mutableMapOf<MACAddress, Direction>()
|
private val macTable = mutableMapOf<MACAddress, Direction>()
|
||||||
|
private val destinationCache = Array<WeakReference<Interface>?>(6) { null }
|
||||||
private var packetsHandledThisTick = 0
|
private var packetsHandledThisTick = 0
|
||||||
private var delayedPackets: Deque<Pair<PacketFrame, SwitchInterface>> = LinkedList()
|
private var delayedPackets: Deque<Pair<PacketFrame, SwitchInterface>> = LinkedList()
|
||||||
|
|
||||||
|
@ -65,12 +67,12 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) forwarding {} to side {}", this, fromItf.side, fromItf.macAddress, frame, dir)
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) forwarding {} to side {}", this, fromItf.side, fromItf.macAddress, frame, dir)
|
||||||
interfaceForSide(dir).send(frame)
|
interfaceForSide(dir).send(frame)
|
||||||
} else {
|
} else {
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) flooding {}", this, fromItf.side, fromItf.macAddress, frame)
|
|
||||||
flood(frame, fromItf)
|
flood(frame, fromItf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flood(frame: EthernetFrame, source: Interface) {
|
private fun flood(frame: EthernetFrame, source: SwitchInterface) {
|
||||||
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) flooding {}", this, source.side, source.macAddress, frame)
|
||||||
for (itf in interfaces) {
|
for (itf in interfaces) {
|
||||||
if (source == itf) continue
|
if (source == itf) continue
|
||||||
itf.send(frame)
|
itf.send(frame)
|
||||||
|
@ -79,10 +81,23 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
|
|
||||||
private fun findDestination(fromItf: Interface): Interface? {
|
private fun findDestination(fromItf: Interface): Interface? {
|
||||||
val side = (fromItf as SwitchInterface).side
|
val side = (fromItf as SwitchInterface).side
|
||||||
return NetworkUtil.findConnectedInterface(world!!, pos, side)
|
return destinationCache[side.ordinal]?.get()
|
||||||
|
?: NetworkUtil.findConnectedInterface(world!!, pos, side)?.also {
|
||||||
|
destinationCache[side.ordinal] = WeakReference(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
private fun cableDisconnected(itf: SwitchInterface) {
|
||||||
|
macTable.entries.filter {
|
||||||
|
it.value == itf.side
|
||||||
|
}.forEach {
|
||||||
|
macTable.remove(it.key)
|
||||||
|
}
|
||||||
|
destinationCache[itf.side.ordinal] = null
|
||||||
|
flood(NetworkSplitFrame(itf.macAddress), itf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tick() {
|
||||||
packetsHandledThisTick = 0
|
packetsHandledThisTick = 0
|
||||||
|
|
||||||
while (delayedPackets.isNotEmpty() && packetsHandledThisTick <= SWITCHING_CAPACITY) {
|
while (delayedPackets.isNotEmpty() && packetsHandledThisTick <= SWITCHING_CAPACITY) {
|
||||||
|
@ -91,39 +106,41 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
override fun writeNbt(tag: NbtCompound) {
|
||||||
|
super.writeNbt(tag)
|
||||||
|
|
||||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||||
val list = ListTag()
|
val list = NbtList()
|
||||||
for ((frame, fromItf) in delayedPackets) {
|
for ((frame, fromItf) in delayedPackets) {
|
||||||
val packet = frame.packet
|
val packet = frame.packet
|
||||||
if (packet !is ItemStackPacket) continue
|
if (packet !is ItemStackPacket) continue
|
||||||
val compound = CompoundTag()
|
val compound = NbtCompound()
|
||||||
compound.putInt("FromItfSide", fromItf.side.ordinal)
|
compound.putInt("FromItfSide", fromItf.side.ordinal)
|
||||||
compound.putInt("SourceIP", packet.source.address)
|
compound.putInt("SourceIP", packet.source.address)
|
||||||
compound.putInt("DestinationIP", packet.destination.address)
|
compound.putInt("DestinationIP", packet.destination.address)
|
||||||
compound.putLong("SourceMAC", frame.source.address)
|
compound.putLong("SourceMAC", frame.source.address)
|
||||||
compound.putLong("DestinationMAC", frame.destination.address)
|
compound.putLong("DestinationMAC", frame.destination.address)
|
||||||
compound.put("Stack", packet.stack.toTag(CompoundTag()))
|
compound.put("Stack", packet.stack.writeNbt(NbtCompound()))
|
||||||
list.add(compound)
|
list.add(compound)
|
||||||
}
|
}
|
||||||
tag.put("DelayedStackPackets", list)
|
tag.put("DelayedStackPackets", list)
|
||||||
return super.toTag(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun readNbt(tag: NbtCompound) {
|
||||||
super.fromTag(state, tag)
|
super.readNbt(tag)
|
||||||
|
|
||||||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
||||||
interfaces[i].macAddress = MACAddress(l)
|
interfaces[i].macAddress = MACAddress(l)
|
||||||
}
|
}
|
||||||
tag.getList("DelayedStackPackets", 10).forEach { it ->
|
tag.getList("DelayedStackPackets", 10).forEach { it ->
|
||||||
val compound = it as CompoundTag
|
val compound = it as NbtCompound
|
||||||
val fromItfSide = Direction.values()[compound.getInt("FromItfSide")]
|
val fromItfSide = Direction.values()[compound.getInt("FromItfSide")]
|
||||||
val fromItf = interfaces.find { it.side == fromItfSide }!!
|
val fromItf = interfaces.find { it.side == fromItfSide }!!
|
||||||
val sourceIP = IPAddress(compound.getInt("SourceIP"))
|
val sourceIP = IPAddress(compound.getInt("SourceIP"))
|
||||||
val destinationIP = IPAddress(compound.getInt("DestinationIP"))
|
val destinationIP = IPAddress(compound.getInt("DestinationIP"))
|
||||||
val sourceMAC = MACAddress(compound.getLong("SourceMAC"))
|
val sourceMAC = MACAddress(compound.getLong("SourceMAC"))
|
||||||
val destinationMAC = MACAddress(compound.getLong("DestinationMAC"))
|
val destinationMAC = MACAddress(compound.getLong("DestinationMAC"))
|
||||||
val stack = ItemStack.fromTag(compound.getCompound("Stack"))
|
val stack = ItemStack.fromNbt(compound.getCompound("Stack"))
|
||||||
if (!stack.isEmpty) {
|
if (!stack.isEmpty) {
|
||||||
val packet = ItemStackPacket(stack, sourceIP, destinationIP)
|
val packet = ItemStackPacket(stack, sourceIP, destinationIP)
|
||||||
val frame = BasePacketFrame(packet, sourceMAC, destinationMAC)
|
val frame = BasePacketFrame(packet, sourceMAC, destinationMAC)
|
||||||
|
@ -132,15 +149,14 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
|
||||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
return BlockEntityUpdateS2CPacket.create(this)
|
||||||
return tag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromClientTag(tag: CompoundTag) {
|
override fun toInitialChunkDataNbt(): NbtCompound {
|
||||||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
val tag = NbtCompound()
|
||||||
interfaces[i].macAddress = MACAddress(l)
|
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||||
}
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
class SwitchInterface(
|
class SwitchInterface(
|
||||||
|
@ -157,6 +173,10 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
override fun send(frame: EthernetFrame) {
|
override fun send(frame: EthernetFrame) {
|
||||||
switch.get()?.findDestination(this)?.receive(frame)
|
switch.get()?.findDestination(this)?.receive(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun cableDisconnected() {
|
||||||
|
switch.get()?.cableDisconnected(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package net.shadowfacts.phycon.block.p2p
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.Material
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class P2PInterfaceBlock: FaceDeviceBlock<P2PInterfaceBlockEntity>(
|
||||||
|
Settings.of(Material.METAL)
|
||||||
|
.strength(1.5f)
|
||||||
|
.sounds(BlockSoundGroup.METAL)
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier(PhysicalConnectivity.MODID, "p2p_interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val faceThickness = 4.0
|
||||||
|
override val faceShapes = mapOf(
|
||||||
|
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 4.0, 16.0),
|
||||||
|
Direction.UP to createCuboidShape(0.0, 12.0, 0.0, 16.0, 16.0, 16.0),
|
||||||
|
Direction.NORTH to createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 4.0),
|
||||||
|
Direction.SOUTH to createCuboidShape(0.0, 0.0, 12.0, 16.0, 16.0, 16.0),
|
||||||
|
Direction.WEST to createCuboidShape(0.0, 0.0, 0.0, 4.0, 16.0, 16.0),
|
||||||
|
Direction.EAST to createCuboidShape(12.0, 0.0, 0.0, 16.0, 16.0, 16.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = P2PInterfaceBlockEntity(pos, state)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package net.shadowfacts.phycon.block.p2p
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
import net.shadowfacts.phycon.packet.ReadItemStoragePacket
|
||||||
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class P2PInterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.P2P_INTERFACE, pos, state) {
|
||||||
|
|
||||||
|
private var inventory: Storage<ItemVariant>? = null
|
||||||
|
|
||||||
|
private fun updateInventory() {
|
||||||
|
val facing = cachedState[FaceDeviceBlock.FACING]
|
||||||
|
inventory = ItemStorage.SIDED.find(world!!, pos.offset(facing), facing.opposite)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInventory(): Storage<ItemVariant>? {
|
||||||
|
if (inventory == null) updateInventory()
|
||||||
|
return inventory
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
|
when (packet) {
|
||||||
|
is RequestInventoryPacket -> handleRequestInventory(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||||
|
if (packet.kind != RequestInventoryPacket.Kind.SIDED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getInventory()?.also {
|
||||||
|
sendPacket(ReadItemStoragePacket(it, ipAddress, packet.source))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package net.shadowfacts.phycon.block.p2p
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.InventoryProvider
|
||||||
|
import net.minecraft.block.Material
|
||||||
|
import net.minecraft.inventory.SidedInventory
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.util.shape.VoxelShape
|
||||||
|
import net.minecraft.world.WorldAccess
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class P2PReceiverBlock: FaceDeviceBlock<P2PReceiverBlockEntity>(
|
||||||
|
Settings.of(Material.METAL)
|
||||||
|
.strength(1.5f)
|
||||||
|
.sounds(BlockSoundGroup.METAL)
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier(PhysicalConnectivity.MODID, "p2p_receiver")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val faceThickness = 4.0
|
||||||
|
override val faceShapes = mapOf(
|
||||||
|
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 4.0, 16.0),
|
||||||
|
Direction.UP to createCuboidShape(0.0, 12.0, 0.0, 16.0, 16.0, 16.0),
|
||||||
|
Direction.NORTH to createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 4.0),
|
||||||
|
Direction.SOUTH to createCuboidShape(0.0, 0.0, 12.0, 16.0, 16.0, 16.0),
|
||||||
|
Direction.WEST to createCuboidShape(0.0, 0.0, 0.0, 4.0, 16.0, 16.0),
|
||||||
|
Direction.EAST to createCuboidShape(12.0, 0.0, 0.0, 16.0, 16.0, 16.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = P2PReceiverBlockEntity(pos, state)
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
package net.shadowfacts.phycon.block.p2p
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
|
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
||||||
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
import net.shadowfacts.phycon.packet.*
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class P2PReceiverBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.P2P_RECEIVER, pos, state),
|
||||||
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
|
enum class Status {
|
||||||
|
OK,
|
||||||
|
NO_TARGET,
|
||||||
|
WAITING_FOR_RESPONSE;
|
||||||
|
|
||||||
|
val displayName: Text
|
||||||
|
get() = when (this) {
|
||||||
|
OK -> TranslatableText("gui.phycon.p2p_receiver.status.ok")
|
||||||
|
NO_TARGET -> TranslatableText("gui.phycon.p2p_receiver.status.no_target")
|
||||||
|
WAITING_FOR_RESPONSE -> TranslatableText("gui.phycon.p2p_receiver.status.waiting_for_response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val REQUEST_INVENTORY_TIMEOUT: Long = 100 // ticks
|
||||||
|
|
||||||
|
fun provideItemStorage(be: P2PReceiverBlockEntity, side: Direction): Storage<ItemVariant>? {
|
||||||
|
if (side == be.cachedState[FaceDeviceBlock.FACING]) {
|
||||||
|
return be.getTargetInventory()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var target: IPAddress? = null
|
||||||
|
var status = Status.NO_TARGET
|
||||||
|
private var requestTimestamp: Long = 0
|
||||||
|
|
||||||
|
var clientObserver: (() -> Unit)? = null
|
||||||
|
|
||||||
|
private var isFirstTick = true
|
||||||
|
private var targetInventory: WeakReference<Storage<ItemVariant>>? = null
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
|
when (packet) {
|
||||||
|
is PongPacket -> if (packet.source == target) status = Status.OK
|
||||||
|
is ReadItemStoragePacket -> targetInventory = WeakReference(packet.inventory)
|
||||||
|
is DeviceRemovedPacket -> if (packet.source == target) targetInventory = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleNetworkSplit() {
|
||||||
|
super.handleNetworkSplit()
|
||||||
|
targetInventory = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
|
|
||||||
|
if (isFirstTick) {
|
||||||
|
isFirstTick = false
|
||||||
|
updateStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTargetInventory(): Storage<ItemVariant>? {
|
||||||
|
if (target == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (targetInventory?.get() == null && (counter - requestTimestamp) >= REQUEST_INVENTORY_TIMEOUT) {
|
||||||
|
status = Status.WAITING_FOR_RESPONSE
|
||||||
|
requestTimestamp = counter
|
||||||
|
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.SIDED, ipAddress, target!!))
|
||||||
|
}
|
||||||
|
return targetInventory?.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStatus() {
|
||||||
|
if (world?.isClient != false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert(!world!!.isClient)
|
||||||
|
if (target == null) {
|
||||||
|
status = Status.NO_TARGET
|
||||||
|
} else {
|
||||||
|
status = Status.WAITING_FOR_RESPONSE
|
||||||
|
sendPacket(PingPacket(ipAddress, target!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
markUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
|
super.toCommonTag(tag)
|
||||||
|
writeDeviceConfiguration(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
|
super.fromCommonTag(tag)
|
||||||
|
loadDeviceConfiguration(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toClientTag(tag: NbtCompound): NbtCompound {
|
||||||
|
tag.putInt("Status", status.ordinal)
|
||||||
|
return super.toClientTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromClientTag(tag: NbtCompound) {
|
||||||
|
super.fromClientTag(tag)
|
||||||
|
status = Status.values()[tag.getInt("Status")]
|
||||||
|
clientObserver?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
|
target?.address?.let { tag.putInt("Target", it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
|
target = if (tag.contains("Target")) {
|
||||||
|
IPAddress(tag.getInt("Target"))
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -44,7 +44,7 @@ class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(
|
||||||
builder.add(POWERED)
|
builder.add(POWERED)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = RedstoneControllerBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = RedstoneControllerBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
val state = super.getPlacementState(context)
|
val state = super.getPlacementState(context)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package net.shadowfacts.phycon.block.redstone_controller
|
package net.shadowfacts.phycon.block.redstone_controller
|
||||||
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
@ -12,7 +14,7 @@ import net.shadowfacts.phycon.util.RedstoneMode
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER),
|
class RedstoneControllerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER, pos, state),
|
||||||
ClientConfigurableDevice {
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
var managedDevices = Array<IPAddress?>(5) { null }
|
var managedDevices = Array<IPAddress?>(5) { null }
|
||||||
|
@ -53,22 +55,22 @@ class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
loadDeviceConfiguration(tag)
|
loadDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
tag.putIntArray("ManagedDevices", managedDevices.mapNotNull { it?.address })
|
tag.putIntArray("ManagedDevices", managedDevices.mapNotNull { it?.address })
|
||||||
tag.putString("RedstoneMode", redstoneMode.name)
|
tag.putString("RedstoneMode", redstoneMode.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
val addresses = tag.getIntArray("ManagedDevices")
|
val addresses = tag.getIntArray("ManagedDevices")
|
||||||
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
|
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
|
||||||
redstoneMode = RedstoneMode.valueOf(tag.getString("RedstoneMode"))
|
redstoneMode = RedstoneMode.valueOf(tag.getString("RedstoneMode"))
|
||||||
|
|
|
@ -45,7 +45,7 @@ class RedstoneEmitterBlock: FaceDeviceBlock<RedstoneEmitterBlockEntity>(
|
||||||
Direction.EAST to createCuboidShape(13.0, 0.0, 0.0, 16.0, 16.0, 16.0)
|
Direction.EAST to createCuboidShape(13.0, 0.0, 0.0, 16.0, 16.0, 16.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = RedstoneEmitterBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = RedstoneEmitterBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun emitsRedstonePower(state: BlockState): Boolean {
|
override fun emitsRedstonePower(state: BlockState): Boolean {
|
||||||
return true
|
return true
|
||||||
|
@ -67,7 +67,7 @@ class RedstoneEmitterBlock: FaceDeviceBlock<RedstoneEmitterBlockEntity>(
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
val be = getBlockEntity(world, pos)!!
|
val be = getBlockEntity(world, pos)!!
|
||||||
|
|
||||||
be.sync()
|
be.markUpdate()
|
||||||
|
|
||||||
val factory = object: ExtendedScreenHandlerFactory {
|
val factory = object: ExtendedScreenHandlerFactory {
|
||||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
package net.shadowfacts.phycon.block.redstone_emitter
|
package net.shadowfacts.phycon.block.redstone_emitter
|
||||||
|
|
||||||
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.text.TranslatableText
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.DeviceRemovedPacket
|
import net.shadowfacts.phycon.packet.DeviceRemovedPacket
|
||||||
import net.shadowfacts.phycon.packet.ReadInventoryPacket
|
import net.shadowfacts.phycon.packet.ReadGroupedInventoryPacket
|
||||||
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.util.GhostInv
|
import net.shadowfacts.phycon.util.GhostInv
|
||||||
|
@ -19,7 +21,7 @@ import kotlin.math.round
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER),
|
class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER, pos, state),
|
||||||
ClientConfigurableDevice,
|
ClientConfigurableDevice,
|
||||||
GhostInv {
|
GhostInv {
|
||||||
|
|
||||||
|
@ -40,12 +42,12 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ReadInventoryPacket -> handleReadInventory(packet)
|
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
|
||||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadInventory(packet: ReadInventoryPacket) {
|
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
|
||||||
inventoryCache[packet.source] = packet.inventory
|
inventoryCache[packet.source] = packet.inventory
|
||||||
recalculateRedstone()
|
recalculateRedstone()
|
||||||
}
|
}
|
||||||
|
@ -68,7 +70,7 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateInventories() {
|
private fun updateInventories() {
|
||||||
sendPacket(RequestInventoryPacket(ipAddress))
|
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun recalculateRedstone() {
|
private fun recalculateRedstone() {
|
||||||
|
@ -100,26 +102,26 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
|
||||||
world!!.updateNeighborsAlways(pos.offset(cachedState[FaceDeviceBlock.FACING]), cachedState.block)
|
world!!.updateNeighborsAlways(pos.offset(cachedState[FaceDeviceBlock.FACING]), cachedState.block)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
tag.putInt("CachedEmittedPower", cachedEmittedPower)
|
tag.putInt("CachedEmittedPower", cachedEmittedPower)
|
||||||
tag.put("StackToMonitor", stackToMonitor.toTag(CompoundTag()))
|
tag.put("StackToMonitor", stackToMonitor.writeNbt(NbtCompound()))
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
cachedEmittedPower = tag.getInt("CachedEmittedPower")
|
cachedEmittedPower = tag.getInt("CachedEmittedPower")
|
||||||
stackToMonitor = ItemStack.fromTag(tag.getCompound("StackToMonitor"))
|
stackToMonitor = ItemStack.fromNbt(tag.getCompound("StackToMonitor"))
|
||||||
loadDeviceConfiguration(tag)
|
loadDeviceConfiguration(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: NbtCompound) {
|
||||||
tag.putInt("MaxAmount", maxAmount)
|
tag.putInt("MaxAmount", maxAmount)
|
||||||
tag.putString("Mode", mode.name)
|
tag.putString("Mode", mode.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: NbtCompound) {
|
||||||
maxAmount = tag.getInt("MaxAmount")
|
maxAmount = tag.getInt("MaxAmount")
|
||||||
mode = Mode.valueOf(tag.getString("Mode"))
|
mode = Mode.valueOf(tag.getString("Mode"))
|
||||||
}
|
}
|
||||||
|
@ -127,7 +129,7 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
ANALOG, DIGITAL;
|
ANALOG, DIGITAL;
|
||||||
|
|
||||||
val friendlyName = TranslatableText("gui.phycon.redstone_emitter_mode.${name.toLowerCase()}")
|
val friendlyName = TranslatableText("gui.phycon.redstone_emitter_mode.${name.lowercase()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package net.shadowfacts.phycon.block.redstone_emitter
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.client.render.GameRenderer
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
@ -49,8 +50,8 @@ class RedstoneEmitterScreen(
|
||||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
super.drawBackground(matrixStack, delta, mouseX, mouseY)
|
super.drawBackground(matrixStack, delta, mouseX, mouseY)
|
||||||
|
|
||||||
RenderSystem.color4f(1f, 1f, 1f, 1f)
|
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||||
client!!.textureManager.bindTexture(BACKGROUND)
|
RenderSystem.setShaderTexture(0, BACKGROUND)
|
||||||
val x = (width - backgroundWidth) / 2
|
val x = (width - backgroundWidth) / 2
|
||||||
val y = (height - backgroundHeight) / 2
|
val y = (height - backgroundHeight) / 2
|
||||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||||
|
|
|
@ -55,16 +55,16 @@ class RedstoneEmitterScreenHandler(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSlotClick(slotId: Int, clickData: Int, slotActionType: SlotActionType, player: PlayerEntity): ItemStack {
|
override fun onSlotClick(slotId: Int, clickData: Int, slotActionType: SlotActionType, player: PlayerEntity) {
|
||||||
// fake slot
|
// fake slot
|
||||||
if (slotId == 0) {
|
if (slotId == 0) {
|
||||||
if (player.inventory.cursorStack.isEmpty) {
|
if (cursorStack.isEmpty) {
|
||||||
emitter.stackToMonitor = ItemStack.EMPTY
|
emitter.stackToMonitor = ItemStack.EMPTY
|
||||||
} else {
|
} else {
|
||||||
emitter.stackToMonitor = player.inventory.cursorStack.copyWithCount(1)
|
emitter.stackToMonitor = cursorStack.copyWithCount(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onSlotClick(slotId, clickData, slotActionType, player)
|
super.onSlotClick(slotId, clickData, slotActionType, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||||
|
|
|
@ -3,42 +3,35 @@ package net.shadowfacts.phycon.block.terminal
|
||||||
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
import net.minecraft.block.BlockState
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
|
||||||
import net.minecraft.inventory.Inventory
|
import net.minecraft.inventory.Inventory
|
||||||
import net.minecraft.inventory.InventoryChangedListener
|
import net.minecraft.inventory.InventoryChangedListener
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.network.PacketByteBuf
|
|
||||||
import net.minecraft.screen.ScreenHandler
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
|
||||||
import net.minecraft.text.TranslatableText
|
|
||||||
import net.minecraft.util.ItemScatterer
|
import net.minecraft.util.ItemScatterer
|
||||||
import net.minecraft.util.Tickable
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
|
||||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.util.NetworkUtil
|
|
||||||
import net.shadowfacts.phycon.component.*
|
import net.shadowfacts.phycon.component.*
|
||||||
|
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.function.IntBinaryOperator
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBlockEntity(type),
|
abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): DeviceBlockEntity(type, pos, state),
|
||||||
InventoryChangedListener,
|
InventoryChangedListener,
|
||||||
BlockEntityClientSerializable,
|
|
||||||
Tickable,
|
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
NetworkStackDispatcher<AbstractTerminalBlockEntity.PendingInsertion> {
|
NetworkStackDispatcher<AbstractTerminalBlockEntity.PendingInsertion> {
|
||||||
|
|
||||||
|
@ -46,18 +39,19 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
// the locate/insertion timeouts are only 1 tick because that's long enough to hear from every device on the network
|
// the locate/insertion timeouts are only 1 tick because that's long enough to hear from every device on the network
|
||||||
// in a degraded state (when there's latency in the network), not handling interface priorities correctly is acceptable
|
// in a degraded state (when there's latency in the network), not handling interface priorities correctly is acceptable
|
||||||
val LOCATE_REQUEST_TIMEOUT: Long = 1 // ticks
|
val LOCATE_REQUEST_TIMEOUT: Long = 1 // ticks
|
||||||
val INSERTION_TIMEOUT: Long = 1
|
val INSERTION_TIMEOUT: Long = 1 // ticks
|
||||||
|
val REQUEST_INVENTORY_TIMEOUT: Long = 1 // ticks
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
protected val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||||
val internalBuffer = TerminalBufferInventory(18)
|
val internalBuffer = TerminalBufferInventory(18)
|
||||||
|
|
||||||
private val pendingRequests = LinkedList<StackLocateRequest>()
|
protected val pendingRequests = LinkedList<StackLocateRequest>()
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = INSERTION_TIMEOUT
|
override val dispatchStackTimeout = INSERTION_TIMEOUT
|
||||||
|
|
||||||
private var observers = 0
|
|
||||||
val cachedNetItems = ItemStackCollections.intMap()
|
val cachedNetItems = ItemStackCollections.intMap()
|
||||||
|
private var requestInventoryTimestamp: Long? = null
|
||||||
|
|
||||||
// todo: multiple players could have the terminal open simultaneously
|
// todo: multiple players could have the terminal open simultaneously
|
||||||
var netItemObserver: WeakReference<NetItemObserver>? = null
|
var netItemObserver: WeakReference<NetItemObserver>? = null
|
||||||
|
@ -76,9 +70,14 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleNetworkSplit() {
|
||||||
|
super.handleNetworkSplit()
|
||||||
|
inventoryCache.clear()
|
||||||
|
}
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ReadInventoryPacket -> handleReadInventory(packet)
|
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
|
||||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||||
is StackLocationPacket -> handleStackLocation(packet)
|
is StackLocationPacket -> handleStackLocation(packet)
|
||||||
is ItemStackPacket -> handleItemStack(packet)
|
is ItemStackPacket -> handleItemStack(packet)
|
||||||
|
@ -86,7 +85,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadInventory(packet: ReadInventoryPacket) {
|
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
|
||||||
inventoryCache[packet.source] = packet.inventory
|
inventoryCache[packet.source] = packet.inventory
|
||||||
updateAndSync()
|
updateAndSync()
|
||||||
}
|
}
|
||||||
|
@ -129,7 +128,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
protected fun updateAndSync() {
|
protected fun updateAndSync() {
|
||||||
updateNetItems()
|
updateNetItems()
|
||||||
// syncs the internal buffer to the client
|
// syncs the internal buffer to the client
|
||||||
sync()
|
markUpdate()
|
||||||
// syncs the open container (if any) to the client
|
// syncs the open container (if any) to the client
|
||||||
netItemObserver?.get()?.netItemsChanged()
|
netItemObserver?.get()?.netItemsChanged()
|
||||||
}
|
}
|
||||||
|
@ -139,7 +138,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
for (inventory in inventoryCache.values) {
|
for (inventory in inventoryCache.values) {
|
||||||
for (stack in inventory.storedStacks) {
|
for (stack in inventory.storedStacks) {
|
||||||
val amount = inventory.getAmount(stack)
|
val amount = inventory.getAmount(stack)
|
||||||
cachedNetItems.mergeInt(stack, amount) { a, b -> a + b }
|
cachedNetItems.mergeInt(stack, amount, IntBinaryOperator { a, b -> a + b })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,14 +171,26 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
if (!world!!.isClient) {
|
if (!world!!.isClient) {
|
||||||
finishPendingRequests()
|
finishPendingRequests()
|
||||||
finishTimedOutPendingInsertions()
|
finishTimedOutPendingInsertions()
|
||||||
|
|
||||||
|
if (counter % 20 == 0L) {
|
||||||
|
beginInsertions()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter % 20 == 0L && !world!!.isClient) {
|
if (requestInventoryTimestamp != null && (counter - requestInventoryTimestamp!!) >= REQUEST_INVENTORY_TIMEOUT) {
|
||||||
beginInsertions()
|
updateAndSync()
|
||||||
|
requestInventoryTimestamp = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun onActivate(player: PlayerEntity) {
|
open fun onActivate(player: PlayerEntity) {
|
||||||
|
if (!world!!.isClient) {
|
||||||
|
updateAndSync()
|
||||||
|
|
||||||
|
inventoryCache.clear()
|
||||||
|
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
|
||||||
|
requestInventoryTimestamp = counter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestItem(stack: ItemStack, amount: Int = stack.count) {
|
fun requestItem(stack: ItemStack, amount: Int = stack.count) {
|
||||||
|
@ -190,7 +201,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
sendPacket(LocateStackPacket(stack, ipAddress))
|
sendPacket(LocateStackPacket(stack, ipAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
protected open fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||||
pendingRequests.remove(request)
|
pendingRequests.remove(request)
|
||||||
|
|
||||||
val sortedResults = request.results.toMutableList()
|
val sortedResults = request.results.toMutableList()
|
||||||
|
@ -220,13 +231,13 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
// as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets
|
// as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets
|
||||||
updateAndSync()
|
updateAndSync()
|
||||||
|
|
||||||
return remaining
|
// don't start a second insertion, since remaining will be dispatched at the next beginInsertions
|
||||||
|
return ItemStack.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInventoryChanged(inv: Inventory) {
|
override fun onInventoryChanged(inv: Inventory) {
|
||||||
if (inv == internalBuffer && world != null && !world!!.isClient) {
|
if (inv == internalBuffer && world != null && !world!!.isClient) {
|
||||||
markDirty()
|
markUpdate()
|
||||||
sync()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,12 +245,12 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
ItemScatterer.spawn(world, pos, internalBuffer)
|
ItemScatterer.spawn(world, pos, internalBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
tag.put("InternalBuffer", internalBuffer.toTag())
|
tag.put("InternalBuffer", internalBuffer.toTag())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromCommonTag(tag: CompoundTag) {
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
super.fromCommonTag(tag)
|
super.fromCommonTag(tag)
|
||||||
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||||
}
|
}
|
||||||
|
@ -252,19 +263,20 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
|
||||||
var bufferSlot by Delegates.notNull<Int>()
|
var bufferSlot by Delegates.notNull<Int>()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class StackLocateRequest(
|
open class StackLocateRequest(
|
||||||
val stack: ItemStack,
|
val stack: ItemStack,
|
||||||
val amount: Int,
|
val amount: Int,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
var results: MutableSet<Pair<Int, NetworkStackProvider>> = mutableSetOf()
|
|
||||||
) {
|
) {
|
||||||
|
var results: MutableSet<Pair<Int, NetworkStackProvider>> = mutableSetOf()
|
||||||
|
|
||||||
val totalResultAmount: Int
|
val totalResultAmount: Int
|
||||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||||
|
|
||||||
fun isFinishable(currentTimestamp: Long): Boolean {
|
fun isFinishable(currentTimestamp: Long): Boolean {
|
||||||
// we can't check totalResultAmount >= amount because we need to hear back from all network stack providers to
|
// we can't check totalResultAmount >= amount because we need to hear back from all network stack providers to
|
||||||
// correctly sort by priority
|
// correctly sort by priority
|
||||||
return currentTimestamp - timestamp >= AbstractTerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
return currentTimestamp - timestamp >= LOCATE_REQUEST_TIMEOUT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.mojang.blaze3d.systems.RenderSystem
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.DrawableHelper
|
import net.minecraft.client.gui.DrawableHelper
|
||||||
import net.minecraft.client.gui.Element
|
import net.minecraft.client.gui.Element
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget
|
import net.minecraft.client.render.GameRenderer
|
||||||
import net.minecraft.client.render.Tessellator
|
import net.minecraft.client.render.Tessellator
|
||||||
import net.minecraft.client.render.VertexConsumerProvider
|
import net.minecraft.client.render.VertexConsumerProvider
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
|
@ -12,7 +12,6 @@ import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.screen.slot.Slot
|
import net.minecraft.screen.slot.Slot
|
||||||
import net.minecraft.screen.slot.SlotActionType
|
import net.minecraft.screen.slot.SlotActionType
|
||||||
import net.minecraft.text.LiteralText
|
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.shadowfacts.cacao.CacaoHandledScreen
|
import net.shadowfacts.cacao.CacaoHandledScreen
|
||||||
|
@ -22,7 +21,6 @@ import net.shadowfacts.phycon.networking.C2STerminalRequestItem
|
||||||
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
|
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.util.LinkedList
|
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@ -37,12 +35,13 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
|
||||||
val terminalBackgroundHeight: Int,
|
val terminalBackgroundHeight: Int,
|
||||||
): CacaoHandledScreen<T>(handler, playerInv, title) {
|
): CacaoHandledScreen<T>(handler, playerInv, title) {
|
||||||
|
|
||||||
companion object {
|
interface SearchQueryListener {
|
||||||
private val clickHandlers = LinkedList<AbstractTerminalScreen<*, *>.(Double, Double, Int) -> Boolean?>()
|
fun terminalSearchQueryChanged(newValue: String)
|
||||||
|
fun requestTerminalSearchFieldUpdate(): String?
|
||||||
fun registerClickHandler(handler: AbstractTerminalScreen<*, *>.(Double, Double, Int) -> Boolean?) {
|
|
||||||
clickHandlers.add(handler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var searchQueryListener: SearchQueryListener? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract val backgroundTexture: Identifier
|
abstract val backgroundTexture: Identifier
|
||||||
|
@ -50,7 +49,15 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
|
||||||
val terminalVC: AbstractTerminalViewController<*, *, *>
|
val terminalVC: AbstractTerminalViewController<*, *, *>
|
||||||
var amountVC: TerminalRequestAmountViewController? = null
|
var amountVC: TerminalRequestAmountViewController? = null
|
||||||
|
|
||||||
|
private var prevSearchQuery = ""
|
||||||
var searchQuery = ""
|
var searchQuery = ""
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
if (prevSearchQuery != value) {
|
||||||
|
searchQueryListener?.terminalSearchQueryChanged(value)
|
||||||
|
}
|
||||||
|
prevSearchQuery = value
|
||||||
|
}
|
||||||
var scrollPosition = 0.0
|
var scrollPosition = 0.0
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -100,7 +107,7 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
|
||||||
private val DECIMAL_FORMAT = DecimalFormat("#.#").apply { roundingMode = RoundingMode.HALF_UP }
|
private val DECIMAL_FORMAT = DecimalFormat("#.#").apply { roundingMode = RoundingMode.HALF_UP }
|
||||||
private val FORMAT = DecimalFormat("##").apply { roundingMode = RoundingMode.HALF_UP }
|
private val FORMAT = DecimalFormat("##").apply { roundingMode = RoundingMode.HALF_UP }
|
||||||
|
|
||||||
fun drawNetworkSlotAmount(stack: ItemStack, x: Int, y: Int, slot: Slot, matrixStack: MatrixStack) {
|
fun drawNetworkSlotAmount(stack: ItemStack, x: Int, y: Int) {
|
||||||
val amount = stack.count
|
val amount = stack.count
|
||||||
val s = when {
|
val s = when {
|
||||||
amount < 1_000 -> amount.toString()
|
amount < 1_000 -> amount.toString()
|
||||||
|
@ -121,16 +128,17 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
|
||||||
// empty string for label because vanilla renders the count behind the damage bar
|
// empty string for label because vanilla renders the count behind the damage bar
|
||||||
itemRenderer.renderGuiItemOverlay(textRenderer, stack, x, y, "")
|
itemRenderer.renderGuiItemOverlay(textRenderer, stack, x, y, "")
|
||||||
|
|
||||||
matrixStack.push()
|
// ItemRenderer.renderGuiItemOverlay creates a new MatrixStack specifically for drawing the overlay
|
||||||
|
val matrixStack = MatrixStack()
|
||||||
matrixStack.translate(x.toDouble(), y.toDouble(), itemRenderer.zOffset + 200.0)
|
matrixStack.translate(x.toDouble(), y.toDouble(), itemRenderer.zOffset + 200.0)
|
||||||
val scale = 2 / 3f
|
val scale = 2 / 3f
|
||||||
matrixStack.scale(scale, scale, 1.0f)
|
matrixStack.scale(scale, scale, 1.0f)
|
||||||
val immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().buffer)
|
val immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().buffer)
|
||||||
val textX = (1 / scale * 18) - textRenderer.getWidth(s).toFloat() - 3
|
val textX = (1 / scale * 18) - textRenderer.getWidth(s).toFloat() - 3
|
||||||
val textY = (1 / scale * 18) - 11
|
val textY = (1 / scale * 18) - 11
|
||||||
textRenderer.draw(s, textX, textY, 0xffffff, true, matrixStack.peek().model, immediate, false, 0, 0xF000F0)
|
textRenderer.draw(s, textX, textY, 0xffffff, true, matrixStack.peek().positionMatrix, immediate, false, 0, 0xF000F0)
|
||||||
|
RenderSystem.enableDepthTest()
|
||||||
immediate.draw()
|
immediate.draw()
|
||||||
matrixStack.pop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
|
@ -140,38 +148,35 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun drawBackgroundTexture(matrixStack: MatrixStack) {
|
open fun drawBackgroundTexture(matrixStack: MatrixStack) {
|
||||||
RenderSystem.color4f(1f, 1f, 1f, 1f)
|
RenderSystem.setShader(GameRenderer::getPositionTexColorShader)
|
||||||
client!!.textureManager.bindTexture(backgroundTexture)
|
RenderSystem.setShaderTexture(0, backgroundTexture)
|
||||||
|
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||||
val x = (width - backgroundWidth) / 2
|
val x = (width - backgroundWidth) / 2
|
||||||
val y = (height - backgroundHeight) / 2
|
val y = (height - backgroundHeight) / 2
|
||||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun handledScreenTick() {
|
||||||
super.tick()
|
super.handledScreenTick()
|
||||||
|
|
||||||
if (amountVC != null) {
|
if (amountVC != null) {
|
||||||
amountVC!!.field.tick()
|
amountVC!!.field.tick()
|
||||||
} else {
|
} else {
|
||||||
terminalVC.searchField.tick()
|
terminalVC.searchField.tick()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
val newSearchQuery = searchQueryListener?.requestTerminalSearchFieldUpdate()
|
||||||
for (handler in clickHandlers) {
|
if (newSearchQuery != null && searchQuery != newSearchQuery) {
|
||||||
val res = handler(mouseX, mouseY, button)
|
searchQuery = newSearchQuery
|
||||||
if (res != null) {
|
terminalVC.searchField.text = newSearchQuery
|
||||||
return res
|
requestUpdatedItems()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.mouseClicked(mouseX, mouseY, button)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
|
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
|
||||||
super.onMouseClick(slot, invSlot, clickData, type)
|
super.onMouseClick(slot, invSlot, clickData, type)
|
||||||
|
|
||||||
if (slot != null && !slot.stack.isEmpty && handler.isNetworkSlot(slot.id)) {
|
if (slot != null && !slot.stack.isEmpty && handler.isNetworkSlot(slot.id) && handler.cursorStack.isEmpty) {
|
||||||
val stack = slot.stack
|
val stack = slot.stack
|
||||||
|
|
||||||
if (type == SlotActionType.QUICK_MOVE) {
|
if (type == SlotActionType.QUICK_MOVE) {
|
||||||
|
@ -188,12 +193,11 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val fakeFocusedElement = TextFieldWidget(textRenderer, 0, 0, 0, 0, LiteralText(""))
|
override fun setFocused(element: Element?) {
|
||||||
override fun getFocused(): Element? {
|
super.setFocused(element)
|
||||||
return if (windows.last().firstResponder != null) {
|
// so that when something else (e.g., REI) steals focus and calls setFocused(null) on us, any first responder resigns
|
||||||
fakeFocusedElement
|
if (element == null) {
|
||||||
} else {
|
windows.last().firstResponder?.resignFirstResponder()
|
||||||
null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
|
||||||
var itemsForDisplay = listOf<ItemStack>()
|
var itemsForDisplay = listOf<ItemStack>()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
open val xOffset: Int = 0
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (!terminal.world!!.isClient) {
|
if (!terminal.world!!.isClient) {
|
||||||
assert(terminal.netItemObserver?.get() === null)
|
assert(terminal.netItemObserver?.get() === null)
|
||||||
|
@ -63,29 +65,31 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
|
||||||
// intentionally don't call netItemsChanged immediately, we need to wait for the client to send us its settings
|
// intentionally don't call netItemsChanged immediately, we need to wait for the client to send us its settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val xOffset = xOffset
|
||||||
|
|
||||||
// network
|
// network
|
||||||
for (y in 0 until 6) {
|
for (y in 0 until 6) {
|
||||||
for (x in 0 until 9) {
|
for (x in 0 until 9) {
|
||||||
addSlot(TerminalFakeSlot(fakeInv, y * 9 + x, 66 + x * 18, 18 + y * 18))
|
addSlot(TerminalFakeSlot(fakeInv, y * 9 + x, xOffset + 66 + x * 18, 18 + y * 18))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal buffer
|
// internal buffer
|
||||||
for (y in 0 until 6) {
|
for (y in 0 until 6) {
|
||||||
for (x in 0 until 3) {
|
for (x in 0 until 3) {
|
||||||
addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18))
|
addSlot(Slot(terminal.internalBuffer, y * 3 + x, xOffset + 8 + x * 18, 18 + y * 18))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// player inv
|
// player inv
|
||||||
for (y in 0 until 3) {
|
for (y in 0 until 3) {
|
||||||
for (x in 0 until 9) {
|
for (x in 0 until 9) {
|
||||||
addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18))
|
addSlot(Slot(playerInv, x + y * 9 + 9, xOffset + 66 + x * 18, 140 + y * 18))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// hotbar
|
// hotbar
|
||||||
for (x in 0 until 9) {
|
for (x in 0 until 9) {
|
||||||
addSlot(Slot(playerInv, x, 66 + x * 18, 198))
|
addSlot(Slot(playerInv, x, xOffset + 66 + x * 18, 198))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,16 +170,16 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
|
||||||
terminal.netItemObserver = null
|
terminal.netItemObserver = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
|
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity) {
|
||||||
if (isBufferSlot(slotId)) {
|
if (isBufferSlot(slotId)) {
|
||||||
// todo: why does this think it's quick_craft sometimes?
|
// todo: why does this think it's quick_craft sometimes?
|
||||||
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) {
|
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !cursorStack.isEmpty) {
|
||||||
// placing cursor stack into buffer
|
// placing cursor stack into buffer
|
||||||
val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
|
val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
|
||||||
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onSlotClick(slotId, clickData, actionType, player)
|
super.onSlotClick(slotId, clickData, actionType, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||||
|
@ -201,7 +205,7 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
|
||||||
} else if (isPlayerSlot(slotId)) {
|
} else if (isPlayerSlot(slotId)) {
|
||||||
val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
|
val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
|
||||||
slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
|
slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
|
||||||
if (slot.stack.isEmpty) {
|
if (slotsInsertedInto.isEmpty()) {
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +227,7 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
|
||||||
|
|
||||||
slot.markDirty()
|
slot.markDirty()
|
||||||
slotsInsertedInto.add(index)
|
slotsInsertedInto.add(index)
|
||||||
} else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) {
|
} else if (ItemStack.canCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) {
|
||||||
val maxToMove = slotStack.maxCount - slotStack.count
|
val maxToMove = slotStack.maxCount - slotStack.count
|
||||||
val toMove = min(maxToMove, stack.count)
|
val toMove = min(maxToMove, stack.count)
|
||||||
slotStack.increment(toMove)
|
slotStack.increment(toMove)
|
||||||
|
|
|
@ -64,7 +64,7 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
|
||||||
|
|
||||||
buffer = view.addLayoutGuide()
|
buffer = view.addLayoutGuide()
|
||||||
view.solver.dsl {
|
view.solver.dsl {
|
||||||
buffer.leftAnchor equalTo (pane.leftAnchor + 7)
|
buffer.leftAnchor equalTo (pane.leftAnchor + 7 + handler.xOffset)
|
||||||
buffer.topAnchor equalTo (pane.topAnchor + 17)
|
buffer.topAnchor equalTo (pane.topAnchor + 17)
|
||||||
buffer.widthAnchor equalTo (18 * 3)
|
buffer.widthAnchor equalTo (18 * 3)
|
||||||
buffer.heightAnchor equalTo (18 * 6)
|
buffer.heightAnchor equalTo (18 * 6)
|
||||||
|
@ -72,7 +72,7 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
|
||||||
|
|
||||||
network = view.addLayoutGuide()
|
network = view.addLayoutGuide()
|
||||||
view.solver.dsl {
|
view.solver.dsl {
|
||||||
network.leftAnchor equalTo (pane.leftAnchor + 65)
|
network.leftAnchor equalTo (pane.leftAnchor + 65 + handler.xOffset)
|
||||||
network.topAnchor equalTo buffer.topAnchor
|
network.topAnchor equalTo buffer.topAnchor
|
||||||
network.widthAnchor equalTo (18 * 9)
|
network.widthAnchor equalTo (18 * 9)
|
||||||
network.heightAnchor equalTo (18 * 6)
|
network.heightAnchor equalTo (18 * 6)
|
||||||
|
@ -100,13 +100,12 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
|
||||||
handler = ::searchFieldChanged
|
handler = ::searchFieldChanged
|
||||||
drawBackground = false
|
drawBackground = false
|
||||||
}
|
}
|
||||||
searchField.becomeFirstResponder()
|
|
||||||
|
|
||||||
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
|
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
|
||||||
|
|
||||||
val settingsStack = view.addSubview(StackView(Axis.VERTICAL, spacing = 2.0))
|
val settingsStack = view.addSubview(StackView(Axis.VERTICAL, spacing = 2.0))
|
||||||
settingsView = settingsStack
|
settingsView = settingsStack
|
||||||
TerminalSettings.allKeys.forEach { key ->
|
TerminalSettings.allKeys.sortedByDescending { it.priority }.forEach { key ->
|
||||||
val button = SettingButton(key)
|
val button = SettingButton(key)
|
||||||
button.handler = { settingsChanged() }
|
button.handler = { settingsChanged() }
|
||||||
settingsStack.addArrangedSubview(button)
|
settingsStack.addArrangedSubview(button)
|
||||||
|
@ -122,12 +121,12 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
|
||||||
playerInvLabel.leftAnchor equalTo playerInv.leftAnchor
|
playerInvLabel.leftAnchor equalTo playerInv.leftAnchor
|
||||||
playerInvLabel.topAnchor equalTo (pane.topAnchor + 128)
|
playerInvLabel.topAnchor equalTo (pane.topAnchor + 128)
|
||||||
|
|
||||||
searchField.leftAnchor equalTo (pane.leftAnchor + 138)
|
searchField.leftAnchor equalTo (pane.leftAnchor + 138 + handler.xOffset)
|
||||||
searchField.topAnchor equalTo (pane.topAnchor + 5)
|
searchField.topAnchor equalTo (pane.topAnchor + 5)
|
||||||
searchField.widthAnchor equalTo 80
|
searchField.widthAnchor equalTo 80
|
||||||
searchField.heightAnchor equalTo 9
|
searchField.heightAnchor equalTo 9
|
||||||
|
|
||||||
scrollTrack.leftAnchor equalTo (pane.leftAnchor + 232)
|
scrollTrack.leftAnchor equalTo (pane.leftAnchor + 232 + handler.xOffset)
|
||||||
scrollTrack.topAnchor equalTo (network.topAnchor + 1)
|
scrollTrack.topAnchor equalTo (network.topAnchor + 1)
|
||||||
scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1)
|
scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1)
|
||||||
scrollTrack.widthAnchor equalTo 12
|
scrollTrack.widthAnchor equalTo 12
|
||||||
|
@ -137,6 +136,12 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun viewWillAppear() {
|
||||||
|
super.viewWillAppear()
|
||||||
|
|
||||||
|
searchField.becomeFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
private fun searchFieldChanged(field: TextField) {
|
private fun searchFieldChanged(field: TextField) {
|
||||||
screen.searchQuery = field.text
|
screen.searchQuery = field.text
|
||||||
screen.requestUpdatedItems()
|
screen.requestUpdatedItems()
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.world.BlockView
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class CraftingTerminalBlock: AbstractTerminalBlock<CraftingTerminalBlockEntity>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier(PhysicalConnectivity.MODID, "crafting_terminal")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = CraftingTerminalBlockEntity(pos, state)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||||
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.inventory.SimpleInventory
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.network.PacketByteBuf
|
||||||
|
import net.minecraft.screen.ScreenHandler
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
|
import net.shadowfacts.phycon.packet.LocateStackPacket
|
||||||
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
|
import net.shadowfacts.phycon.util.fromTag
|
||||||
|
import net.shadowfacts.phycon.util.toTag
|
||||||
|
import java.util.LinkedList
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlockEntity(PhyBlockEntities.CRAFTING_TERMINAL, pos, state) {
|
||||||
|
|
||||||
|
val craftingInv = SimpleInventory(9)
|
||||||
|
|
||||||
|
private val completedCraftingStackRequests = LinkedList<CraftingStackLocateRequest>()
|
||||||
|
|
||||||
|
override fun onActivate(player: PlayerEntity) {
|
||||||
|
super.onActivate(player)
|
||||||
|
|
||||||
|
if (!world!!.isClient) {
|
||||||
|
val factory = object: ExtendedScreenHandlerFactory {
|
||||||
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
||||||
|
return CraftingTerminalScreenHandler(syncId, playerInv, this@CraftingTerminalBlockEntity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDisplayName() = TranslatableText("block.phycon.crafting_terminal")
|
||||||
|
|
||||||
|
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
||||||
|
buf.writeBlockPos(this@CraftingTerminalBlockEntity.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.openHandledScreen(factory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestItemsForCrafting(maxAmount: Int) {
|
||||||
|
val amounts = ItemStackCollections.map<IntArray>()
|
||||||
|
|
||||||
|
for (i in 0 until craftingInv.size()) {
|
||||||
|
val craftingInvStack = craftingInv.getStack(i)
|
||||||
|
if (craftingInvStack.isEmpty) continue
|
||||||
|
if (craftingInvStack.count >= craftingInvStack.maxCount) continue
|
||||||
|
|
||||||
|
if (craftingInvStack !in amounts) amounts[craftingInvStack] = IntArray(9) { 0 }
|
||||||
|
amounts[craftingInvStack]!![i] = min(maxAmount, craftingInvStack.maxCount - craftingInvStack.count)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((stack, amountPerSlot) in amounts) {
|
||||||
|
val total = amountPerSlot.sum()
|
||||||
|
val request = CraftingStackLocateRequest(stack, total, counter, amountPerSlot)
|
||||||
|
pendingRequests.add(request)
|
||||||
|
sendPacket(LocateStackPacket(stack, ipAddress))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||||
|
if (request is CraftingStackLocateRequest) {
|
||||||
|
completedCraftingStackRequests.add(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
super.stackLocateRequestCompleted(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||||
|
val craftingReq = completedCraftingStackRequests.find { ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) }
|
||||||
|
if (craftingReq != null) {
|
||||||
|
var remaining = packet.stack.copy()
|
||||||
|
|
||||||
|
for (i in 0 until craftingInv.size()) {
|
||||||
|
val currentStack = craftingInv.getStack(i)
|
||||||
|
if (currentStack.count >= currentStack.maxCount) continue
|
||||||
|
if (!ItemStackUtil.areEqualIgnoreAmounts(currentStack, remaining)) continue
|
||||||
|
|
||||||
|
val toInsert = minOf(remaining.count, currentStack.maxCount - currentStack.count, craftingReq.amountPerSlot[i])
|
||||||
|
currentStack.count += toInsert
|
||||||
|
remaining.count -= toInsert
|
||||||
|
craftingReq.amountPerSlot[i] -= toInsert
|
||||||
|
craftingReq.received += toInsert
|
||||||
|
|
||||||
|
if (remaining.isEmpty) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (craftingReq.amountPerSlot.sum() == 0 || craftingReq.received >= craftingReq.totalResultAmount) {
|
||||||
|
completedCraftingStackRequests.remove(craftingReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!remaining.isEmpty) {
|
||||||
|
remaining = internalBuffer.insert(remaining, TerminalBufferInventory.Mode.FROM_NETWORK)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAndSync()
|
||||||
|
|
||||||
|
return remaining
|
||||||
|
} else {
|
||||||
|
return super.doHandleItemStack(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toCommonTag(tag: NbtCompound) {
|
||||||
|
super.toCommonTag(tag)
|
||||||
|
tag.put("CraftingInv", craftingInv.toTag())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromCommonTag(tag: NbtCompound) {
|
||||||
|
super.fromCommonTag(tag)
|
||||||
|
craftingInv.fromTag(tag.getList("CraftingInv", 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
class CraftingStackLocateRequest(
|
||||||
|
stack: ItemStack,
|
||||||
|
amount: Int,
|
||||||
|
timestamp: Long,
|
||||||
|
val amountPerSlot: IntArray,
|
||||||
|
): StackLocateRequest(stack, amount, timestamp) {
|
||||||
|
var received: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
|
import net.minecraft.client.render.GameRenderer
|
||||||
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class CraftingTerminalScreen(
|
||||||
|
handler: CraftingTerminalScreenHandler,
|
||||||
|
playerInv: PlayerInventory,
|
||||||
|
title: Text,
|
||||||
|
): AbstractTerminalScreen<CraftingTerminalBlockEntity, CraftingTerminalScreenHandler>(
|
||||||
|
handler,
|
||||||
|
playerInv,
|
||||||
|
title,
|
||||||
|
259,
|
||||||
|
252,
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val BACKGROUND_1 = Identifier(PhysicalConnectivity.MODID, "textures/gui/crafting_terminal_1.png")
|
||||||
|
private val BACKGROUND_2 = Identifier(PhysicalConnectivity.MODID, "textures/gui/crafting_terminal_2.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val backgroundTexture = BACKGROUND_1
|
||||||
|
|
||||||
|
override fun createViewController(): AbstractTerminalViewController<*, *, *> {
|
||||||
|
return CraftingTerminalViewController(this, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawBackgroundTexture(matrixStack: MatrixStack) {
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||||
|
RenderSystem.setShaderTexture(0, BACKGROUND_1)
|
||||||
|
val x = (width - backgroundWidth) / 2
|
||||||
|
val y = (height - backgroundHeight) / 2
|
||||||
|
drawTexture(matrixStack, x, y, 0, 0, 256, 252)
|
||||||
|
|
||||||
|
RenderSystem.setShaderTexture(0, BACKGROUND_2)
|
||||||
|
drawTexture(matrixStack, x + 256, y, 0, 0, 3, 252)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.inventory.CraftingInventory
|
||||||
|
import net.minecraft.inventory.CraftingResultInventory
|
||||||
|
import net.minecraft.inventory.Inventory
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.network.PacketByteBuf
|
||||||
|
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket
|
||||||
|
import net.minecraft.recipe.RecipeMatcher
|
||||||
|
import net.minecraft.recipe.RecipeType
|
||||||
|
import net.minecraft.screen.slot.CraftingResultSlot
|
||||||
|
import net.minecraft.screen.slot.Slot
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
|
import net.shadowfacts.phycon.init.PhyBlocks
|
||||||
|
import net.shadowfacts.phycon.init.PhyScreens
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class CraftingTerminalScreenHandler(
|
||||||
|
syncId: Int,
|
||||||
|
playerInv: PlayerInventory,
|
||||||
|
terminal: CraftingTerminalBlockEntity,
|
||||||
|
): AbstractTerminalScreenHandler<CraftingTerminalBlockEntity>(PhyScreens.CRAFTING_TERMINAL, syncId, playerInv, terminal) {
|
||||||
|
|
||||||
|
val craftingInv = CraftingInv(this)
|
||||||
|
val result = CraftingResultInventory()
|
||||||
|
val resultSlot: CraftingResultSlot
|
||||||
|
|
||||||
|
val craftingSlotsStart: Int
|
||||||
|
val craftingSlotsEnd: Int
|
||||||
|
get() = craftingSlotsStart + 9
|
||||||
|
|
||||||
|
override val xOffset: Int
|
||||||
|
get() = 5
|
||||||
|
|
||||||
|
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
|
||||||
|
this(
|
||||||
|
syncId,
|
||||||
|
playerInv,
|
||||||
|
PhyBlocks.CRAFTING_TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
craftingSlotsStart = slots.size
|
||||||
|
for (y in 0 until 3) {
|
||||||
|
for (x in 0 until 3) {
|
||||||
|
this.addSlot(Slot(craftingInv, x + y * 3, 13 + x * 18, 140 + y * 18))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSlot = CraftingResultSlot(playerInv.player, craftingInv, result, 0, 31, 224)
|
||||||
|
addSlot(resultSlot)
|
||||||
|
|
||||||
|
updateCraftingResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onContentChanged(inventory: Inventory?) {
|
||||||
|
updateCraftingResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCraftingResult() {
|
||||||
|
val world = playerInv.player.world
|
||||||
|
if (!world.isClient) {
|
||||||
|
val player = playerInv.player as ServerPlayerEntity
|
||||||
|
val recipe = world.server!!.recipeManager.getFirstMatch(RecipeType.CRAFTING, craftingInv, world)
|
||||||
|
val resultStack =
|
||||||
|
if (recipe.isPresent && result.shouldCraftRecipe(world, player, recipe.get())) {
|
||||||
|
recipe.get().craft(craftingInv)
|
||||||
|
} else {
|
||||||
|
ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
result.setStack(0, resultStack)
|
||||||
|
player.networkHandler.sendPacket(ScreenHandlerSlotUpdateS2CPacket(syncId, nextRevision(), resultSlot.id, resultStack))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearCraftingGrid() {
|
||||||
|
assert(!playerInv.player.world.isClient)
|
||||||
|
for (i in 0 until terminal.craftingInv.size()) {
|
||||||
|
val craftingInvStack = terminal.craftingInv.getStack(i)
|
||||||
|
if (craftingInvStack.isEmpty) continue
|
||||||
|
val remainder = terminal.internalBuffer.insert(craftingInvStack, TerminalBufferInventory.Mode.TO_NETWORK)
|
||||||
|
terminal.craftingInv.setStack(i, remainder)
|
||||||
|
}
|
||||||
|
updateCraftingResult()
|
||||||
|
sendContentUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestMoreCraftingIngredients(maxAmount: Int) {
|
||||||
|
assert(!playerInv.player.world.isClient)
|
||||||
|
terminal.requestItemsForCrafting(maxAmount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||||
|
if (slotId == resultSlot.id && resultSlot.hasStack()) {
|
||||||
|
val craftingResult = resultSlot.stack
|
||||||
|
val originalResult = craftingResult.copy()
|
||||||
|
|
||||||
|
// todo: CraftingScreenHandler calls onCraft, but I don't think that's necessary because onStackChanged should handle it
|
||||||
|
craftingResult.item.onCraft(craftingResult, player.world, player)
|
||||||
|
|
||||||
|
if (!insertItem(craftingResult, playerSlotsStart, playerSlotsEnd, true)) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
resultSlot.onQuickTransfer(craftingResult, originalResult)
|
||||||
|
|
||||||
|
if (craftingResult.isEmpty) {
|
||||||
|
resultSlot.stack = ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
if (craftingResult.count == originalResult.count) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSlot.onTakeItem(player, craftingResult)
|
||||||
|
player.dropItem(craftingResult, false)
|
||||||
|
|
||||||
|
return originalResult
|
||||||
|
} else {
|
||||||
|
return super.transferSlot(player, slotId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecipeType.CRAFTING wants a CraftingInventory, but we can't store a CraftingInventory on the BE without a screen handler, so...
|
||||||
|
class CraftingInv(val handler: CraftingTerminalScreenHandler): CraftingInventory(handler, 3, 3) {
|
||||||
|
private val backing = handler.terminal.craftingInv
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
return backing.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStack(i: Int): ItemStack {
|
||||||
|
return backing.getStack(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeStack(i: Int): ItemStack {
|
||||||
|
return backing.removeStack(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeStack(i: Int, j: Int): ItemStack {
|
||||||
|
val res = backing.removeStack(i, j)
|
||||||
|
if (!res.isEmpty) {
|
||||||
|
handler.onContentChanged(this)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setStack(i: Int, itemStack: ItemStack?) {
|
||||||
|
backing.setStack(i, itemStack)
|
||||||
|
handler.onContentChanged(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
backing.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun provideRecipeInputs(finder: RecipeMatcher) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.client.gui.screen.Screen
|
||||||
|
import net.minecraft.client.util.InputUtil
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.shadowfacts.cacao.geometry.Size
|
||||||
|
import net.shadowfacts.cacao.util.Color
|
||||||
|
import net.shadowfacts.cacao.util.LayoutGuide
|
||||||
|
import net.shadowfacts.cacao.util.texture.Texture
|
||||||
|
import net.shadowfacts.cacao.view.Label
|
||||||
|
import net.shadowfacts.cacao.view.TextureView
|
||||||
|
import net.shadowfacts.cacao.view.button.Button
|
||||||
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.networking.C2STerminalCraftingButton
|
||||||
|
import org.lwjgl.glfw.GLFW
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class CraftingTerminalViewController(
|
||||||
|
screen: CraftingTerminalScreen,
|
||||||
|
handler: CraftingTerminalScreenHandler,
|
||||||
|
): AbstractTerminalViewController<CraftingTerminalBlockEntity, CraftingTerminalScreen, CraftingTerminalScreenHandler>(
|
||||||
|
screen,
|
||||||
|
handler,
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val SMALL_BUTTON = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/icons.png"), 0, 48)
|
||||||
|
val SMALL_BUTTON_HOVERED = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/icons.png"), 16, 48)
|
||||||
|
val CLEAR_ICON = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/icons.png"), 32, 48)
|
||||||
|
val PLUS_ICON = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/icons.png"), 48, 48)
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var craftingInv: LayoutGuide
|
||||||
|
|
||||||
|
override fun viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
craftingInv = view.addLayoutGuide()
|
||||||
|
view.solver.dsl {
|
||||||
|
craftingInv.leftAnchor equalTo buffer.leftAnchor
|
||||||
|
craftingInv.topAnchor equalTo playerInv.topAnchor
|
||||||
|
craftingInv.widthAnchor equalTo buffer.widthAnchor
|
||||||
|
craftingInv.heightAnchor equalTo 54
|
||||||
|
}
|
||||||
|
|
||||||
|
val craftingLabel = view.addSubview(Label(TranslatableText("gui.phycon.terminal_crafting"))).apply {
|
||||||
|
textColor = Color.TEXT
|
||||||
|
}
|
||||||
|
view.solver.dsl {
|
||||||
|
craftingLabel.leftAnchor equalTo craftingInv.leftAnchor
|
||||||
|
craftingLabel.topAnchor equalTo playerInvLabel.topAnchor
|
||||||
|
}
|
||||||
|
|
||||||
|
val clearIcon = TextureView(CLEAR_ICON).apply {
|
||||||
|
intrinsicContentSize = Size(3.0,3.0)
|
||||||
|
}
|
||||||
|
val clearButton = view.addSubview(Button(clearIcon, padding = 2.0, handler = ::clearPressed)).apply {
|
||||||
|
background = TextureView(SMALL_BUTTON)
|
||||||
|
hoveredBackground = TextureView(SMALL_BUTTON_HOVERED)
|
||||||
|
tooltip = TranslatableText("gui.phycon.terminal.clear_crafting")
|
||||||
|
}
|
||||||
|
view.solver.dsl {
|
||||||
|
clearButton.topAnchor equalTo craftingInv.topAnchor
|
||||||
|
clearButton.leftAnchor equalTo (pane.leftAnchor + 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
val plusIcon = TextureView(PLUS_ICON).apply {
|
||||||
|
intrinsicContentSize = Size(3.0, 3.0)
|
||||||
|
}
|
||||||
|
val plusButton = view.addSubview(Button(plusIcon, padding = 2.0, handler = ::plusPressed)).apply {
|
||||||
|
background= TextureView(SMALL_BUTTON)
|
||||||
|
hoveredBackground = TextureView(SMALL_BUTTON_HOVERED)
|
||||||
|
tooltip = TranslatableText("gui.phycon.terminal.more_crafting")
|
||||||
|
}
|
||||||
|
view.solver.dsl {
|
||||||
|
plusButton.topAnchor equalTo (clearButton.bottomAnchor + 2)
|
||||||
|
plusButton.leftAnchor equalTo clearButton.leftAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearPressed(button: Button) {
|
||||||
|
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2STerminalCraftingButton(terminal, C2STerminalCraftingButton.Action.CLEAR_GRID))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun plusPressed(button: Button) {
|
||||||
|
val client = MinecraftClient.getInstance()
|
||||||
|
val action =
|
||||||
|
if (Screen.hasShiftDown()) {
|
||||||
|
C2STerminalCraftingButton.Action.REQUEST_MAX_MORE
|
||||||
|
} else {
|
||||||
|
C2STerminalCraftingButton.Action.REQUEST_ONE_MORE
|
||||||
|
}
|
||||||
|
client.player!!.networkHandler.sendPacket(C2STerminalCraftingButton(terminal, action))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.world.BlockView
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +14,6 @@ class TerminalBlock: AbstractTerminalBlock<TerminalBlockEntity>() {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = TerminalBlockEntity()
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = TerminalBlockEntity(pos, state)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.minecraft.screen.ScreenHandler
|
import net.minecraft.screen.ScreenHandler
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
import net.minecraft.text.TranslatableText
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class TerminalBlockEntity: AbstractTerminalBlockEntity(PhyBlockEntities.TERMINAL) {
|
class TerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlockEntity(PhyBlockEntities.TERMINAL, pos, state) {
|
||||||
|
|
||||||
override fun onActivate(player: PlayerEntity) {
|
override fun onActivate(player: PlayerEntity) {
|
||||||
if (!world!!.isClient) {
|
super.onActivate(player)
|
||||||
updateAndSync()
|
|
||||||
|
|
||||||
inventoryCache.clear()
|
if (!world!!.isClient) {
|
||||||
sendPacket(RequestInventoryPacket(ipAddress))
|
|
||||||
val factory = object: ExtendedScreenHandlerFactory {
|
val factory = object: ExtendedScreenHandlerFactory {
|
||||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||||
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
||||||
|
|
|
@ -3,8 +3,8 @@ package net.shadowfacts.phycon.block.terminal
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.inventory.SimpleInventory
|
import net.minecraft.inventory.SimpleInventory
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.nbt.IntArrayTag
|
import net.minecraft.nbt.NbtIntArray
|
||||||
import net.shadowfacts.phycon.util.fromTag
|
import net.shadowfacts.phycon.util.fromTag
|
||||||
import net.shadowfacts.phycon.util.toTag
|
import net.shadowfacts.phycon.util.toTag
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
@ -21,14 +21,14 @@ class TerminalBufferInventory(size: Int): SimpleInventory(size) {
|
||||||
var modes = Array(size) { Mode.UNASSIGNED }
|
var modes = Array(size) { Mode.UNASSIGNED }
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun toTag(): CompoundTag {
|
fun toTag(): NbtCompound {
|
||||||
val compound = CompoundTag()
|
val compound = NbtCompound()
|
||||||
compound.put("Inventory", (this as SimpleInventory).toTag())
|
compound.put("Inventory", (this as SimpleInventory).toTag())
|
||||||
compound.put("Modes", IntArrayTag(modes.map(Mode::ordinal)))
|
compound.put("Modes", NbtIntArray(modes.map(Mode::ordinal)))
|
||||||
return compound
|
return compound
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromTag(tag: CompoundTag) {
|
fun fromTag(tag: NbtCompound) {
|
||||||
val inventory = tag.getList("Inventory", 10)
|
val inventory = tag.getList("Inventory", 10)
|
||||||
(this as SimpleInventory).fromTag(inventory)
|
(this as SimpleInventory).fromTag(inventory)
|
||||||
tag.getIntArray("Modes").forEachIndexed { i, it -> modes[i] = Mode.values()[it] }
|
tag.getIntArray("Modes").forEachIndexed { i, it -> modes[i] = Mode.values()[it] }
|
||||||
|
|
|
@ -6,7 +6,7 @@ import net.minecraft.client.render.model.UnbakedModel
|
||||||
import net.minecraft.resource.ResourceManager
|
import net.minecraft.resource.ResourceManager
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.client.model.TerminalModel
|
import net.shadowfacts.phycon.client.model.ScreenDeviceModel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -15,11 +15,13 @@ class PhyExtendedModelProvider(resourceManager: ResourceManager): ModelResourceP
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TERMINAL = Identifier(PhysicalConnectivity.MODID, "block/terminal")
|
val TERMINAL = Identifier(PhysicalConnectivity.MODID, "block/terminal")
|
||||||
|
val CRAFTING_TERMINAL = Identifier(PhysicalConnectivity.MODID, "block/crafting_terminal")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? {
|
override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? {
|
||||||
return when (resourceId) {
|
return when (resourceId) {
|
||||||
TERMINAL -> TerminalModel
|
TERMINAL -> ScreenDeviceModel(TERMINAL)
|
||||||
|
CRAFTING_TERMINAL -> ScreenDeviceModel(CRAFTING_TERMINAL)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,10 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
|
||||||
val EXTRACTOR_SIDE = Identifier(PhysicalConnectivity.MODID, "block/extractor_side")
|
val EXTRACTOR_SIDE = Identifier(PhysicalConnectivity.MODID, "block/extractor_side")
|
||||||
val INSERTER = Identifier(PhysicalConnectivity.MODID, "block/inserter")
|
val INSERTER = Identifier(PhysicalConnectivity.MODID, "block/inserter")
|
||||||
val INSERTER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/inserter_side")
|
val INSERTER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/inserter_side")
|
||||||
|
val P2P_INTERFACE = Identifier(PhysicalConnectivity.MODID, "block/p2p_interface")
|
||||||
|
val P2P_INTERFACE_SIDE = Identifier(PhysicalConnectivity.MODID, "block/p2p_interface_side")
|
||||||
|
val P2P_RECEIVER = Identifier(PhysicalConnectivity.MODID, "block/p2p_receiver")
|
||||||
|
val P2P_RECEIVER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/p2p_receiver_side")
|
||||||
|
|
||||||
val CABLES = DyeColor.values().map {
|
val CABLES = DyeColor.values().map {
|
||||||
Identifier(PhysicalConnectivity.MODID, "block/cable/${it.getName()}") to it
|
Identifier(PhysicalConnectivity.MODID, "block/cable/${it.getName()}") to it
|
||||||
|
@ -38,6 +42,8 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
|
||||||
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
|
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
|
||||||
EXTRACTOR -> SimpleFaceDeviceModel(EXTRACTOR_SIDE)
|
EXTRACTOR -> SimpleFaceDeviceModel(EXTRACTOR_SIDE)
|
||||||
INSERTER -> SimpleFaceDeviceModel(INSERTER_SIDE)
|
INSERTER -> SimpleFaceDeviceModel(INSERTER_SIDE)
|
||||||
|
P2P_INTERFACE -> SimpleFaceDeviceModel(P2P_INTERFACE_SIDE)
|
||||||
|
P2P_RECEIVER -> SimpleFaceDeviceModel(P2P_RECEIVER_SIDE)
|
||||||
in CABLES -> ColoredCableModel(CABLES[resourceId]!!)
|
in CABLES -> ColoredCableModel(CABLES[resourceId]!!)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import net.minecraft.client.render.model.*
|
||||||
import net.minecraft.client.texture.Sprite
|
import net.minecraft.client.texture.Sprite
|
||||||
import net.minecraft.client.texture.SpriteAtlasTexture
|
import net.minecraft.client.texture.SpriteAtlasTexture
|
||||||
import net.minecraft.client.util.SpriteIdentifier
|
import net.minecraft.client.util.SpriteIdentifier
|
||||||
|
import net.minecraft.screen.PlayerScreenHandler
|
||||||
import net.minecraft.util.DyeColor
|
import net.minecraft.util.DyeColor
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
@ -85,7 +86,7 @@ class ColoredCableModel(
|
||||||
rotationContainer: ModelBakeSettings,
|
rotationContainer: ModelBakeSettings,
|
||||||
modelId: Identifier
|
modelId: Identifier
|
||||||
): BakedModel {
|
): BakedModel {
|
||||||
centerSprite = textureGetter.apply(SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/cable/${color.getName()}/straight")))
|
centerSprite = textureGetter.apply(SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/cable/${color.getName()}/straight")))
|
||||||
|
|
||||||
sideRotations.forEach { (side, rot) ->
|
sideRotations.forEach { (side, rot) ->
|
||||||
this.side[side.ordinal] = loader.bakeRecoloredCable(SIDE, rot, textureGetter, color)
|
this.side[side.ordinal] = loader.bakeRecoloredCable(SIDE, rot, textureGetter, color)
|
||||||
|
@ -260,7 +261,7 @@ class ColoredCableModel(
|
||||||
|
|
||||||
override fun isBuiltin() = false
|
override fun isBuiltin() = false
|
||||||
|
|
||||||
override fun getSprite() = centerSprite
|
override fun getParticleSprite() = centerSprite
|
||||||
|
|
||||||
override fun getTransformation() = null
|
override fun getTransformation() = null
|
||||||
|
|
||||||
|
|
|
@ -120,9 +120,9 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
|
||||||
|
|
||||||
val sideQuads = getSideModel(state)?.getQuads(state, face, random) ?: listOf()
|
val sideQuads = getSideModel(state)?.getQuads(state, face, random) ?: listOf()
|
||||||
val cableQuads = if (connection.direction == facing.opposite) {
|
val cableQuads = if (connection.direction == facing.opposite) {
|
||||||
interfaceCableStraight[color]!![facing.ordinal]?.getQuads(state, face, random) ?: listOf()
|
interfaceCableStraight[color]!![facing.ordinal].getQuads(state, face, random) ?: listOf()
|
||||||
} else if (connection == FaceCableConnection.NONE) {
|
} else if (connection == FaceCableConnection.NONE) {
|
||||||
interfaceCableCap[color]!![facing.ordinal]?.getQuads(state, face, random) ?: listOf()
|
interfaceCableCap[color]!![facing.ordinal].getQuads(state, face, random) ?: listOf()
|
||||||
} else {
|
} else {
|
||||||
val model = when (facing) {
|
val model = when (facing) {
|
||||||
Direction.DOWN -> when (connection) {
|
Direction.DOWN -> when (connection) {
|
||||||
|
@ -183,7 +183,7 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
|
||||||
|
|
||||||
override fun isBuiltin() = false
|
override fun isBuiltin() = false
|
||||||
|
|
||||||
abstract override fun getSprite(): Sprite
|
abstract override fun getParticleSprite(): Sprite
|
||||||
|
|
||||||
override fun getTransformation() = null
|
override fun getTransformation() = null
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,8 @@ object RedstoneControllerModel: FaceDeviceModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSprite(): Sprite {
|
override fun getParticleSprite(): Sprite {
|
||||||
return offModels.first()!!.sprite
|
return offModels.first()!!.particleSprite
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import net.minecraft.client.texture.Sprite
|
||||||
import net.minecraft.client.texture.SpriteAtlasTexture
|
import net.minecraft.client.texture.SpriteAtlasTexture
|
||||||
import net.minecraft.client.util.SpriteIdentifier
|
import net.minecraft.client.util.SpriteIdentifier
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.screen.PlayerScreenHandler
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
@ -27,13 +28,18 @@ import java.util.function.Supplier
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
object TerminalModel: UnbakedModel, BakedModel, FabricBakedModel {
|
class ScreenDeviceModel(
|
||||||
|
screenTexture: Identifier,
|
||||||
|
): UnbakedModel, BakedModel, FabricBakedModel {
|
||||||
|
|
||||||
private val TERMINAL = SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/terminal"))
|
companion object {
|
||||||
private val CASING = SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/casing"))
|
private val CASING = SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/casing"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val screenTexture = SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, screenTexture)
|
||||||
|
|
||||||
private lateinit var meshes: Array<Mesh>
|
private lateinit var meshes: Array<Mesh>
|
||||||
private lateinit var terminalSprite: Sprite
|
private lateinit var screenSprite: Sprite
|
||||||
|
|
||||||
override fun getModelDependencies(): Collection<Identifier> {
|
override fun getModelDependencies(): Collection<Identifier> {
|
||||||
return listOf()
|
return listOf()
|
||||||
|
@ -43,7 +49,7 @@ object TerminalModel: UnbakedModel, BakedModel, FabricBakedModel {
|
||||||
unbakedModelGetter: Function<Identifier, UnbakedModel>,
|
unbakedModelGetter: Function<Identifier, UnbakedModel>,
|
||||||
unresolvedTextureDependencies: MutableSet<Pair<String, String>>
|
unresolvedTextureDependencies: MutableSet<Pair<String, String>>
|
||||||
): Collection<SpriteIdentifier> {
|
): Collection<SpriteIdentifier> {
|
||||||
return listOf(TERMINAL, CASING)
|
return listOf(screenTexture, CASING)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bake(
|
override fun bake(
|
||||||
|
@ -53,7 +59,7 @@ object TerminalModel: UnbakedModel, BakedModel, FabricBakedModel {
|
||||||
modelId: Identifier
|
modelId: Identifier
|
||||||
): BakedModel {
|
): BakedModel {
|
||||||
|
|
||||||
terminalSprite = textureGetter.apply(TERMINAL)
|
screenSprite = textureGetter.apply(screenTexture)
|
||||||
val casingSprite = textureGetter.apply(CASING)
|
val casingSprite = textureGetter.apply(CASING)
|
||||||
|
|
||||||
val renderer = RendererAccess.INSTANCE.renderer!!
|
val renderer = RendererAccess.INSTANCE.renderer!!
|
||||||
|
@ -66,26 +72,63 @@ object TerminalModel: UnbakedModel, BakedModel, FabricBakedModel {
|
||||||
|
|
||||||
for (dir in Direction.values()) {
|
for (dir in Direction.values()) {
|
||||||
if (dir == facing) {
|
if (dir == facing) {
|
||||||
emitter.square(facing, 0f, 0f, 1f, 1f, QuadEmitter.CULL_FACE_EPSILON * 10)
|
// screen border
|
||||||
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
|
emitter.square(facing, 0f, 0f, 3/16f, 3/16f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
emitter.spriteColor(0, -1, -1, -1, -1)
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
emitter.emit()
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 13/16f, 0f, 1f, 3/16f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 13/16f, 13/16f, 1f, 1f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 0f, 13/16f, 3/16f, 1f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 3/16f, 0f, 13/16f, 2/16f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 3/16f, 14/16f, 13/16f, 1f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 0f, 3/16f, 2/16f, 13/16f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
emitter.square(facing, 14/16f, 3/16f, 1f, 13/16f, 0f)
|
||||||
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
|
emitter.emit()
|
||||||
|
|
||||||
|
// screen
|
||||||
emitter.material(PhysicalConnectivityClient.screenMaterial)
|
emitter.material(PhysicalConnectivityClient.screenMaterial)
|
||||||
emitter.square(facing, 3/16f, 2/16f, 13/16f, 3/16f, 0f)
|
emitter.square(facing, 3/16f, 2/16f, 13/16f, 3/16f, 0f)
|
||||||
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
emitter.spriteColor(0, -1, -1, -1, -1)
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
emitter.emit()
|
emitter.emit()
|
||||||
|
|
||||||
emitter.material(PhysicalConnectivityClient.screenMaterial)
|
emitter.material(PhysicalConnectivityClient.screenMaterial)
|
||||||
emitter.square(facing, 2/16f, 3/16f, 14/16f, 13/16f, 0f)
|
emitter.square(facing, 2/16f, 3/16f, 14/16f, 13/16f, 0f)
|
||||||
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
emitter.spriteColor(0, -1, -1, -1, -1)
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
emitter.emit()
|
emitter.emit()
|
||||||
|
|
||||||
emitter.material(PhysicalConnectivityClient.screenMaterial)
|
emitter.material(PhysicalConnectivityClient.screenMaterial)
|
||||||
emitter.square(facing, 3/16f, 13/16f, 13/16f, 14/16f, 0f)
|
emitter.square(facing, 3/16f, 13/16f, 13/16f, 14/16f, 0f)
|
||||||
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
|
emitter.spriteBake(0, screenSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||||
emitter.spriteColor(0, -1, -1, -1, -1)
|
emitter.spriteColor(0, -1, -1, -1, -1)
|
||||||
emitter.emit()
|
emitter.emit()
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,7 +172,7 @@ object TerminalModel: UnbakedModel, BakedModel, FabricBakedModel {
|
||||||
|
|
||||||
override fun isBuiltin() = false
|
override fun isBuiltin() = false
|
||||||
|
|
||||||
override fun getSprite() = terminalSprite
|
override fun getParticleSprite() = screenSprite
|
||||||
|
|
||||||
override fun getTransformation() = null
|
override fun getTransformation() = null
|
||||||
|
|
|
@ -35,7 +35,7 @@ class SimpleFaceDeviceModel(
|
||||||
return sideModels[state[FaceDeviceBlock.COLOR]]!![state[FaceDeviceBlock.FACING].ordinal]
|
return sideModels[state[FaceDeviceBlock.COLOR]]!![state[FaceDeviceBlock.FACING].ordinal]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSprite(): Sprite {
|
override fun getParticleSprite(): Sprite {
|
||||||
return sideModels[DyeColor.BLACK]!!.first().sprite
|
return sideModels[DyeColor.BLACK]!!.first().particleSprite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
package net.shadowfacts.phycon.client.screen
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget
|
|
||||||
import net.shadowfacts.phycon.util.FriendlyNameable
|
|
||||||
import net.shadowfacts.phycon.util.RotatableEnum
|
|
||||||
import net.shadowfacts.phycon.util.next
|
|
||||||
import net.shadowfacts.phycon.util.prev
|
|
||||||
import kotlin.reflect.KMutableProperty
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
class EnumButton<E>(
|
|
||||||
val prop: KMutableProperty<E>,
|
|
||||||
x: Int,
|
|
||||||
y: Int,
|
|
||||||
width: Int,
|
|
||||||
height: Int,
|
|
||||||
val onChange: () -> Unit
|
|
||||||
): AbstractPressableButtonWidget(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
prop.getter.call().friendlyName
|
|
||||||
) where E: Enum<E>, E: RotatableEnum, E: FriendlyNameable {
|
|
||||||
|
|
||||||
private var currentButton: Int? = null
|
|
||||||
|
|
||||||
override fun mouseClicked(d: Double, e: Double, button: Int): Boolean {
|
|
||||||
currentButton = button
|
|
||||||
val res = super.mouseClicked(d, e, button)
|
|
||||||
currentButton = null
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isValidClickButton(i: Int): Boolean {
|
|
||||||
return i == 0 || i == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPress() {
|
|
||||||
val newVal = if ((currentButton ?: 0) == 0) prop.getter.call().next else prop.getter.call().prev
|
|
||||||
prop.setter.call(newVal)
|
|
||||||
message = newVal.friendlyName
|
|
||||||
onChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -18,7 +18,7 @@ class ScrollTrackView(
|
||||||
): View() {
|
): View() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val THUMB = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png"), 52, 230)
|
private val THUMB = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png"), 52, 224)
|
||||||
private const val THUMB_WIDTH = 12.0
|
private const val THUMB_WIDTH = 12.0
|
||||||
private const val THUMB_HEIGHT = 15.0
|
private const val THUMB_HEIGHT = 15.0
|
||||||
}
|
}
|
||||||
|
@ -50,16 +50,16 @@ class ScrollTrackView(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mouseDragged(point: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
override fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
||||||
if (grabbedY == null && point !in thumbView.frame) {
|
if (grabbedY == null && startPoint !in thumbView.frame) {
|
||||||
val newCenter = MathHelper.clamp(point.y, THUMB_HEIGHT / 2, frame.height - THUMB_HEIGHT / 2)
|
val newCenter = MathHelper.clamp(startPoint.y, THUMB_HEIGHT / 2, frame.height - THUMB_HEIGHT / 2)
|
||||||
thumbView.frame = Rect(0.0, newCenter - THUMB_HEIGHT / 2, THUMB_WIDTH, THUMB_HEIGHT)
|
thumbView.frame = Rect(0.0, newCenter - THUMB_HEIGHT / 2, THUMB_WIDTH, THUMB_HEIGHT)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grabbedY == null) {
|
if (grabbedY == null) {
|
||||||
grabbedY = point.y - thumbView.frame.top
|
grabbedY = startPoint.y - thumbView.frame.top
|
||||||
}
|
}
|
||||||
val newTop = MathHelper.clamp(point.y - grabbedY!!, 0.0, frame.height - THUMB_HEIGHT)
|
val newTop = MathHelper.clamp(startPoint.y - grabbedY!!, 0.0, frame.height - THUMB_HEIGHT)
|
||||||
thumbView.frame = Rect(0.0, newTop, THUMB_WIDTH, THUMB_HEIGHT)
|
thumbView.frame = Rect(0.0, newTop, THUMB_WIDTH, THUMB_HEIGHT)
|
||||||
|
|
||||||
scrollPositionChanged(this)
|
scrollPositionChanged(this)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import net.shadowfacts.cacao.window.Window
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
|
||||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
|
||||||
import net.shadowfacts.phycon.component.ActivationController
|
import net.shadowfacts.phycon.component.ActivationController
|
||||||
|
@ -90,6 +91,15 @@ class DeviceConsoleScreen(
|
||||||
RedstoneEmitterViewController(device)
|
RedstoneEmitterViewController(device)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
if (device is P2PReceiverBlockEntity) {
|
||||||
|
tabs.add(TabViewController.SimpleTab(
|
||||||
|
TextureView(Texture(Identifier("textures/item/ender_pearl.png"), 0, 0, 16, 16)).apply {
|
||||||
|
intrinsicContentSize = Size(16.0, 16.0)
|
||||||
|
},
|
||||||
|
TranslatableText("block.phycon.p2p_receiver"),
|
||||||
|
P2PReceiverViewController(device)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
tabController = TabViewController(tabs)
|
tabController = TabViewController(tabs)
|
||||||
|
|
||||||
|
@ -108,11 +118,11 @@ class DeviceConsoleScreen(
|
||||||
addWindow(Window(root))
|
addWindow(Window(root))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isPauseScreen() = false
|
override fun shouldPause() = false
|
||||||
|
|
||||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||||
if (keyCode == GLFW.GLFW_KEY_E) {
|
if (keyCode == GLFW.GLFW_KEY_E) {
|
||||||
onClose()
|
close()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return super.keyPressed(keyCode, scanCode, modifiers)
|
return super.keyPressed(keyCode, scanCode, modifiers)
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package net.shadowfacts.phycon.client.screen.console
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.shadowfacts.cacao.util.Color
|
||||||
|
import net.shadowfacts.cacao.view.Label
|
||||||
|
import net.shadowfacts.cacao.view.textfield.TextField
|
||||||
|
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||||
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
|
||||||
|
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class P2PReceiverViewController(
|
||||||
|
val device: P2PReceiverBlockEntity,
|
||||||
|
): ViewController() {
|
||||||
|
|
||||||
|
override fun viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
val label = Label(TranslatableText("gui.phycon.console.p2p_receiver.target")).apply {
|
||||||
|
textColor = Color.TEXT
|
||||||
|
}
|
||||||
|
view.addSubview(label)
|
||||||
|
|
||||||
|
val textField =
|
||||||
|
TextField(device.target?.toString() ?: "") {
|
||||||
|
device.target = IPAddress.parse(it.text)
|
||||||
|
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||||
|
}
|
||||||
|
view.addSubview(textField)
|
||||||
|
|
||||||
|
val status = Label(device.status.displayName).apply {
|
||||||
|
textColor = Color.TEXT
|
||||||
|
}
|
||||||
|
view.addSubview(status)
|
||||||
|
device.clientObserver = {
|
||||||
|
status.text = device.status.displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
view.solver.dsl {
|
||||||
|
textField.widthAnchor equalTo 100
|
||||||
|
textField.heightAnchor equalTo 20
|
||||||
|
textField.topAnchor equalTo view.topAnchor
|
||||||
|
textField.rightAnchor equalTo view.rightAnchor
|
||||||
|
|
||||||
|
label.centerYAnchor equalTo textField.centerYAnchor
|
||||||
|
label.rightAnchor equalTo (textField.leftAnchor - 4)
|
||||||
|
|
||||||
|
status.centerXAnchor equalTo view.centerXAnchor
|
||||||
|
status.centerYAnchor equalTo (view.centerYAnchor - 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,7 +36,9 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
||||||
insertion.results.add(packet.capacity to packet.stackReceiver)
|
insertion.results.add(packet.capacity to packet.stackReceiver)
|
||||||
if (insertion.isFinishable(this)) {
|
if (insertion.isFinishable(this)) {
|
||||||
val remaining = finishInsertion(insertion)
|
val remaining = finishInsertion(insertion)
|
||||||
// todo: do something with remaining
|
if (!remaining.isEmpty) {
|
||||||
|
pendingInsertions.add(createPendingInsertion(remaining))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +58,13 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
||||||
// copy the insertion stack so subclasses that override this method can still see the originally dispatched stack after the super call
|
// copy the insertion stack so subclasses that override this method can still see the originally dispatched stack after the super call
|
||||||
val remaining = insertion.stack.copy()
|
val remaining = insertion.stack.copy()
|
||||||
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
||||||
val (capacity, receivingInterface) = sortedResults.removeFirst()
|
val (capacity, receiver) = sortedResults.removeFirst()
|
||||||
if (capacity <= 0) continue
|
if (capacity <= 0) continue
|
||||||
val copy = remaining.copyWithCount(min(capacity, remaining.count))
|
val sentCount = min(capacity, remaining.count)
|
||||||
sendPacket(ItemStackPacket(copy, ipAddress, receivingInterface.ipAddress))
|
val copy = remaining.copyWithCount(sentCount)
|
||||||
|
sendPacket(ItemStackPacket(copy, ipAddress, receiver.ipAddress))
|
||||||
// todo: the destination should confirm how much was actually inserted, in case of race condition
|
// todo: the destination should confirm how much was actually inserted, in case of race condition
|
||||||
remaining.count -= capacity
|
remaining.count -= sentCount
|
||||||
}
|
}
|
||||||
|
|
||||||
return remaining
|
return remaining
|
||||||
|
@ -89,7 +92,11 @@ fun <Self, Insertion: NetworkStackDispatcher.PendingInsertion<Insertion>> Self.f
|
||||||
|
|
||||||
val finishable = pendingInsertions.filter { it.isFinishable(this) }
|
val finishable = pendingInsertions.filter { it.isFinishable(this) }
|
||||||
// finishInsertion removes the object from pendingInsertions
|
// finishInsertion removes the object from pendingInsertions
|
||||||
finishable.forEach(::finishInsertion)
|
for (insertion in finishable) {
|
||||||
// todo: do something with remaining?
|
val remaining = finishInsertion(insertion)
|
||||||
|
if (!remaining.isEmpty) {
|
||||||
|
pendingInsertions.add(createPendingInsertion(remaining))
|
||||||
|
}
|
||||||
|
}
|
||||||
// todo: if a timed-out insertion can't be finished, we should probably retry after some time (exponential backoff?)
|
// todo: if a timed-out insertion can't be finished, we should probably retry after some time (exponential backoff?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.shadowfacts.phycon.frame
|
package net.shadowfacts.phycon.frame
|
||||||
|
|
||||||
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
open class BaseFrame(
|
open class BaseFrame(
|
||||||
@JvmField private val source: MACAddress,
|
private val source: MACAddress,
|
||||||
@JvmField private val destination: MACAddress
|
private val destination: MACAddress
|
||||||
): EthernetFrame {
|
): EthernetFrame {
|
||||||
override fun getSource() = source
|
override fun getSource() = source
|
||||||
override fun getDestination() = destination
|
override fun getDestination() = destination
|
||||||
|
|
|
@ -8,7 +8,7 @@ import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class BasePacketFrame(
|
class BasePacketFrame(
|
||||||
@JvmField private val packet: Packet,
|
private val packet: Packet,
|
||||||
source: MACAddress,
|
source: MACAddress,
|
||||||
destination: MACAddress,
|
destination: MACAddress,
|
||||||
): BaseFrame(source, destination), PacketFrame {
|
): BaseFrame(source, destination), PacketFrame {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package net.shadowfacts.phycon.frame
|
||||||
|
|
||||||
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class NetworkSplitFrame(source: MACAddress): BaseFrame(source, MACAddress.BROADCAST)
|
|
@ -1,9 +1,11 @@
|
||||||
package net.shadowfacts.phycon.init
|
package net.shadowfacts.phycon.init
|
||||||
|
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity
|
||||||
|
@ -15,10 +17,16 @@ import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlockEntity
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlock
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlock
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
|
||||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlockEntity
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||||
|
|
||||||
|
@ -29,26 +37,32 @@ object PhyBlockEntities {
|
||||||
|
|
||||||
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
|
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
|
||||||
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
||||||
|
val CRAFTING_TERMINAL = create(::CraftingTerminalBlockEntity, PhyBlocks.CRAFTING_TERMINAL)
|
||||||
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
||||||
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
|
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
|
||||||
val INSERTER = create(::InserterBlockEntity, PhyBlocks.INSERTER)
|
val INSERTER = create(::InserterBlockEntity, PhyBlocks.INSERTER)
|
||||||
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
||||||
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
|
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
|
||||||
val REDSTONE_EMITTER = create(::RedstoneEmitterBlockEntity, PhyBlocks.REDSTONE_EMITTER)
|
val REDSTONE_EMITTER = create(::RedstoneEmitterBlockEntity, PhyBlocks.REDSTONE_EMITTER)
|
||||||
|
val P2P_INTERFACE = create(::P2PInterfaceBlockEntity, PhyBlocks.P2P_INTERFACE)
|
||||||
|
val P2P_RECEIVER = create(::P2PReceiverBlockEntity, PhyBlocks.P2P_RECEIVER)
|
||||||
|
|
||||||
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
private fun <T: BlockEntity> create(builder: (BlockPos, BlockState) -> T, block: Block): BlockEntityType<T> {
|
||||||
return BlockEntityType.Builder.create(builder, block).build(null)
|
return BlockEntityType.Builder.create(builder, block).build(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
|
register(CraftingTerminalBlock.ID, CRAFTING_TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(ExtractorBlock.ID, EXTRACTOR)
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
register(InserterBlock.ID, INSERTER)
|
register(InserterBlock.ID, INSERTER)
|
||||||
register(MinerBlock.ID, MINER)
|
register(MinerBlock.ID, MINER)
|
||||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||||
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||||
|
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
|
||||||
|
register(P2PReceiverBlock.ID, P2P_RECEIVER)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
||||||
|
|
|
@ -11,8 +11,11 @@ import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||||
import net.shadowfacts.phycon.block.miner.MinerBlock
|
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlock
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlock
|
||||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,12 +27,15 @@ object PhyBlocks {
|
||||||
|
|
||||||
val INTERFACE = InterfaceBlock()
|
val INTERFACE = InterfaceBlock()
|
||||||
val TERMINAL = TerminalBlock()
|
val TERMINAL = TerminalBlock()
|
||||||
|
val CRAFTING_TERMINAL = CraftingTerminalBlock()
|
||||||
val SWITCH = SwitchBlock()
|
val SWITCH = SwitchBlock()
|
||||||
val EXTRACTOR = ExtractorBlock()
|
val EXTRACTOR = ExtractorBlock()
|
||||||
val INSERTER = InserterBlock()
|
val INSERTER = InserterBlock()
|
||||||
val MINER = MinerBlock()
|
val MINER = MinerBlock()
|
||||||
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
|
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
|
||||||
val REDSTONE_EMITTER = RedstoneEmitterBlock()
|
val REDSTONE_EMITTER = RedstoneEmitterBlock()
|
||||||
|
val P2P_INTERFACE = P2PInterfaceBlock()
|
||||||
|
val P2P_RECEIVER = P2PReceiverBlock()
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
for ((color, block) in CABLES) {
|
for ((color, block) in CABLES) {
|
||||||
|
@ -38,12 +44,15 @@ object PhyBlocks {
|
||||||
|
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
|
register(CraftingTerminalBlock.ID, CRAFTING_TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(ExtractorBlock.ID, EXTRACTOR)
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
register(InserterBlock.ID, INSERTER)
|
register(InserterBlock.ID, INSERTER)
|
||||||
register(MinerBlock.ID, MINER)
|
register(MinerBlock.ID, MINER)
|
||||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||||
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||||
|
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
|
||||||
|
register(P2PReceiverBlock.ID, P2P_RECEIVER)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, block: Block) {
|
private fun register(id: Identifier, block: Block) {
|
||||||
|
|
|
@ -12,11 +12,15 @@ import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||||
import net.shadowfacts.phycon.block.miner.MinerBlock
|
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlock
|
||||||
|
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlock
|
||||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
import net.shadowfacts.phycon.item.DeviceBlockItem
|
import net.shadowfacts.phycon.item.DeviceBlockItem
|
||||||
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
|
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
|
||||||
|
import net.shadowfacts.phycon.util.text
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -29,12 +33,15 @@ object PhyItems {
|
||||||
|
|
||||||
val INTERFACE = FaceDeviceBlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
val INTERFACE = FaceDeviceBlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
||||||
val TERMINAL = DeviceBlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
val TERMINAL = DeviceBlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
||||||
|
val CRAFTING_TERMINAL = DeviceBlockItem(PhyBlocks.CRAFTING_TERMINAL, Item.Settings())
|
||||||
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
||||||
val EXTRACTOR = FaceDeviceBlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
|
val EXTRACTOR = FaceDeviceBlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
|
||||||
val INSERTER = FaceDeviceBlockItem(PhyBlocks.INSERTER, Item.Settings())
|
val INSERTER = FaceDeviceBlockItem(PhyBlocks.INSERTER, Item.Settings())
|
||||||
val MINER = DeviceBlockItem(PhyBlocks.MINER, Item.Settings())
|
val MINER = DeviceBlockItem(PhyBlocks.MINER, Item.Settings())
|
||||||
val REDSTONE_CONTROLLER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
|
val REDSTONE_CONTROLLER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
|
||||||
val REDSTONE_EMITTER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_EMITTER, Item.Settings())
|
val REDSTONE_EMITTER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_EMITTER, Item.Settings())
|
||||||
|
val P2P_INTERFACE = FaceDeviceBlockItem(PhyBlocks.P2P_INTERFACE, Item.Settings())
|
||||||
|
val P2P_RECEIVER = FaceDeviceBlockItem(PhyBlocks.P2P_RECEIVER, Item.Settings())
|
||||||
|
|
||||||
val SCREWDRIVER = ScrewdriverItem()
|
val SCREWDRIVER = ScrewdriverItem()
|
||||||
val CONSOLE = ConsoleItem()
|
val CONSOLE = ConsoleItem()
|
||||||
|
@ -52,12 +59,25 @@ object PhyItems {
|
||||||
|
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
|
register(CraftingTerminalBlock.ID, CRAFTING_TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(ExtractorBlock.ID, EXTRACTOR)
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
register(InserterBlock.ID, INSERTER)
|
register(InserterBlock.ID, INSERTER)
|
||||||
register(MinerBlock.ID, MINER)
|
register(MinerBlock.ID, MINER)
|
||||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||||
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||||
|
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
|
||||||
|
P2P_INTERFACE.addTooltip(text {
|
||||||
|
withStyle(darkGray) {
|
||||||
|
+translate("tooltip.phycon.p2p_interface")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
register(P2PReceiverBlock.ID, P2P_RECEIVER)
|
||||||
|
P2P_RECEIVER.addTooltip(text {
|
||||||
|
withStyle(darkGray) {
|
||||||
|
+translate("tooltip.phycon.p2p_receiver")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
register(ScrewdriverItem.ID, SCREWDRIVER)
|
register(ScrewdriverItem.ID, SCREWDRIVER)
|
||||||
register(ConsoleItem.ID, CONSOLE)
|
register(ConsoleItem.ID, CONSOLE)
|
||||||
|
|
|
@ -4,6 +4,8 @@ import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
||||||
import net.minecraft.screen.ScreenHandlerType
|
import net.minecraft.screen.ScreenHandlerType
|
||||||
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreenHandler
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreenHandler
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreenHandler
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||||
|
|
||||||
|
@ -11,6 +13,8 @@ object PhyScreens {
|
||||||
|
|
||||||
lateinit var TERMINAL: ScreenHandlerType<TerminalScreenHandler>
|
lateinit var TERMINAL: ScreenHandlerType<TerminalScreenHandler>
|
||||||
private set
|
private set
|
||||||
|
lateinit var CRAFTING_TERMINAL: ScreenHandlerType<CraftingTerminalScreenHandler>
|
||||||
|
private set
|
||||||
lateinit var INSERTER: ScreenHandlerType<InserterScreenHandler>
|
lateinit var INSERTER: ScreenHandlerType<InserterScreenHandler>
|
||||||
private set
|
private set
|
||||||
lateinit var REDSTONE_EMITTER: ScreenHandlerType<RedstoneEmitterScreenHandler>
|
lateinit var REDSTONE_EMITTER: ScreenHandlerType<RedstoneEmitterScreenHandler>
|
||||||
|
@ -18,6 +22,7 @@ object PhyScreens {
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
TERMINAL = ScreenHandlerRegistry.registerExtended(TerminalBlock.ID, ::TerminalScreenHandler)
|
TERMINAL = ScreenHandlerRegistry.registerExtended(TerminalBlock.ID, ::TerminalScreenHandler)
|
||||||
|
CRAFTING_TERMINAL = ScreenHandlerRegistry.registerExtended(CraftingTerminalBlock.ID, ::CraftingTerminalScreenHandler)
|
||||||
INSERTER = ScreenHandlerRegistry.registerExtended(InserterScreenHandler.ID, ::InserterScreenHandler)
|
INSERTER = ScreenHandlerRegistry.registerExtended(InserterScreenHandler.ID, ::InserterScreenHandler)
|
||||||
REDSTONE_EMITTER = ScreenHandlerRegistry.registerExtended(RedstoneEmitterScreenHandler.ID, ::RedstoneEmitterScreenHandler)
|
REDSTONE_EMITTER = ScreenHandlerRegistry.registerExtended(RedstoneEmitterScreenHandler.ID, ::RedstoneEmitterScreenHandler)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ConsoleItem: Item(Settings().maxCount(1)) {
|
||||||
if (context.world.isClient) {
|
if (context.world.isClient) {
|
||||||
this.openScreen(be)
|
this.openScreen(be)
|
||||||
} else {
|
} else {
|
||||||
be.sync()
|
be.markUpdate()
|
||||||
}
|
}
|
||||||
return ActionResult.SUCCESS
|
return ActionResult.SUCCESS
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class ConsoleItem: Item(Settings().maxCount(1)) {
|
||||||
private fun openScreen(be: DeviceBlockEntity) {
|
private fun openScreen(be: DeviceBlockEntity) {
|
||||||
// val screen = TestCacaoScreen()
|
// val screen = TestCacaoScreen()
|
||||||
val screen = DeviceConsoleScreen(be)
|
val screen = DeviceConsoleScreen(be)
|
||||||
MinecraftClient.getInstance().openScreen(screen)
|
MinecraftClient.getInstance().setScreen(screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,16 @@ import net.shadowfacts.phycon.util.text
|
||||||
*/
|
*/
|
||||||
open class DeviceBlockItem(block: DeviceBlock<*>, settings: Settings = Settings()): BlockItem(block, settings) {
|
open class DeviceBlockItem(block: DeviceBlock<*>, settings: Settings = Settings()): BlockItem(block, settings) {
|
||||||
|
|
||||||
|
private var tooltip = mutableListOf<Text>()
|
||||||
|
|
||||||
|
fun addTooltip(tooltip: Text) {
|
||||||
|
this.tooltip.add(tooltip)
|
||||||
|
}
|
||||||
|
|
||||||
override fun appendTooltip(stack: ItemStack, world: World?, list: MutableList<Text>, context: TooltipContext) {
|
override fun appendTooltip(stack: ItemStack, world: World?, list: MutableList<Text>, context: TooltipContext) {
|
||||||
val beTag = stack.getSubTag("BlockEntityTag")
|
list.addAll(tooltip)
|
||||||
|
|
||||||
|
val beTag = stack.getSubNbt("BlockEntityTag")
|
||||||
if (beTag != null) {
|
if (beTag != null) {
|
||||||
val ip = IPAddress(beTag.getInt("IPAddress"))
|
val ip = IPAddress(beTag.getInt("IPAddress"))
|
||||||
list.add(text {
|
list.add(text {
|
||||||
|
|
|
@ -2,11 +2,14 @@ package net.shadowfacts.phycon.item
|
||||||
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
import net.shadowfacts.phycon.init.PhyBlocks
|
||||||
import net.shadowfacts.phycon.util.CableConnection
|
import net.shadowfacts.phycon.util.CableConnection
|
||||||
|
import kotlin.math.floor
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -18,8 +21,14 @@ class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settin
|
||||||
val hitBlock = hitState.block
|
val hitBlock = hitState.block
|
||||||
if (hitBlock is CableBlock) {
|
if (hitBlock is CableBlock) {
|
||||||
val hitBlockEdge = context.hitPos.getComponentAlongAxis(context.side.axis) % 1 == 0.0
|
val hitBlockEdge = context.hitPos.getComponentAlongAxis(context.side.axis) % 1 == 0.0
|
||||||
|
val hitBlockBeingPlacedIn = floor(context.hitPos.getComponentAlongAxis(context.side.axis)).toInt() == context.blockPos.getComponentAlongAxis(context.side.axis)
|
||||||
|
|
||||||
val placementSide = if (hitBlockEdge) context.side.opposite else context.side
|
val placementSide: Direction =
|
||||||
|
if (hitBlockEdge xor hitBlockBeingPlacedIn) {
|
||||||
|
context.side
|
||||||
|
} else {
|
||||||
|
context.side.opposite
|
||||||
|
}
|
||||||
|
|
||||||
if (hitState[CableBlock.CONNECTIONS[placementSide]] != CableConnection.ON) {
|
if (hitState[CableBlock.CONNECTIONS[placementSide]] != CableConnection.ON) {
|
||||||
var connection = FaceDeviceBlock.FaceCableConnection.NONE
|
var connection = FaceDeviceBlock.FaceCableConnection.NONE
|
||||||
|
|
|
@ -54,12 +54,12 @@ class ScrewdriverItem: Item(Settings().maxCount(1)) {
|
||||||
val be = block.getBlockEntity(context.world, context.blockPos)!!
|
val be = block.getBlockEntity(context.world, context.blockPos)!!
|
||||||
|
|
||||||
val stack = ItemStack(block)
|
val stack = ItemStack(block)
|
||||||
val beTag = stack.getOrCreateSubTag("BlockEntityTag")
|
val beTag = be.createNbt()
|
||||||
be.toTag(beTag)
|
|
||||||
// remove x, y, z entries for stacking purposes
|
// remove x, y, z entries for stacking purposes
|
||||||
beTag.remove("x")
|
beTag.remove("x")
|
||||||
beTag.remove("y")
|
beTag.remove("y")
|
||||||
beTag.remove("z")
|
beTag.remove("z")
|
||||||
|
stack.setSubNbt("BlockEntityTag", beTag)
|
||||||
|
|
||||||
if (block === PhyBlocks.TERMINAL) {
|
if (block === PhyBlocks.TERMINAL) {
|
||||||
// remove the terminal's internal buffer since it drops its items
|
// remove the terminal's internal buffer since it drops its items
|
||||||
|
|
|
@ -3,7 +3,7 @@ package net.shadowfacts.phycon.networking
|
||||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
||||||
import net.fabricmc.fabric.api.networking.v1.PacketSender
|
import net.fabricmc.fabric.api.networking.v1.PacketSender
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.network.Packet
|
import net.minecraft.network.Packet
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.minecraft.server.MinecraftServer
|
import net.minecraft.server.MinecraftServer
|
||||||
|
@ -24,9 +24,9 @@ object C2SConfigureDevice: ServerReceiver {
|
||||||
|
|
||||||
buf.writeIdentifier(be.world!!.registryKey.value)
|
buf.writeIdentifier(be.world!!.registryKey.value)
|
||||||
buf.writeBlockPos(be.pos)
|
buf.writeBlockPos(be.pos)
|
||||||
val tag = CompoundTag()
|
val tag = NbtCompound()
|
||||||
be.writeDeviceConfiguration(tag)
|
be.writeDeviceConfiguration(tag)
|
||||||
buf.writeCompoundTag(tag)
|
buf.writeNbt(tag)
|
||||||
|
|
||||||
return createPacket(buf)
|
return createPacket(buf)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ object C2SConfigureDevice: ServerReceiver {
|
||||||
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
val dimID = buf.readIdentifier()
|
val dimID = buf.readIdentifier()
|
||||||
val pos = buf.readBlockPos()
|
val pos = buf.readBlockPos()
|
||||||
val tag = buf.readCompoundTag() ?: return
|
val tag = buf.readNbt() ?: return
|
||||||
|
|
||||||
server.execute {
|
server.execute {
|
||||||
// todo: check if the player is close enough
|
// todo: check if the player is close enough
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package net.shadowfacts.phycon.networking
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketSender
|
||||||
|
import net.minecraft.network.Packet
|
||||||
|
import net.minecraft.network.PacketByteBuf
|
||||||
|
import net.minecraft.server.MinecraftServer
|
||||||
|
import net.minecraft.server.network.ServerPlayNetworkHandler
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.registry.Registry
|
||||||
|
import net.minecraft.util.registry.RegistryKey
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlockEntity
|
||||||
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreenHandler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
object C2STerminalCraftingButton: ServerReceiver {
|
||||||
|
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "terminal_crafting_button")
|
||||||
|
|
||||||
|
enum class Action {
|
||||||
|
CLEAR_GRID,
|
||||||
|
REQUEST_ONE_MORE,
|
||||||
|
REQUEST_MAX_MORE,
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(terminal: CraftingTerminalBlockEntity, action: Action): Packet<*> {
|
||||||
|
val buf = PacketByteBufs.create()
|
||||||
|
|
||||||
|
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
||||||
|
buf.writeBlockPos(terminal.pos)
|
||||||
|
buf.writeByte(action.ordinal)
|
||||||
|
|
||||||
|
return createPacket(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
|
val dimID = buf.readIdentifier()
|
||||||
|
val pos = buf.readBlockPos()
|
||||||
|
val action = Action.values()[buf.readByte().toInt()]
|
||||||
|
|
||||||
|
server.execute {
|
||||||
|
val key = RegistryKey.of(Registry.WORLD_KEY, dimID)
|
||||||
|
val screenHandler = player.currentScreenHandler as? CraftingTerminalScreenHandler ?: return@execute
|
||||||
|
if (screenHandler.terminal.pos != pos || screenHandler.terminal.world!!.registryKey != key) return@execute
|
||||||
|
|
||||||
|
when (action) {
|
||||||
|
Action.CLEAR_GRID -> screenHandler.clearCraftingGrid()
|
||||||
|
Action.REQUEST_ONE_MORE -> screenHandler.requestMoreCraftingIngredients(1)
|
||||||
|
Action.REQUEST_MAX_MORE -> screenHandler.requestMoreCraftingIngredients(64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ object C2STerminalRequestItem: ServerReceiver {
|
||||||
val amount = buf.readVarInt()
|
val amount = buf.readVarInt()
|
||||||
|
|
||||||
server.execute {
|
server.execute {
|
||||||
val key = RegistryKey.of(Registry.DIMENSION, dimID)
|
val key = RegistryKey.of(Registry.WORLD_KEY, dimID)
|
||||||
val world = server.getWorld(key) ?: return@execute
|
val world = server.getWorld(key) ?: return@execute
|
||||||
val terminal = world.getBlockEntity(pos) as? AbstractTerminalBlockEntity ?: return@execute
|
val terminal = world.getBlockEntity(pos) as? AbstractTerminalBlockEntity ?: return@execute
|
||||||
terminal.requestItem(stack, amount)
|
terminal.requestItem(stack, amount)
|
||||||
|
|
|
@ -29,7 +29,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
|
||||||
buf.writeBlockPos(terminal.pos)
|
buf.writeBlockPos(terminal.pos)
|
||||||
|
|
||||||
buf.writeString(query)
|
buf.writeString(query)
|
||||||
buf.writeCompoundTag(PhysicalConnectivityClient.terminalSettings.toTag())
|
buf.writeNbt(PhysicalConnectivityClient.terminalSettings.toTag())
|
||||||
buf.writeFloat(scrollPosition)
|
buf.writeFloat(scrollPosition)
|
||||||
|
|
||||||
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
||||||
|
@ -40,7 +40,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
|
||||||
val pos = buf.readBlockPos()
|
val pos = buf.readBlockPos()
|
||||||
val query = buf.readString()
|
val query = buf.readString()
|
||||||
val settings = TerminalSettings()
|
val settings = TerminalSettings()
|
||||||
settings.fromTag(buf.readCompoundTag()!!)
|
settings.fromTag(buf.readNbt()!!)
|
||||||
val scrollPosition = buf.readFloat()
|
val scrollPosition = buf.readFloat()
|
||||||
|
|
||||||
server.execute {
|
server.execute {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue