Compare commits

...

9 Commits

119 changed files with 1274 additions and 642 deletions

View File

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

View File

@ -1,19 +1,21 @@
org.gradle.jvmargs=-Xmx1G
org.gradle.daemon=false
minecraft_version=1.16.5
yarn_mappings=1.16.5+build.4
loader_version=0.11.1
minecraft_version=1.18.1
yarn_mappings=1.18.1+build.7
loader_version=0.12.12
mod_version=0.2.0
maven_group=net.shadowfacts
archives_base_name=PhysicalConnectivity
fabric_version=0.30.0+1.16
fabric_kotlin_version=1.4.30+build.2
fabric_version=0.44.0+1.18
fabric_kotlin_version=1.7.1+kotlin.1.6.10
libblockattributes_version=0.8.5
cotton_resources_version=1.7.4
modmenu_version=1.16.8
libblockattributes_version=0.10.0
# cotton_resources_version=1.7.4
modmenu_version=3.0.1
rei_version=7.1.356
mousewheelie_version=1.8.0+mc1.18-pre5
junit_version = 5.4.0

View File

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

@ -1 +1 @@
Subproject commit 1cbaea53d207f1e16c6e5ee2e6bf6e3c1440ac44
Subproject commit abe783ae7ce45ccf296ed7b7e5c1b194e7c560fa

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,46 +1,67 @@
package net.shadowfacts.phycon.plugin.rei
import me.shedaniel.rei.server.ContainerContext
import me.shedaniel.rei.server.ContainerInfo
import me.shedaniel.rei.server.ContainerInfoHandler
import me.shedaniel.rei.server.StackAccessor
import net.fabricmc.api.ModInitializer
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: ModInitializer {
object PhyConPluginCommon: REIServerPlugin, PhyConPlugin {
const val MODID = "phycon_rei"
override fun onInitialize() {
ContainerInfoHandler.registerContainerInfo(Identifier("minecraft", "plugins/crafting"), TerminalInfo)
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))
}
object TerminalInfo: ContainerInfo<CraftingTerminalScreenHandler> {
override fun getContainerClass() = CraftingTerminalScreenHandler::class.java
override fun initializePhyCon(api: PhyConAPI) {
REI_SYNC_KEY = api.registerTerminalSetting(Identifier(MODID, "rei_sync"), REISyncMode.OFF)
}
override fun getCraftingResultSlotIndex(container: CraftingTerminalScreenHandler): Int {
return container.resultSlot.id
class TerminalInfo<D: SimpleGridMenuDisplay>(
private val display: D,
): SimpleGridMenuInfo<CraftingTerminalScreenHandler, D> {
override fun getCraftingResultSlotIndex(menu: CraftingTerminalScreenHandler): Int {
return menu.resultSlot.id
}
override fun getCraftingWidth(container: CraftingTerminalScreenHandler): Int {
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(container: CraftingTerminalScreenHandler): Int {
override fun getCraftingHeight(menu: CraftingTerminalScreenHandler): Int {
return 3
}
override fun getGridStacks(context: ContainerContext<CraftingTerminalScreenHandler>): List<StackAccessor> {
val handler = context.container
return (handler.craftingSlotsStart until handler.craftingSlotsEnd).map(context::getStack)
}
override fun getInventoryStacks(context: ContainerContext<CraftingTerminalScreenHandler>): List<StackAccessor> {
val handler = context.container
val slots = (handler.playerSlotsStart until handler.playerSlotsEnd) + (handler.bufferSlotsStart until handler.bufferSlotsEnd)
return slots.map(context::getStack)
override fun getDisplay(): D {
return display
}
}

View File

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

View File

@ -13,22 +13,26 @@
},
"license": "LGPL-3.0",
"entrypoints": {
"main": [
"client": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginClient"
}
],
"rei": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginClient"
},
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginCommon"
}
],
"client": [
"phycon": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPlugin"
}
],
"rei_plugins": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPlugin"
"value": "net.shadowfacts.phycon.plugin.rei.PhyConPluginCommon"
}
]
},
@ -39,7 +43,7 @@
"fabric": "*",
"fabric-language-kotlin": ">=1.3.50",
"phycon": "*",
"roughlyenoughitems": "^5.0.0"
"roughlyenoughitems": "^7.0.0"
},
"custom": {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -147,11 +147,6 @@ class TabViewController<T: TabViewController.Tab>(
currentTabController.viewWillAppear()
}
override fun viewDidAppear() {
super.viewDidAppear()
currentTabController.viewDidAppear()
}
override fun viewWillDisappear() {
super.viewWillDisappear()
currentTabController.viewWillDisappear()
@ -225,7 +220,6 @@ class TabViewController<T: TabViewController.Tab>(
embedChild(currentTabController, tabVCContainer)
currentTabController.didMoveTo(this)
currentTabController.viewWillAppear()
currentTabController.viewDidAppear()
onTabChange?.invoke(currentTab)

View File

@ -122,12 +122,12 @@ abstract class ViewController {
children.forEach(ViewController::viewWillAppear)
}
/**
* Called immediately after the VC's view has first been displayed on screen.
*/
open fun viewDidAppear() {
children.forEach(ViewController::viewDidAppear)
}
// /**
// * Called immediately after the VC's view has first been displayed on screen.
// */
// open fun 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

View File

@ -100,4 +100,4 @@ class KiwiContext(val solver: Solver) {
fun Solver.dsl(init: KiwiContext.() -> Unit): Solver {
KiwiContext(this).init()
return this
}
}

View File

@ -16,6 +16,7 @@ object DefaultPlugin: PhyConPlugin {
override fun initializePhyCon(api: PhyConAPI) {
SORT_MODE = api.registerTerminalSetting(Identifier(PhysicalConnectivity.MODID, "sort"), SortMode.COUNT_HIGH_FIRST)
SORT_MODE.setPriority(Int.MAX_VALUE)
}
}

View File

@ -2,8 +2,10 @@ package net.shadowfacts.phycon
import net.fabricmc.api.ModInitializer
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.shadowfacts.phycon.api.PhyConPlugin
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyItems
@ -31,6 +33,8 @@ object PhysicalConnectivity: ModInitializer {
registerGlobalReceiver(C2STerminalRequestItem)
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
ItemStorage.SIDED.registerForBlockEntity(P2PReceiverBlockEntity::provideItemStorage, PhyBlockEntities.P2P_RECEIVER)
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
it.initializePhyCon(PhyConAPIImpl)
}

View File

@ -2,15 +2,20 @@ package net.shadowfacts.phycon.block
import net.minecraft.block.Block
import net.minecraft.block.BlockEntityProvider
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.util.math.BlockPos
import net.minecraft.world.BlockView
import net.minecraft.world.World
/**
* @author shadowfacts
*/
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? {
val entity = world.getBlockEntity(pos)
return if (entity != null) {
@ -19,4 +24,4 @@ abstract class BlockWithEntity<T: BlockEntity>(settings: Settings): Block(settin
null
}
}
}
}

View File

@ -1,6 +1,9 @@
package net.shadowfacts.phycon.block
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.util.math.BlockPos
import net.minecraft.util.math.Direction
@ -25,4 +28,14 @@ abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithE
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()
}
}
}
}

View File

@ -1,34 +1,32 @@
package net.shadowfacts.phycon.block
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.nbt.CompoundTag
import net.minecraft.util.Tickable
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
import net.minecraft.util.math.BlockPos
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.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.PacketFrame
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.util.NetworkUtil
import net.shadowfacts.phycon.frame.ARPQueryFrame
import net.shadowfacts.phycon.frame.ARPResponseFrame
import net.shadowfacts.phycon.frame.BasePacketFrame
import net.shadowfacts.phycon.packet.*
import net.shadowfacts.phycon.util.NetworkUtil
import java.util.*
/**
* @author shadowfacts
*/
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
BlockEntityClientSerializable,
Tickable,
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state),
PacketSink,
PacketSource,
Interface {
@ -59,6 +57,9 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
is DeviceRemovedPacket -> {
arpTable.remove(packet.source)
}
is PingPacket -> {
sendPacket(PongPacket(ipAddress, packet.source))
}
}
handle(packet)
}
@ -126,7 +127,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
}
}
override fun tick() {
open fun tick() {
counter++
if (!world!!.isClient) {
@ -148,33 +149,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.putLong("MACAddress", macAddress.address)
}
protected open fun fromCommonTag(tag: CompoundTag) {
protected open fun fromCommonTag(tag: NbtCompound) {
ipAddress = IPAddress(tag.getInt("IPAddress"))
macAddress = MACAddress(tag.getLong("MACAddress"))
}
override fun toTag(tag: CompoundTag): CompoundTag {
override fun writeNbt(tag: NbtCompound) {
super.writeNbt(tag)
toCommonTag(tag)
return super.toTag(tag)
}
override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag)
override fun readNbt(tag: NbtCompound) {
super.readNbt(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)
return tag
}
override fun fromClientTag(tag: CompoundTag) {
fromCommonTag(tag)
open fun fromClientTag(tag: NbtCompound) {
}
fun markUpdate() {
markDirty()
world!!.updateListeners(pos, cachedState, cachedState, 3)
}
fun onBreak() {

View File

@ -42,7 +42,7 @@ class CableBlock(
), NetworkCableBlock {
companion object {
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 SIDE_SHAPES = mapOf<Direction, VoxelShape>(
Direction.DOWN to createCuboidShape(6.0, 0.0, 6.0, 10.0, 6.0, 10.0),

View File

@ -15,6 +15,8 @@ import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import kotlin.math.max
import kotlin.math.min
/**
* @author shadowfacts
@ -57,7 +59,7 @@ class ExtractorBlock: FaceDeviceBlock<ExtractorBlockEntity>(
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) }
}
@ -67,7 +69,7 @@ class ExtractorBlock: FaceDeviceBlock<ExtractorBlockEntity>(
override val faceThickness = 6.0
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) {
if (!world.isClient) {

View File

@ -5,8 +5,10 @@ import alexiil.mc.lib.attributes.Simulation
import alexiil.mc.lib.attributes.item.FixedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes
import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter
import net.minecraft.block.BlockState
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.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities
@ -26,7 +28,7 @@ import kotlin.properties.Delegates
/**
* @author shadowfacts
*/
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
class ExtractorBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.EXTRACTOR, pos, state),
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
ActivationController.ActivatableDevice,
ClientConfigurableDevice {
@ -106,21 +108,21 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
return false
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
writeDeviceConfiguration(tag)
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
loadDeviceConfiguration(tag)
}
override fun writeDeviceConfiguration(tag: CompoundTag) {
override fun writeDeviceConfiguration(tag: NbtCompound) {
tag.putString("ActivationMode", controller.activationMode.name)
}
override fun loadDeviceConfiguration(tag: CompoundTag) {
override fun loadDeviceConfiguration(tag: NbtCompound) {
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
}

View File

@ -25,6 +25,8 @@ import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import java.util.*
import kotlin.math.max
import kotlin.math.min
/**
* @author shadowfacts
@ -66,7 +68,7 @@ class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
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) }
}
@ -76,7 +78,7 @@ class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
override val faceThickness = 6.0
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) {
if (!world.isClient) {
@ -94,7 +96,7 @@ class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
if (!world.isClient) {
val be = getBlockEntity(world, pos)!!
be.sync()
be.markUpdate()
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {

View File

@ -5,8 +5,10 @@ import alexiil.mc.lib.attributes.Simulation
import alexiil.mc.lib.attributes.item.ItemAttributes
import alexiil.mc.lib.attributes.item.ItemInsertable
import alexiil.mc.lib.attributes.item.ItemStackUtil
import net.minecraft.block.BlockState
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.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.block.DeviceBlockEntity
@ -25,7 +27,7 @@ import kotlin.math.min
/**
* @author shadowfacts
*/
class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
class InserterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.INSERTER, pos, state),
ItemStackPacketHandler,
ActivationController.ActivatableDevice,
ClientConfigurableDevice,
@ -132,24 +134,24 @@ class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
currentRequest = null
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(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)
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.putInt("AmountToExtract", amountToExtract)
}
override fun loadDeviceConfiguration(tag: CompoundTag) {
override fun loadDeviceConfiguration(tag: NbtCompound) {
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
amountToExtract = tag.getInt("AmountToExtract")
}

View File

@ -3,6 +3,7 @@ package net.shadowfacts.phycon.block.inserter
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.screen.slot.Slot
@ -44,9 +45,9 @@ class InserterScreen(
amountField = TextFieldWidget(textRenderer, x + 57, y + 24, 80, 9, LiteralText("Amount"))
amountField.text = handler.inserter.amountToExtract.toString()
amountField.setHasBorder(false)
amountField.setDrawsBackground(false)
amountField.isVisible = true
amountField.setSelected(true)
amountField.setTextFieldFocused(true)
amountField.setEditableColor(0xffffff)
amountField.setTextPredicate {
if (it.isEmpty()) {
@ -60,7 +61,7 @@ class InserterScreen(
}
}
}
addChild(amountField)
addDrawableChild(amountField)
}
fun amountUpdated() {
@ -70,16 +71,16 @@ class InserterScreen(
}
}
override fun tick() {
super.tick()
override fun handledScreenTick() {
super.handledScreenTick()
amountField.tick()
}
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
renderBackground(matrixStack)
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
RenderSystem.setShaderTexture(0, BACKGROUND)
val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2
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?) {
super.onMouseClick(slot, invSlot, clickData, slotActionType)
amountField.setSelected(true)
amountField.setTextFieldFocused(true)
}
override fun charTyped(c: Char, i: Int): Boolean {

View File

@ -60,17 +60,17 @@ class InserterScreenHandler(
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
if (slotId == 0) {
if (player.inventory.cursorStack.isEmpty) {
if (cursorStack.isEmpty) {
inserter.stackToExtract = ItemStack.EMPTY
} else {
inserter.stackToExtract = player.inventory.cursorStack.copyWithCount(1)
inserter.stackToExtract = cursorStack.copyWithCount(1)
}
stackToExtractChanged()
}
return super.onSlotClick(slotId, clickData, actionType, player)
super.onSlotClick(slotId, clickData, actionType, player)
}
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {

View File

@ -51,7 +51,7 @@ class MinerBlock: DeviceBlock<MinerBlockEntity>(
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? {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite

View File

@ -7,7 +7,7 @@ import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtCompound
import net.minecraft.server.world.ServerWorld
import net.minecraft.text.TranslatableText
import net.minecraft.util.math.BlockPos
@ -27,7 +27,7 @@ import kotlin.math.min
/**
* @author shadowfacts
*/
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
class MinerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.MINER, pos, state),
NetworkStackProvider,
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion>,
ActivationController.ActivatableDevice,
@ -57,10 +57,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
if (minerMode != MinerMode.ON_DEMAND) {
if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) {
return
}
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
sendPacket(ReadGroupedInventoryPacket(invProxy, ipAddress, packet.source))
}
private fun handleLocateStack(packet: LocateStackPacket) {
@ -156,23 +156,23 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
return minerMode == MinerMode.ON_DEMAND
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
writeDeviceConfiguration(tag)
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
loadDeviceConfiguration(tag)
}
override fun writeDeviceConfiguration(tag: CompoundTag) {
override fun writeDeviceConfiguration(tag: NbtCompound) {
tag.putString("MinerMode", minerMode.name)
tag.putString("ActivationMode", controller.activationMode.name)
tag.putInt("ProviderPriority", providerPriority)
}
override fun loadDeviceConfiguration(tag: CompoundTag) {
override fun loadDeviceConfiguration(tag: NbtCompound) {
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
providerPriority = tag.getInt("ProviderPriority")
@ -181,7 +181,7 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
enum class MinerMode {
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 {
@ -205,7 +205,8 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
if (cachedDrops == null || realState != cachedState || recalculate) {
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)
}
return cachedDrops!!

View File

@ -40,7 +40,7 @@ class InterfaceBlock: FaceDeviceBlock<InterfaceBlockEntity>(
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) {
if (!world.isClient) {

View File

@ -6,7 +6,8 @@ import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes
import net.minecraft.block.BlockState
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.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities
@ -23,7 +24,7 @@ import kotlin.math.min
/**
* @author shadowfacts
*/
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
class InterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.INTERFACE, pos, state),
ItemStackPacketHandler,
NetworkStackProvider,
NetworkStackReceiver,
@ -63,8 +64,11 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
if (packet.kind != RequestInventoryPacket.Kind.GROUPED) {
return
}
getInventory()?.also { inv ->
sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source))
sendPacket(ReadGroupedInventoryPacket(inv, ipAddress, packet.source))
}
}
@ -109,23 +113,23 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
}
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
writeDeviceConfiguration(tag)
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
loadDeviceConfiguration(tag)
}
override fun writeDeviceConfiguration(tag: CompoundTag) {
override fun writeDeviceConfiguration(tag: NbtCompound) {
tag.putInt("ProviderPriority", providerPriority)
tag.putInt("ReceiverPriority", receiverPriority)
tag.putBoolean("SyncPriorities", syncPriorities)
}
override fun loadDeviceConfiguration(tag: CompoundTag) {
override fun loadDeviceConfiguration(tag: NbtCompound) {
providerPriority = tag.getInt("ProviderPriority")
receiverPriority = tag.getInt("ReceiverPriority")
syncPriorities = tag.getBoolean("SyncPriorities")

View File

@ -4,6 +4,9 @@ import alexiil.mc.lib.attributes.AttributeList
import alexiil.mc.lib.attributes.AttributeProvider
import net.minecraft.block.BlockState
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.util.Identifier
import net.minecraft.util.math.BlockPos
@ -40,7 +43,17 @@ class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(
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<*>) {
to.offer(getBlockEntity(world, pos))

View File

@ -1,12 +1,14 @@
package net.shadowfacts.phycon.block.netswitch
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.util.Tickable
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtList
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.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.Interface
@ -25,9 +27,7 @@ import java.util.LinkedList
/**
* @author shadowfacts
*/
class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
BlockEntityClientSerializable,
Tickable {
class SwitchBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(PhyBlockEntities.SWITCH, pos, state) {
companion object {
var SWITCHING_CAPACITY = 256 // 256 packets/tick
@ -82,7 +82,7 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
return NetworkUtil.findConnectedInterface(world!!, pos, side)
}
override fun tick() {
fun tick() {
packetsHandledThisTick = 0
while (delayedPackets.isNotEmpty() && packetsHandledThisTick <= SWITCHING_CAPACITY) {
@ -91,39 +91,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 })
val list = ListTag()
val list = NbtList()
for ((frame, fromItf) in delayedPackets) {
val packet = frame.packet
if (packet !is ItemStackPacket) continue
val compound = CompoundTag()
val compound = NbtCompound()
compound.putInt("FromItfSide", fromItf.side.ordinal)
compound.putInt("SourceIP", packet.source.address)
compound.putInt("DestinationIP", packet.destination.address)
compound.putLong("SourceMAC", frame.source.address)
compound.putLong("DestinationMAC", frame.destination.address)
compound.put("Stack", packet.stack.toTag(CompoundTag()))
compound.put("Stack", packet.stack.writeNbt(NbtCompound()))
list.add(compound)
}
tag.put("DelayedStackPackets", list)
return super.toTag(tag)
}
override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag)
override fun readNbt(tag: NbtCompound) {
super.readNbt(tag)
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
interfaces[i].macAddress = MACAddress(l)
}
tag.getList("DelayedStackPackets", 10).forEach { it ->
val compound = it as CompoundTag
val compound = it as NbtCompound
val fromItfSide = Direction.values()[compound.getInt("FromItfSide")]
val fromItf = interfaces.find { it.side == fromItfSide }!!
val sourceIP = IPAddress(compound.getInt("SourceIP"))
val destinationIP = IPAddress(compound.getInt("DestinationIP"))
val sourceMAC = MACAddress(compound.getLong("SourceMAC"))
val destinationMAC = MACAddress(compound.getLong("DestinationMAC"))
val stack = ItemStack.fromTag(compound.getCompound("Stack"))
val stack = ItemStack.fromNbt(compound.getCompound("Stack"))
if (!stack.isEmpty) {
val packet = ItemStackPacket(stack, sourceIP, destinationIP)
val frame = BasePacketFrame(packet, sourceMAC, destinationMAC)
@ -132,15 +134,14 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
}
}
override fun toClientTag(tag: CompoundTag): CompoundTag {
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
return tag
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
return BlockEntityUpdateS2CPacket.create(this)
}
override fun fromClientTag(tag: CompoundTag) {
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
interfaces[i].macAddress = MACAddress(l)
}
override fun toInitialChunkDataNbt(): NbtCompound {
val tag = NbtCompound()
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
return tag
}
class SwitchInterface(

View File

@ -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)
}

View File

@ -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))
}
}
}

View File

@ -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)
}

View File

@ -0,0 +1,133 @@
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.init.PhyBlockEntities
import net.shadowfacts.phycon.packet.*
import net.shadowfacts.phycon.util.ClientConfigurableDevice
/**
* @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 {
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
var clientObserver: (() -> Unit)? = null
private var isFirstTick = true
// todo: need some way of removing this when there's no network path to the p2p interface
private var targetInventory: Storage<ItemVariant>? = null
override fun handle(packet: Packet) {
when (packet) {
is PongPacket -> if (packet.source == target) status = Status.OK
is ReadItemStoragePacket -> targetInventory = packet.inventory
is DeviceRemovedPacket -> if (packet.source == target) targetInventory = null
}
}
override fun tick() {
super.tick()
if (isFirstTick) {
isFirstTick = false
updateStatus()
}
}
fun getTargetInventory(): Storage<ItemVariant>? {
if (target == null) {
return null
}
if (targetInventory == null) {
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.SIDED, ipAddress, target!!))
}
return targetInventory
}
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()
}
}

View File

@ -44,7 +44,7 @@ class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(
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 {
val state = super.getPlacementState(context)

View File

@ -1,6 +1,8 @@
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.util.IPAddress
import net.shadowfacts.phycon.init.PhyBlockEntities
@ -12,7 +14,7 @@ import net.shadowfacts.phycon.util.RedstoneMode
/**
* @author shadowfacts
*/
class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER),
class RedstoneControllerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER, pos, state),
ClientConfigurableDevice {
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)
writeDeviceConfiguration(tag)
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
loadDeviceConfiguration(tag)
}
override fun writeDeviceConfiguration(tag: CompoundTag) {
override fun writeDeviceConfiguration(tag: NbtCompound) {
tag.putIntArray("ManagedDevices", managedDevices.mapNotNull { it?.address })
tag.putString("RedstoneMode", redstoneMode.name)
}
override fun loadDeviceConfiguration(tag: CompoundTag) {
override fun loadDeviceConfiguration(tag: NbtCompound) {
val addresses = tag.getIntArray("ManagedDevices")
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
redstoneMode = RedstoneMode.valueOf(tag.getString("RedstoneMode"))

View File

@ -45,7 +45,7 @@ class RedstoneEmitterBlock: FaceDeviceBlock<RedstoneEmitterBlockEntity>(
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 {
return true
@ -67,7 +67,7 @@ class RedstoneEmitterBlock: FaceDeviceBlock<RedstoneEmitterBlockEntity>(
if (!world.isClient) {
val be = getBlockEntity(world, pos)!!
be.sync()
be.markUpdate()
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {

View File

@ -1,16 +1,18 @@
package net.shadowfacts.phycon.block.redstone_emitter
import alexiil.mc.lib.attributes.item.GroupedItemInvView
import net.minecraft.block.BlockState
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtCompound
import net.minecraft.text.TranslatableText
import net.minecraft.util.math.BlockPos
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.init.PhyBlockEntities
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.util.ClientConfigurableDevice
import net.shadowfacts.phycon.util.GhostInv
@ -19,7 +21,7 @@ import kotlin.math.round
/**
* @author shadowfacts
*/
class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER),
class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER, pos, state),
ClientConfigurableDevice,
GhostInv {
@ -40,12 +42,12 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
override fun handle(packet: Packet) {
when (packet) {
is ReadInventoryPacket -> handleReadInventory(packet)
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
}
}
private fun handleReadInventory(packet: ReadInventoryPacket) {
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
inventoryCache[packet.source] = packet.inventory
recalculateRedstone()
}
@ -68,7 +70,7 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
}
private fun updateInventories() {
sendPacket(RequestInventoryPacket(ipAddress))
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
}
private fun recalculateRedstone() {
@ -100,26 +102,26 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
world!!.updateNeighborsAlways(pos.offset(cachedState[FaceDeviceBlock.FACING]), cachedState.block)
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
tag.putInt("CachedEmittedPower", cachedEmittedPower)
tag.put("StackToMonitor", stackToMonitor.toTag(CompoundTag()))
tag.put("StackToMonitor", stackToMonitor.writeNbt(NbtCompound()))
writeDeviceConfiguration(tag)
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
cachedEmittedPower = tag.getInt("CachedEmittedPower")
stackToMonitor = ItemStack.fromTag(tag.getCompound("StackToMonitor"))
stackToMonitor = ItemStack.fromNbt(tag.getCompound("StackToMonitor"))
loadDeviceConfiguration(tag)
}
override fun writeDeviceConfiguration(tag: CompoundTag) {
override fun writeDeviceConfiguration(tag: NbtCompound) {
tag.putInt("MaxAmount", maxAmount)
tag.putString("Mode", mode.name)
}
override fun loadDeviceConfiguration(tag: CompoundTag) {
override fun loadDeviceConfiguration(tag: NbtCompound) {
maxAmount = tag.getInt("MaxAmount")
mode = Mode.valueOf(tag.getString("Mode"))
}
@ -127,7 +129,7 @@ class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EM
enum class Mode {
ANALOG, DIGITAL;
val friendlyName = TranslatableText("gui.phycon.redstone_emitter_mode.${name.toLowerCase()}")
val friendlyName = TranslatableText("gui.phycon.redstone_emitter_mode.${name.lowercase()}")
}
}

View File

@ -2,6 +2,7 @@ package net.shadowfacts.phycon.block.redstone_emitter
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.text.Text
@ -49,8 +50,8 @@ class RedstoneEmitterScreen(
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
super.drawBackground(matrixStack, delta, mouseX, mouseY)
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
RenderSystem.setShaderTexture(0, BACKGROUND)
val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)

View File

@ -55,16 +55,16 @@ class RedstoneEmitterScreenHandler(
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
if (slotId == 0) {
if (player.inventory.cursorStack.isEmpty) {
if (cursorStack.isEmpty) {
emitter.stackToMonitor = ItemStack.EMPTY
} 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 {

View File

@ -3,42 +3,34 @@ package net.shadowfacts.phycon.block.terminal
import alexiil.mc.lib.attributes.item.GroupedItemInvView
import alexiil.mc.lib.attributes.item.ItemStackCollections
import alexiil.mc.lib.attributes.item.ItemStackUtil
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.InventoryChangedListener
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.TranslatableText
import net.minecraft.nbt.NbtCompound
import net.minecraft.util.ItemScatterer
import net.minecraft.util.Tickable
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.util.NetworkUtil
import net.shadowfacts.phycon.component.*
import net.shadowfacts.phycon.packet.*
import net.shadowfacts.phycon.util.NetworkUtil
import java.lang.ref.WeakReference
import java.util.*
import java.util.function.IntBinaryOperator
import kotlin.math.min
import kotlin.properties.Delegates
/**
* @author shadowfacts
*/
abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBlockEntity(type),
abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): DeviceBlockEntity(type, pos, state),
InventoryChangedListener,
BlockEntityClientSerializable,
Tickable,
ItemStackPacketHandler,
NetworkStackDispatcher<AbstractTerminalBlockEntity.PendingInsertion> {
@ -78,7 +70,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
override fun handle(packet: Packet) {
when (packet) {
is ReadInventoryPacket -> handleReadInventory(packet)
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
is StackLocationPacket -> handleStackLocation(packet)
is ItemStackPacket -> handleItemStack(packet)
@ -86,7 +78,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
}
}
private fun handleReadInventory(packet: ReadInventoryPacket) {
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
inventoryCache[packet.source] = packet.inventory
updateAndSync()
}
@ -129,7 +121,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
protected fun updateAndSync() {
updateNetItems()
// syncs the internal buffer to the client
sync()
markUpdate()
// syncs the open container (if any) to the client
netItemObserver?.get()?.netItemsChanged()
}
@ -139,7 +131,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
for (inventory in inventoryCache.values) {
for (stack in inventory.storedStacks) {
val amount = inventory.getAmount(stack)
cachedNetItems.mergeInt(stack, amount) { a, b -> a + b }
cachedNetItems.mergeInt(stack, amount, IntBinaryOperator { a, b -> a + b })
}
}
}
@ -225,8 +217,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
override fun onInventoryChanged(inv: Inventory) {
if (inv == internalBuffer && world != null && !world!!.isClient) {
markDirty()
sync()
markUpdate()
}
}
@ -234,12 +225,12 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>): DeviceBloc
ItemScatterer.spawn(world, pos, internalBuffer)
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
tag.put("InternalBuffer", internalBuffer.toTag())
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
}

View File

@ -4,7 +4,7 @@ import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawableHelper
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.VertexConsumerProvider
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.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.LiteralText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.shadowfacts.cacao.CacaoHandledScreen
@ -22,7 +21,6 @@ import net.shadowfacts.phycon.networking.C2STerminalRequestItem
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
import java.math.RoundingMode
import java.text.DecimalFormat
import java.util.LinkedList
import kotlin.math.ceil
import kotlin.math.min
@ -37,12 +35,13 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
val terminalBackgroundHeight: Int,
): CacaoHandledScreen<T>(handler, playerInv, title) {
companion object {
private val clickHandlers = LinkedList<AbstractTerminalScreen<*, *>.(Double, Double, Int) -> Boolean?>()
interface SearchQueryListener {
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
@ -50,7 +49,15 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
val terminalVC: AbstractTerminalViewController<*, *, *>
var amountVC: TerminalRequestAmountViewController? = null
private var prevSearchQuery = ""
var searchQuery = ""
set(value) {
field = value
if (prevSearchQuery != value) {
searchQueryListener?.terminalSearchQueryChanged(value)
}
prevSearchQuery = value
}
var scrollPosition = 0.0
init {
@ -100,7 +107,7 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
private val DECIMAL_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 s = when {
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
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)
val scale = 2 / 3f
matrixStack.scale(scale, scale, 1.0f)
val immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().buffer)
val textX = (1 / scale * 18) - textRenderer.getWidth(s).toFloat() - 3
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()
matrixStack.pop()
}
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) {
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(backgroundTexture)
RenderSystem.setShader(GameRenderer::getPositionTexColorShader)
RenderSystem.setShaderTexture(0, backgroundTexture)
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
}
override fun tick() {
super.tick()
override fun handledScreenTick() {
super.handledScreenTick()
if (amountVC != null) {
amountVC!!.field.tick()
} else {
terminalVC.searchField.tick()
}
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
for (handler in clickHandlers) {
val res = handler(mouseX, mouseY, button)
if (res != null) {
return res
}
val newSearchQuery = searchQueryListener?.requestTerminalSearchFieldUpdate()
if (newSearchQuery != null && searchQuery != newSearchQuery) {
searchQuery = newSearchQuery
terminalVC.searchField.text = newSearchQuery
requestUpdatedItems()
}
return super.mouseClicked(mouseX, mouseY, button)
}
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
super.onMouseClick(slot, invSlot, clickData, type)
if (slot != null && !slot.stack.isEmpty && handler.isNetworkSlot(slot.id) && playerInventory.cursorStack.isEmpty) {
if (slot != null && !slot.stack.isEmpty && handler.isNetworkSlot(slot.id) && handler.cursorStack.isEmpty) {
val stack = slot.stack
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 getFocused(): Element? {
return if (windows.last().firstResponder != null) {
fakeFocusedElement
} else {
null
override fun setFocused(element: Element?) {
super.setFocused(element)
// so that when something else (e.g., REI) steals focus and calls setFocused(null) on us, any first responder resigns
if (element == null) {
windows.last().firstResponder?.resignFirstResponder()
}
}

View File

@ -170,16 +170,16 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
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)) {
// 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
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)
}
}
return super.onSlotClick(slotId, clickData, actionType, player)
super.onSlotClick(slotId, clickData, actionType, player)
}
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
@ -227,7 +227,7 @@ abstract class AbstractTerminalScreenHandler<T: AbstractTerminalBlockEntity>(
slot.markDirty()
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 toMove = min(maxToMove, stack.count)
slotStack.increment(toMove)

View File

@ -100,13 +100,12 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
handler = ::searchFieldChanged
drawBackground = false
}
searchField.becomeFirstResponder()
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
val settingsStack = view.addSubview(StackView(Axis.VERTICAL, spacing = 2.0))
settingsView = settingsStack
TerminalSettings.allKeys.forEach { key ->
TerminalSettings.allKeys.sortedByDescending { it.priority }.forEach { key ->
val button = SettingButton(key)
button.handler = { settingsChanged() }
settingsStack.addArrangedSubview(button)
@ -137,6 +136,12 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
}
}
override fun viewWillAppear() {
super.viewWillAppear()
searchField.becomeFirstResponder()
}
private fun searchFieldChanged(field: TextField) {
screen.searchQuery = field.text
screen.requestUpdatedItems()

View File

@ -1,6 +1,8 @@
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
@ -13,6 +15,6 @@ class CraftingTerminalBlock: AbstractTerminalBlock<CraftingTerminalBlockEntity>(
val ID = Identifier(PhysicalConnectivity.MODID, "crafting_terminal")
}
override fun createBlockEntity(world: BlockView) = CraftingTerminalBlockEntity()
override fun createBlockEntity(pos: BlockPos, state: BlockState) = CraftingTerminalBlockEntity(pos, state)
}

View File

@ -2,19 +2,18 @@ package net.shadowfacts.phycon.block.terminal
import alexiil.mc.lib.attributes.item.ItemStackCollections
import alexiil.mc.lib.attributes.item.ItemStackUtil
import it.unimi.dsi.fastutil.objects.Object2IntMap
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.CraftingInventory
import net.minecraft.inventory.SimpleInventory
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.Text
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
@ -27,7 +26,7 @@ import kotlin.math.min
/**
* @author shadowfacts
*/
class CraftingTerminalBlockEntity: AbstractTerminalBlockEntity(PhyBlockEntities.CRAFTING_TERMINAL) {
class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlockEntity(PhyBlockEntities.CRAFTING_TERMINAL, pos, state) {
val craftingInv = SimpleInventory(9)
@ -38,7 +37,7 @@ class CraftingTerminalBlockEntity: AbstractTerminalBlockEntity(PhyBlockEntities.
updateAndSync()
inventoryCache.clear()
sendPacket(RequestInventoryPacket(ipAddress))
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
return CraftingTerminalScreenHandler(syncId, playerInv, this@CraftingTerminalBlockEntity)
@ -119,12 +118,12 @@ class CraftingTerminalBlockEntity: AbstractTerminalBlockEntity(PhyBlockEntities.
}
}
override fun toCommonTag(tag: CompoundTag) {
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
tag.put("CraftingInv", craftingInv.toTag())
}
override fun fromCommonTag(tag: CompoundTag) {
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
craftingInv.fromTag(tag.getList("CraftingInv", 10))
}

View File

@ -1,6 +1,7 @@
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
@ -34,13 +35,13 @@ class CraftingTerminalScreen(
}
override fun drawBackgroundTexture(matrixStack: MatrixStack) {
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND_1)
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)
client!!.textureManager.bindTexture(BACKGROUND_2)
RenderSystem.setShaderTexture(0, BACKGROUND_2)
drawTexture(matrixStack, x + 256, y, 0, 0, 3, 252)
}

View File

@ -8,7 +8,7 @@ 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.RecipeFinder
import net.minecraft.recipe.RecipeMatcher
import net.minecraft.recipe.RecipeType
import net.minecraft.screen.slot.CraftingResultSlot
import net.minecraft.screen.slot.Slot
@ -73,7 +73,7 @@ class CraftingTerminalScreenHandler(
ItemStack.EMPTY
}
result.setStack(0, resultStack)
player.networkHandler.sendPacket(ScreenHandlerSlotUpdateS2CPacket(syncId, resultSlot.id, resultStack))
player.networkHandler.sendPacket(ScreenHandlerSlotUpdateS2CPacket(syncId, nextRevision(), resultSlot.id, resultStack))
}
}
@ -105,7 +105,7 @@ class CraftingTerminalScreenHandler(
if (!insertItem(craftingResult, playerSlotsStart, playerSlotsEnd, true)) {
return ItemStack.EMPTY
}
resultSlot.onStackChanged(craftingResult, originalResult)
resultSlot.onQuickTransfer(craftingResult, originalResult)
if (craftingResult.isEmpty) {
resultSlot.stack = ItemStack.EMPTY
@ -115,8 +115,8 @@ class CraftingTerminalScreenHandler(
return ItemStack.EMPTY
}
val taken = resultSlot.onTakeItem(player, craftingResult)
player.dropItem(taken, false)
resultSlot.onTakeItem(player, craftingResult)
player.dropItem(craftingResult, false)
return originalResult
} else {
@ -157,7 +157,7 @@ class CraftingTerminalScreenHandler(
backing.clear()
}
override fun provideRecipeInputs(finder: RecipeFinder) {
override fun provideRecipeInputs(finder: RecipeMatcher) {
TODO()
}
}

View File

@ -1,7 +1,8 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.block.BlockState
import net.minecraft.util.Identifier
import net.minecraft.world.BlockView
import net.minecraft.util.math.BlockPos
import net.shadowfacts.phycon.PhysicalConnectivity
/**
@ -13,6 +14,6 @@ class TerminalBlock: AbstractTerminalBlock<TerminalBlockEntity>() {
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
}
override fun createBlockEntity(world: BlockView) = TerminalBlockEntity()
override fun createBlockEntity(pos: BlockPos, state: BlockState) = TerminalBlockEntity(pos, state)
}

View File

@ -1,26 +1,28 @@
package net.shadowfacts.phycon.block.terminal
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.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.RequestInventoryPacket
/**
* @author shadowfacts
*/
class TerminalBlockEntity: AbstractTerminalBlockEntity(PhyBlockEntities.TERMINAL) {
class TerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlockEntity(PhyBlockEntities.TERMINAL, pos, state) {
override fun onActivate(player: PlayerEntity) {
if (!world!!.isClient) {
updateAndSync()
inventoryCache.clear()
sendPacket(RequestInventoryPacket(ipAddress))
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)

View File

@ -3,8 +3,8 @@ package net.shadowfacts.phycon.block.terminal
import alexiil.mc.lib.attributes.item.ItemStackUtil
import net.minecraft.inventory.SimpleInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.IntArrayTag
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtIntArray
import net.shadowfacts.phycon.util.fromTag
import net.shadowfacts.phycon.util.toTag
import kotlin.math.min
@ -21,14 +21,14 @@ class TerminalBufferInventory(size: Int): SimpleInventory(size) {
var modes = Array(size) { Mode.UNASSIGNED }
private set
fun toTag(): CompoundTag {
val compound = CompoundTag()
fun toTag(): NbtCompound {
val compound = NbtCompound()
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
}
fun fromTag(tag: CompoundTag) {
fun fromTag(tag: NbtCompound) {
val inventory = tag.getList("Inventory", 10)
(this as SimpleInventory).fromTag(inventory)
tag.getIntArray("Modes").forEachIndexed { i, it -> modes[i] = Mode.values()[it] }

View File

@ -25,6 +25,10 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
val EXTRACTOR_SIDE = Identifier(PhysicalConnectivity.MODID, "block/extractor_side")
val INSERTER = Identifier(PhysicalConnectivity.MODID, "block/inserter")
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 {
Identifier(PhysicalConnectivity.MODID, "block/cable/${it.getName()}") to it
@ -38,6 +42,8 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
EXTRACTOR -> SimpleFaceDeviceModel(EXTRACTOR_SIDE)
INSERTER -> SimpleFaceDeviceModel(INSERTER_SIDE)
P2P_INTERFACE -> SimpleFaceDeviceModel(P2P_INTERFACE_SIDE)
P2P_RECEIVER -> SimpleFaceDeviceModel(P2P_RECEIVER_SIDE)
in CABLES -> ColoredCableModel(CABLES[resourceId]!!)
else -> null
}

View File

@ -6,6 +6,7 @@ import net.minecraft.client.render.model.*
import net.minecraft.client.texture.Sprite
import net.minecraft.client.texture.SpriteAtlasTexture
import net.minecraft.client.util.SpriteIdentifier
import net.minecraft.screen.PlayerScreenHandler
import net.minecraft.util.DyeColor
import net.minecraft.util.Identifier
import net.minecraft.util.math.Direction
@ -85,7 +86,7 @@ class ColoredCableModel(
rotationContainer: ModelBakeSettings,
modelId: Identifier
): 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) ->
this.side[side.ordinal] = loader.bakeRecoloredCable(SIDE, rot, textureGetter, color)
@ -260,7 +261,7 @@ class ColoredCableModel(
override fun isBuiltin() = false
override fun getSprite() = centerSprite
override fun getParticleSprite() = centerSprite
override fun getTransformation() = null

View File

@ -120,9 +120,9 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
val sideQuads = getSideModel(state)?.getQuads(state, face, random) ?: listOf()
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) {
interfaceCableCap[color]!![facing.ordinal]?.getQuads(state, face, random) ?: listOf()
interfaceCableCap[color]!![facing.ordinal].getQuads(state, face, random) ?: listOf()
} else {
val model = when (facing) {
Direction.DOWN -> when (connection) {
@ -183,7 +183,7 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
override fun isBuiltin() = false
abstract override fun getSprite(): Sprite
abstract override fun getParticleSprite(): Sprite
override fun getTransformation() = null

View File

@ -40,8 +40,8 @@ object RedstoneControllerModel: FaceDeviceModel() {
}
}
override fun getSprite(): Sprite {
return offModels.first()!!.sprite
override fun getParticleSprite(): Sprite {
return offModels.first()!!.particleSprite
}
}

View File

@ -13,6 +13,7 @@ import net.minecraft.client.texture.Sprite
import net.minecraft.client.texture.SpriteAtlasTexture
import net.minecraft.client.util.SpriteIdentifier
import net.minecraft.item.ItemStack
import net.minecraft.screen.PlayerScreenHandler
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
@ -32,10 +33,10 @@ class ScreenDeviceModel(
): UnbakedModel, BakedModel, FabricBakedModel {
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(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, screenTexture)
private val screenTexture = SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, screenTexture)
private lateinit var meshes: Array<Mesh>
private lateinit var screenSprite: Sprite
@ -171,7 +172,7 @@ class ScreenDeviceModel(
override fun isBuiltin() = false
override fun getSprite() = screenSprite
override fun getParticleSprite() = screenSprite
override fun getTransformation() = null

View File

@ -35,7 +35,7 @@ class SimpleFaceDeviceModel(
return sideModels[state[FaceDeviceBlock.COLOR]]!![state[FaceDeviceBlock.FACING].ordinal]
}
override fun getSprite(): Sprite {
return sideModels[DyeColor.BLACK]!!.first().sprite
override fun getParticleSprite(): Sprite {
return sideModels[DyeColor.BLACK]!!.first().particleSprite
}
}

View File

@ -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()
}
}

View File

@ -18,7 +18,7 @@ class ScrollTrackView(
): View() {
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_HEIGHT = 15.0
}
@ -50,16 +50,16 @@ class ScrollTrackView(
})
}
override fun mouseDragged(point: Point, delta: Point, mouseButton: MouseButton): Boolean {
if (grabbedY == null && point !in thumbView.frame) {
val newCenter = MathHelper.clamp(point.y, THUMB_HEIGHT / 2, frame.height - THUMB_HEIGHT / 2)
override fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
if (grabbedY == null && startPoint !in thumbView.frame) {
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)
}
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)
scrollPositionChanged(this)

View File

@ -14,6 +14,7 @@ import net.shadowfacts.cacao.window.Window
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.block.DeviceBlockEntity
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_emitter.RedstoneEmitterBlockEntity
import net.shadowfacts.phycon.component.ActivationController
@ -90,6 +91,15 @@ class DeviceConsoleScreen(
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)

View File

@ -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)
}
}
}

View File

@ -7,8 +7,8 @@ import net.shadowfacts.phycon.api.util.MACAddress
* @author shadowfacts
*/
open class BaseFrame(
@JvmField private val source: MACAddress,
@JvmField private val destination: MACAddress
private val source: MACAddress,
private val destination: MACAddress
): EthernetFrame {
override fun getSource() = source
override fun getDestination() = destination

View File

@ -8,7 +8,7 @@ import net.shadowfacts.phycon.api.util.MACAddress
* @author shadowfacts
*/
class BasePacketFrame(
@JvmField private val packet: Packet,
private val packet: Packet,
source: MACAddress,
destination: MACAddress,
): BaseFrame(source, destination), PacketFrame {

View File

@ -1,9 +1,11 @@
package net.shadowfacts.phycon.init
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity
@ -15,6 +17,10 @@ import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
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.RedstoneControllerBlockEntity
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
@ -38,8 +44,10 @@ object PhyBlockEntities {
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
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)
}
@ -53,6 +61,8 @@ object PhyBlockEntities {
register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
register(P2PReceiverBlock.ID, P2P_RECEIVER)
}
private fun register(id: Identifier, type: BlockEntityType<*>) {

View File

@ -11,6 +11,8 @@ import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
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_emitter.RedstoneEmitterBlock
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
@ -32,6 +34,8 @@ object PhyBlocks {
val MINER = MinerBlock()
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
val REDSTONE_EMITTER = RedstoneEmitterBlock()
val P2P_INTERFACE = P2PInterfaceBlock()
val P2P_RECEIVER = P2PReceiverBlock()
fun init() {
for ((color, block) in CABLES) {
@ -47,6 +51,8 @@ object PhyBlocks {
register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
register(P2PReceiverBlock.ID, P2P_RECEIVER)
}
private fun register(id: Identifier, block: Block) {

View File

@ -12,12 +12,15 @@ import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
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_emitter.RedstoneEmitterBlock
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
import net.shadowfacts.phycon.block.terminal.TerminalBlock
import net.shadowfacts.phycon.item.DeviceBlockItem
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
import net.shadowfacts.phycon.util.text
/**
* @author shadowfacts
@ -37,6 +40,8 @@ object PhyItems {
val MINER = DeviceBlockItem(PhyBlocks.MINER, Item.Settings())
val REDSTONE_CONTROLLER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, 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 CONSOLE = ConsoleItem()
@ -61,6 +66,18 @@ object PhyItems {
register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
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(ConsoleItem.ID, CONSOLE)

View File

@ -27,7 +27,7 @@ class ConsoleItem: Item(Settings().maxCount(1)) {
if (context.world.isClient) {
this.openScreen(be)
} else {
be.sync()
be.markUpdate()
}
return ActionResult.SUCCESS
}
@ -38,7 +38,7 @@ class ConsoleItem: Item(Settings().maxCount(1)) {
private fun openScreen(be: DeviceBlockEntity) {
// val screen = TestCacaoScreen()
val screen = DeviceConsoleScreen(be)
MinecraftClient.getInstance().openScreen(screen)
MinecraftClient.getInstance().setScreen(screen)
}
}

View File

@ -14,8 +14,16 @@ import net.shadowfacts.phycon.util.text
*/
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) {
val beTag = stack.getSubTag("BlockEntityTag")
list.addAll(tooltip)
val beTag = stack.getSubNbt("BlockEntityTag")
if (beTag != null) {
val ip = IPAddress(beTag.getInt("IPAddress"))
list.add(text {

View File

@ -2,11 +2,14 @@ package net.shadowfacts.phycon.item
import net.minecraft.block.BlockState
import net.minecraft.item.ItemPlacementContext
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.util.CableConnection
import kotlin.math.floor
import kotlin.math.roundToInt
/**
* @author shadowfacts
@ -18,8 +21,14 @@ class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settin
val hitBlock = hitState.block
if (hitBlock is CableBlock) {
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) {
var connection = FaceDeviceBlock.FaceCableConnection.NONE

View File

@ -54,12 +54,12 @@ class ScrewdriverItem: Item(Settings().maxCount(1)) {
val be = block.getBlockEntity(context.world, context.blockPos)!!
val stack = ItemStack(block)
val beTag = stack.getOrCreateSubTag("BlockEntityTag")
be.toTag(beTag)
val beTag = be.createNbt()
// remove x, y, z entries for stacking purposes
beTag.remove("x")
beTag.remove("y")
beTag.remove("z")
stack.setSubNbt("BlockEntityTag", beTag)
if (block === PhyBlocks.TERMINAL) {
// remove the terminal's internal buffer since it drops its items

View File

@ -3,7 +3,7 @@ package net.shadowfacts.phycon.networking
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.PacketSender
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.PacketByteBuf
import net.minecraft.server.MinecraftServer
@ -24,9 +24,9 @@ object C2SConfigureDevice: ServerReceiver {
buf.writeIdentifier(be.world!!.registryKey.value)
buf.writeBlockPos(be.pos)
val tag = CompoundTag()
val tag = NbtCompound()
be.writeDeviceConfiguration(tag)
buf.writeCompoundTag(tag)
buf.writeNbt(tag)
return createPacket(buf)
}
@ -34,7 +34,7 @@ object C2SConfigureDevice: ServerReceiver {
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
val dimID = buf.readIdentifier()
val pos = buf.readBlockPos()
val tag = buf.readCompoundTag() ?: return
val tag = buf.readNbt() ?: return
server.execute {
// todo: check if the player is close enough

View File

@ -42,7 +42,7 @@ object C2STerminalCraftingButton: ServerReceiver {
val action = Action.values()[buf.readByte().toInt()]
server.execute {
val key = RegistryKey.of(Registry.DIMENSION, dimID)
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

View File

@ -45,7 +45,7 @@ object C2STerminalRequestItem: ServerReceiver {
val amount = buf.readVarInt()
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 terminal = world.getBlockEntity(pos) as? AbstractTerminalBlockEntity ?: return@execute
terminal.requestItem(stack, amount)

View File

@ -29,7 +29,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
buf.writeBlockPos(terminal.pos)
buf.writeString(query)
buf.writeCompoundTag(PhysicalConnectivityClient.terminalSettings.toTag())
buf.writeNbt(PhysicalConnectivityClient.terminalSettings.toTag())
buf.writeFloat(scrollPosition)
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
@ -40,7 +40,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
val pos = buf.readBlockPos()
val query = buf.readString()
val settings = TerminalSettings()
settings.fromTag(buf.readCompoundTag()!!)
settings.fromTag(buf.readNbt()!!)
val scrollPosition = buf.readFloat()
server.execute {

View File

@ -33,7 +33,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
}
buf.writeString(query)
buf.writeCompoundTag(settings.toTag())
buf.writeNbt(settings.toTag())
buf.writeFloat(scrollPosition)
buf.writeInt(totalEntries)
@ -49,7 +49,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
entries.add(AbstractTerminalScreenHandler.Entry(buf.readItemStackWithoutCount(), buf.readVarInt()))
}
val query = buf.readString()
PhysicalConnectivityClient.terminalSettings.fromTag(buf.readCompoundTag()!!)
PhysicalConnectivityClient.terminalSettings.fromTag(buf.readNbt()!!)
val scrollPosition = buf.readFloat()
val totalEntries = buf.readInt()

View File

@ -7,8 +7,8 @@ import net.shadowfacts.phycon.api.util.IPAddress
* @author shadowfacts
*/
abstract class BasePacket(
@JvmField private val source: IPAddress,
@JvmField private val destination: IPAddress
private val source: IPAddress,
private val destination: IPAddress
): Packet {
override fun getSource() = source

View File

@ -0,0 +1,10 @@
package net.shadowfacts.phycon.packet
import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class PingPacket(source: IPAddress, destination: IPAddress): BasePacket(source, destination)
class PongPacket(source: IPAddress, destination: IPAddress): BasePacket(source, destination)

View File

@ -6,7 +6,7 @@ import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class ReadInventoryPacket(
class ReadGroupedInventoryPacket(
val inventory: GroupedItemInvView,
source: IPAddress,
destination: IPAddress

View File

@ -0,0 +1,14 @@
package net.shadowfacts.phycon.packet
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class ReadItemStoragePacket(
val inventory: Storage<ItemVariant>,
source: IPAddress,
destination: IPAddress
): BasePacket(source, destination)

View File

@ -5,4 +5,12 @@ import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class RequestInventoryPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination)
class RequestInventoryPacket(
val kind: Kind,
source: IPAddress,
destination: IPAddress = IPAddress.BROADCAST
): BasePacket(source, destination) {
enum class Kind {
GROUPED, SIDED
}
}

View File

@ -11,5 +11,5 @@ enum class ActivationMode: RotatableEnum, FriendlyNameable {
MANAGED;
override val friendlyName: Text
get() = TranslatableText("gui.phycon.activation_mode.${name.toLowerCase()}")
get() = TranslatableText("gui.phycon.activation_mode.${name.lowercase()}")
}

Some files were not shown because too many files have changed in this diff Show More