diff --git a/.idea/scopes/Catalyx_Source.xml b/.idea/scopes/Catalyx_Source.xml new file mode 100644 index 0000000..196bc63 --- /dev/null +++ b/.idea/scopes/Catalyx_Source.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/README.md b/README.md index 13c525c..eec9b58 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ link(shield("License", "License", "LGPL-3.0", "blue"), "{{mod_url}}/blob/master/ "{{mod_description}}".replace("Kotlin", link("Kotlin", "https://kotlinlang.org/")).replace("Ender-Development's mods", link("Ender-Development's mods", "https://www.curseforge.com/members/enderdevelopment/projects")) ].join("\n") --> -[![Kotlin](https://img.shields.io/badge/Kotlin-2.2.20-blue.svg)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/Kotlin-2.3.0-blue.svg)](https://kotlinlang.org/) [![Maven artifact](https://img.shields.io/badge/Maven-org.ender__development%3Acatalyx-blue.svg)](https://maven.ender-development.org/org/ender_development/catalyx/) [![Version](https://img.shields.io/badge/Version-0.1.0-blue.svg)](https://github.com/Ender-Development/Catalyx/commits/master) [![License](https://img.shields.io/badge/License-LGPL--3.0-blue.svg)](https://github.com/Ender-Development/Catalyx/blob/master/LICENSE) diff --git a/build.gradle.kts b/build.gradle.kts index 9dabfa9..fc5999f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,6 +22,7 @@ plugins { id("catalyx.propsync") id("catalyx.buildfilesync") id("catalyx.referencecreator") apply false + id("catalyx.ijscopecreator") id("java") id("java-library") id("maven-publish") @@ -62,7 +63,14 @@ checkSubPropertiesExist("use_groovyscript", "groovyscript_version") checkSubPropertiesExist("use_hei", "hei_version") checkSubPropertiesExist("use_top", "top_version") -kotlin { jvmToolchain(8) } +kotlin { + jvmToolchain(8) + compilerOptions { + freeCompilerArgs.add("-Xexplicit-backing-fields") + freeCompilerArgs.add("-Xcontext-sensitive-resolution") + extraWarnings.set(true) + } +} minecraft { mcVersion = propertyString("minecraft_version") @@ -244,8 +252,8 @@ tasks.withType { if (propertyBoolean("coremod_includes_mod")) { attributeMap["FMLCorePluginContainsFMLMod"] = "true" val currentTask = gradle.startParameter.taskNames - val validTasks = listOf("build", "prepareObfModsFolder", "runObfClient") - if (currentTask[0] in validTasks) attributeMap["ForceLoadAsMod"] = "true" + val validTasks = arrayOf("build", "prepareObfModsFolder", "runObfClient") + if (!currentTask.isEmpty() && currentTask[0] in validTasks) attributeMap["ForceLoadAsMod"] = "true" } } if (propertyBoolean("use_access_transformer")) { diff --git a/buildSrc/CHANGELOG.md b/buildSrc/CHANGELOG.md new file mode 100644 index 0000000..f80bab8 --- /dev/null +++ b/buildSrc/CHANGELOG.md @@ -0,0 +1,87 @@ +# Catalyx Buildscripts Changelog + + + +## [0.5.2] - 2026-02-03 + +_general maintenance._ + +- update dependencies +- add a few more mavens + +## [0.5.1] - 2026-01-26 + +_this is fine._ + +- update dependencies +- enable a few experimental kotlin features +- experimental: sync kotlin version from template + +## [0.5.0] - 2026-01-19 + +_Happy new year._ + +- extend secrets management +- fix package name in reference creator +- add indent guesser for reference creator +- update dependencies +- auto create IntelliJ scope file +- improve sync plugin + +## [0.4.1] - 2025-11-26 + +_that one is on me._ + +- fix dependency loader + +## [0.4.0] - 2025-11-17 + +_sync scripts_ + +- implement local plugin updater +- add .gitattributes +- fix new tag implementation + +## [0.3.0] - 2025-11-08 + +_spotless flex_ + +- utilize flexmark +- update docs +- replace RFG tag system with a new implementation + +## [0.2.0] - 2025-10-29 + +_Look at this pretty image._ + +- organization assets +- update dependencies +- .editorconfig profiles + +## [0.1.0] - 2025-10-18 + +_You could almost call it usable._ + +- spotless formatting +- .editorconfig +- property sync from template +- groovyscript jvm argument management +- proper dependency manager + +## [0.0.2] - 2025-10-14 + +_The second iteration..._ + +- change license +- we now use a local plugin structure + +## [0.0.1] - 2025-10-13 + +_The first iteration..._ + +## [0.0.0] - 2025-10-09 + +_Initial commit._ diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 2aabfa0..8e54b45 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -41,5 +41,9 @@ gradlePlugin { id = "catalyx.referencecreator" implementationClass = "plugins.ReferenceCreator" } + create("ijScopeCreatorPlugin") { + id = "catalyx.ijscopecreator" + implementationClass = "plugins.IJScopeCreator" + } } } diff --git a/buildSrc/src/main/kotlin/Repositories.kt b/buildSrc/src/main/kotlin/Repositories.kt index 5a543ff..a7577ca 100644 --- a/buildSrc/src/main/kotlin/Repositories.kt +++ b/buildSrc/src/main/kotlin/Repositories.kt @@ -4,14 +4,33 @@ import org.gradle.kotlin.dsl.repositories fun Project.loadDefaultRepositories() { repositories { mavenCentral() + // RetroFuturaGradle maven { - name = "CleanroomMC Maven" - url = uri("https://maven.cleanroommc.com") + name = "GTNH Maven" + url = uri("https://nexus.gtnewhorizons.com/repository/public/") + } + // JitPack is a novel package repository for JVM and Android projects. + // It builds Git projects on demand and provides you with ready-to-use artifacts (jar, aar). + // Docs: https://docs.jitpack.io/ + maven { + name = "JitPack" + url = uri("https://jitpack.io") } maven { name = "SpongePowered Maven" url = uri("https://repo.spongepowered.org/maven") } + // HEI, MixinBooter, GroovyScript, Forgelin Continuous, ... + maven { + name = "CleanroomMC Maven" + url = uri("https://maven.cleanroommc.com") + } + // Our own maven, meow :3 + maven { + name = "Ender-Development Maven" + url = uri("https://maven.ender-development.org/") + } + // Better implementation of the curseforge maven, which allows adding mods that disable third party downloads exclusiveContent { forRepository { maven { @@ -34,25 +53,52 @@ fun Project.loadDefaultRepositories() { includeGroup("maven.modrinth") } } + // CraftTweaker, ContentTweaker, BWM, JEI, ... maven { name = "BlameJared's Maven" url = uri("https://maven.blamejared.com/") } + // GTCE, GTCEu, AE2uel, EnderIO maven { - name = "JitPack" - url = uri("https://jitpack.io") + name = "GTCEu Maven" + url = uri("https://maven.gtceu.com") } + // AE2, Mekanism, ProjectE, ComputerCraft, OpenComputers, ... maven { - name = "Ender-Development Maven" - url = uri("https://maven.ender-development.org/") + name = "Thiakil's Maven" + url = uri("https://maven.thiakil.com/") } maven { - name = "GTNH Maven" - url = uri("https://nexus.gtnewhorizons.com/repository/public/") + name = "AppleCore's Maven" + url = uri("https://www.ryanliptak.com/maven/") } + // TiCo, Mantle, HungerOverhaul, Natura, IronChest, ... maven { - name = "GTCEu Maven" - url = uri("https://maven.gtceu.com") + name = "Mantle's Maven" + url = uri("https://dvs1.progwml6.com/files/maven") + } + // CTM + maven { + name = "tterrag's Maven" + url = uri("https://maven.tterrag.com/") + } + // cofh, codechicken, ProjectRed, p455w0rd, brandon3055, ... + maven { + name = "covers1624's Maven" + url = uri("https://maven.covers1624.net/") + } + maven { + name = "modmuss50's Maven" + url = uri("https://maven.modmuss50.me/") + } + maven { + name = "BuildCraft's Maven" + url = uri("https://mod-buildcraft.com/maven/") + } + // Large collection of mods from various authors, curseforge maven precursor + maven { + name = "ModMaven" + url = uri("https://modmaven.dev/") } mavenLocal() // Must be last for caching to work } diff --git a/buildSrc/src/main/kotlin/plugins/IJScopeCreator.kt b/buildSrc/src/main/kotlin/plugins/IJScopeCreator.kt new file mode 100644 index 0000000..2783c89 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugins/IJScopeCreator.kt @@ -0,0 +1,46 @@ +package plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project +import propertyString +import util.OnlineUtils +import kotlin.io.path.createDirectories +import kotlin.io.path.createFile +import kotlin.io.path.div +import kotlin.io.path.notExists +import kotlin.io.path.writeText + +@Suppress("UNUSED") +class IJScopeCreator : Plugin { + companion object { + const val SCOPE_FILE = "Mod_Source.xml" + + private fun createIJScope(project: Project) { + if (OnlineUtils.isTemplateProject()) { + return + } + + val modName = project.propertyString("mod_name") + val filteredModName = modName.filter(Char::isLetterOrDigit) + val outputPath = project.rootDir.toPath() / ".idea" / "scopes" / SCOPE_FILE + + val ijScope = buildString { + appendLine("") + appendLine(" ") + appendLine("") + } + + if (outputPath.notExists()) { + outputPath.parent.createDirectories() + outputPath.createFile() + } + outputPath.writeText(ijScope) + Logger.info("IntelliJ scope file created at ${outputPath.normalize()}") + } + } + + override fun apply(target: Project) { + Logger.greet(this) + createIJScope(target) + } +} diff --git a/buildSrc/src/main/kotlin/plugins/PropSync.kt b/buildSrc/src/main/kotlin/plugins/PropSync.kt index e7244b3..54ad0ee 100644 --- a/buildSrc/src/main/kotlin/plugins/PropSync.kt +++ b/buildSrc/src/main/kotlin/plugins/PropSync.kt @@ -12,7 +12,7 @@ import java.nio.file.StandardCopyOption import java.util.Properties class PropSync : Plugin { - data class SyncConfig(val keysToSync: List = emptyList(), val syncAll: Boolean = false) + data class SyncConfig(val keysToSync: List = emptyList(), val syncAll: Boolean = false, val path: String = "buildSrc/src/main/resources/") companion object { private var foundUpdate = false @@ -46,6 +46,11 @@ class PropSync : Plugin { "tags.properties" to SyncConfig( syncAll = true, ), + // This one is new, still needs to be tested + "gradle.properties" to SyncConfig( + keysToSync = listOf("kotlin_version"), + path = "", + ), ) fun syncPropertiesFromTemplate() { @@ -59,12 +64,12 @@ class PropSync : Plugin { Logger.info("Syncing with template repository: ${OnlineUtils.TEMPLATE_REPO}") syncConfig.forEach { (file, cfg) -> try { - val templateProperties = fetchTemplateProperties(file) + val templateProperties = fetchTemplateProperties(file, cfg.path) val localProperties = Loader.loadPropertyFromFile(file) val mergedProperties = mergeProperties(localProperties, templateProperties, cfg) if (foundUpdate) { - updateLocalPropertiesFile(file, mergedProperties) + updateLocalPropertiesFile(cfg.path, file, mergedProperties) Logger.info("Synchronized properties for '$file'") } else { Logger.info("No changes detected for '$file'") @@ -75,8 +80,8 @@ class PropSync : Plugin { } } - private fun fetchTemplateProperties(fileName: PropertyFile): Properties { - val url = "${OnlineUtils.GITHUB_RAW_URL}/${OnlineUtils.TEMPLATE_REPO}/${OnlineUtils.TEMPLATE_BRANCH}/buildSrc/src/main/resources/$fileName" + private fun fetchTemplateProperties(fileName: PropertyFile, path: String): Properties { + val url = "${OnlineUtils.GITHUB_RAW_URL}/${OnlineUtils.TEMPLATE_REPO}/${OnlineUtils.TEMPLATE_BRANCH}/$path$fileName" val properties = Properties() val content = OnlineUtils.fetchFileContent(url) ?: throw Exception("Failed to fetch content from $url") properties.load(ByteArrayInputStream(content.toByteArray())) @@ -110,8 +115,8 @@ class PropSync : Plugin { return merged } - private fun updateLocalPropertiesFile(fileName: PropertyFile, properties: Properties) { - val buildSrcDirectory = project.rootProject.file("buildSrc/src/main/resources") + private fun updateLocalPropertiesFile(path: String, fileName: PropertyFile, properties: Properties) { + val buildSrcDirectory = project.rootProject.file(path.removeSuffix("/")) val propertyFile = File(buildSrcDirectory, fileName) if (propertyFile.exists().not()) { return Logger.warn("Property file '$fileName' does not exist at ${propertyFile.absolutePath}, skipping update.") @@ -135,6 +140,7 @@ class PropSync : Plugin { existingLines.forEach { when { it.startsWith("#") || it.trim().isEmpty() -> lines.add(it) + it.contains("=") -> { val key = it.substringBefore("=").trim() val newValue = properties.getProperty(key) @@ -147,6 +153,7 @@ class PropSync : Plugin { updatedKeys.add(key) } ?: lines.add(it) // Keep existing line if key not in new properties } + else -> lines.add(it) } } diff --git a/buildSrc/src/main/kotlin/plugins/ReferenceCreator.kt b/buildSrc/src/main/kotlin/plugins/ReferenceCreator.kt index e389bcf..a72e730 100644 --- a/buildSrc/src/main/kotlin/plugins/ReferenceCreator.kt +++ b/buildSrc/src/main/kotlin/plugins/ReferenceCreator.kt @@ -15,32 +15,81 @@ class ReferenceCreator : Plugin { companion object { const val REFERENCE_FILE = "tags.properties" + /** + * Guesses the indent style based on the .editorconfig file used. + * + * If the .editorconfig file is not present, or the required values cannot be found, the default 4-space indent is returned instead. + */ + fun guessIndent(project: Project): String { + val editorconfig = project.file(".editorconfig") + if (!editorconfig.exists()) { + return " " + } + + var indentStyle = "" + var indentSize = -1 + + // this is crude and doesn't parse everything per spec https://spec.editorconfig.org/, but it's good enough + editorconfig.useLines { lines -> + for (line in lines) { + val line = line.trim() + if (line.startsWith("indent_size", true)) { + indentSize = line.substringAfter('=').trim().toIntOrNull() ?: -1 + if (indentStyle == "") { + continue + } else { + break + } + } + + if (line.startsWith("indent_style", true)) { + indentStyle = line.substringAfter('=').trim() + if (indentSize == -1) { + continue + } else { + break + } + } + } + } + + return when { + indentStyle.equals("tab", true) -> "\t" + indentStyle.equals("space", true) -> " ".repeat(if (indentSize == -1) 4 else indentSize) + else -> " " + } + } + private fun createReference(project: Project) { val properties = Loader.loadPropertyFromFile(REFERENCE_FILE) val objectName = project.propertyString("mod_name").filter(Char::isLetterOrDigit) - val reference = arrayListOf("package ${project.propertyString("tags_package")}") - reference.add("") - reference.add("internal typealias Reference = ${objectName}Reference") - reference.add("") - reference.add("/**") - reference.add(" * Auto-generated reference object containing constants from `$REFERENCE_FILE`.") - reference.add(" * Don't change this file manually as it will be overwritten.") - reference.add(" */") - reference.add("@Suppress(\"UNUSED\")") - reference.add("object ${objectName}Reference {") - properties.forEach { (key, value) -> - val eval = (if (value is String) project.evaluate(value) else value).toString() - reference.add(" const val ${key.toString().uppercase()} = ${if (eval.all(Char::isDigit) && eval.count { it == '.' } <= 1) eval else "\"$eval\""}") + val objectPath = project.propertyString("tags_package") + val indent = guessIndent(project) + val reference = buildString { + appendLine("package $objectPath") + appendLine("") + appendLine("internal typealias Reference = ${objectName}Reference") + appendLine("") + appendLine("/**") + appendLine(" * Auto-generated reference object containing constants from `$REFERENCE_FILE`.") + appendLine(" * Don't change this file manually as it will be overwritten.") + appendLine(" */") + appendLine("@Suppress(\"UNUSED\")") + appendLine("object ${objectName}Reference {") + properties.forEach { (key, value) -> + val eval = (if (value is String) project.evaluate(value) else value).toString() + val value = if (eval.toDoubleOrNull() != null) eval else "\"${eval.replace("\"", "\\\"")}\"" + appendLine("${indent}const val $key = $value") + } + appendLine("}") } - reference.add("}") - reference.add("") val outputPath = "${project.rootDir}/src/main/kotlin/${project.propertyString("tags_package").replace(".", "/")}/${objectName}Reference.kt" val outputFile = Path(outputPath) if (outputFile.notExists()) { outputFile.parent.createDirectories() outputFile.createFile() } - outputFile.writeText(reference.joinToString(separator = System.lineSeparator())) + outputFile.writeText(reference.replace("\n", System.lineSeparator())) Logger.info("Reference file created at ${outputPath.replace("\\", "/")}") } } diff --git a/buildSrc/src/main/kotlin/plugins/ScriptSync.kt b/buildSrc/src/main/kotlin/plugins/ScriptSync.kt index 78b23bd..dd03e5f 100644 --- a/buildSrc/src/main/kotlin/plugins/ScriptSync.kt +++ b/buildSrc/src/main/kotlin/plugins/ScriptSync.kt @@ -3,53 +3,39 @@ package plugins import org.gradle.api.Plugin import org.gradle.api.Project import util.OnlineUtils -import util.OnlineUtils.isOnline -import util.OnlineUtils.shouldDisableSync class ScriptSync : Plugin { companion object { + const val BASE_URL = "${OnlineUtils.GITHUB_RAW_URL}/${OnlineUtils.TEMPLATE_REPO}/${OnlineUtils.TEMPLATE_BRANCH}/" + const val FILE_LIST_NAME = "buildSrc/src/main/resources/sync-file-list.txt" private lateinit var project: Project - private val syncScripts: List = listOf( - "buildSrc/src/main/kotlin/plugins/DepLoader.kt", - "buildSrc/src/main/kotlin/plugins/Loader.kt", - "buildSrc/src/main/kotlin/plugins/Logger.kt", - "buildSrc/src/main/kotlin/plugins/PropSync.kt", - "buildSrc/src/main/kotlin/plugins/ReferenceCreator.kt", - "buildSrc/src/main/kotlin/plugins/ScriptSync.kt", - "buildSrc/src/main/kotlin/plugins/Secrets.kt", - "buildSrc/src/main/kotlin/util/DependencyProvider.kt", - "buildSrc/src/main/kotlin/util/OnlineUtils.kt", - "buildSrc/src/main/kotlin/BaseSetup.kt", - "buildSrc/src/main/kotlin/Dependencies.kt", - "buildSrc/src/main/kotlin/PropertyExtension.kt", - "buildSrc/src/main/kotlin/Repositories.kt", - "buildSrc/build.gradle.kts", - "build.gradle.kts", - "settings.gradle.kts", - ) - fun syncFilesFromTemplate() { Logger.banner("Searching for Files to sync!") - if (shouldDisableSync()) return Logger.info("Sync is disabled via system.") - if (!isOnline()) return Logger.warn("No internet connection detected.") + if (OnlineUtils.shouldDisableSync()) return Logger.info("Sync is disabled via system.") + if (!OnlineUtils.isOnline()) return Logger.warn("No internet connection detected.") performSync() } + private fun syncFile(fileName: String) { + val fileUrl = "$BASE_URL$fileName" + val remoteContent = OnlineUtils.fetchFileContent(fileUrl) ?: throw Exception("Failed to fetch content from $fileUrl") + val localFile = project.file(fileName) + val localContent = if (localFile.exists()) localFile.readText() else "" + + if (remoteContent != localContent) { + localFile.writeText(remoteContent) + Logger.info("Synchronized file: $fileName") + } else { + Logger.info("File is up-to-date: $fileName") + } + } + private fun performSync() { - val baseUrl = "${OnlineUtils.GITHUB_RAW_URL}/${OnlineUtils.TEMPLATE_REPO}/${OnlineUtils.TEMPLATE_BRANCH}/" - syncScripts.forEach { - val fileUrl = "$baseUrl$it" - val remoteContent = OnlineUtils.fetchFileContent(fileUrl) ?: throw Exception("Failed to fetch content from $fileUrl") - val localFile = project.file(it) - val localContent = if (localFile.exists()) localFile.readText() else "" - - if (remoteContent != localContent) { - localFile.writeText(remoteContent) - Logger.info("Synchronized file: $it") - } else { - Logger.info("File is up-to-date: $it") - } + syncFile(FILE_LIST_NAME) + + project.file(FILE_LIST_NAME).useLines { lines -> + lines.filter(String::isNotBlank).forEach(::syncFile) } } } diff --git a/buildSrc/src/main/kotlin/plugins/Secrets.kt b/buildSrc/src/main/kotlin/plugins/Secrets.kt index c594fe7..5988694 100644 --- a/buildSrc/src/main/kotlin/plugins/Secrets.kt +++ b/buildSrc/src/main/kotlin/plugins/Secrets.kt @@ -33,32 +33,32 @@ class Secrets : Plugin { val rootSecrets = target.rootProject.file(PROPERTIES_FILE) val userSecrets = File( System.getProperty("user.home"), - ".gradle/$PROPERTIES_FILE" + ".gradle/$PROPERTIES_FILE", ) val secretsFile = when { rootSecrets.exists() -> { - if (!getOrEnvironment("DISMISS_SECRET_FILE_WARNING").toBoolean()) { - Logger.warn("Don't store secrets inside the repo tree BECAUSE IT IS FCKN DANGEROUS!") + if (System.getenv("DISMISS_SECRET_FILE_WARNING") == null) { + Logger.warn( + "Keeping the secrets file in the project root can have security implications, as such moving the '$PROPERTIES_FILE' to ~/.gradle would be recommended. Set the DISMISS_SECRET_FILE_WARNING environment variable to disable this warning at your own risk.", + ) } rootSecrets } + userSecrets.exists() -> userSecrets - else -> null - } - if (secretsFile == null) { - if (target.rootProject.file(EXAMPLE_FILE).exists()) { - Logger.warn("No '$PROPERTIES_FILE' found. Please create one in project root or even better in ~/.gradle based on '$EXAMPLE_FILE'.") + else -> { + if (target.rootProject.file(EXAMPLE_FILE).exists()) { + Logger.warn("No '$PROPERTIES_FILE' found, please create one in ~/.gradle, or in the project root, based on '$EXAMPLE_FILE'.") + } - // Needed? - //println("WARNING: No '$PROPERTIES_FILE' found in project root or ~/.gradle. Please create one based on '$EXAMPLE_FILE'.") + return } - return } + Companion.secretsFile = secretsFile.absolutePath Logger.info("Loading secrets from: ${secretsFile.absolutePath}") Loader.loadPropertyFile(secretsFile.absolutePath) - Companion.secretsFile = secretsFile.absolutePath } } diff --git a/buildSrc/src/main/kotlin/util/OnlineUtils.kt b/buildSrc/src/main/kotlin/util/OnlineUtils.kt index b3776c7..d24ad46 100644 --- a/buildSrc/src/main/kotlin/util/OnlineUtils.kt +++ b/buildSrc/src/main/kotlin/util/OnlineUtils.kt @@ -36,7 +36,7 @@ object OnlineUtils { * Checks if the current project is the template project by examining the Git remote URL. * @return `true` if the project is the template project, `false` otherwise. */ - private fun isTemplateProject(): Boolean { + fun isTemplateProject(): Boolean { val repo = FileRepositoryBuilder() .setGitDir(File(".git")) .readEnvironment() @@ -79,7 +79,7 @@ object OnlineUtils { val connection = URI.create(url).toURL().openConnection() connection.connectTimeout = CONNECTION_TIMEOUT connection.readTimeout = CONNECTION_TIMEOUT - connection.getInputStream().readBytes().toString(Charsets.UTF_8) + connection.inputStream.use { it.readBytes().toString(Charsets.UTF_8) } } catch (e: Exception) { Logger.error("Error fetching file from '$url': ${e.message}") null diff --git a/buildSrc/src/main/resources/deps.properties b/buildSrc/src/main/resources/deps.properties index 9beea51..edd5463 100644 --- a/buildSrc/src/main/resources/deps.properties +++ b/buildSrc/src/main/resources/deps.properties @@ -76,4 +76,4 @@ use_modularui = true # The version of ModularUI to use, should be compatible with the Minecraft version you are using # Check https://repo.cleanroommc.com/#/releases/com/cleanroommc/modularui -modularui_version = 3.0.8 +modularui_version = 3.1.2 diff --git a/buildSrc/src/main/resources/integration.properties b/buildSrc/src/main/resources/integration.properties index 56e902d..8f94901 100644 --- a/buildSrc/src/main/resources/integration.properties +++ b/buildSrc/src/main/resources/integration.properties @@ -24,7 +24,7 @@ use_groovyscript = true groovy_version = 4.0.26 # The version of GroovyScript to use. Check https://repo.cleanroommc.com/#/releases/com/cleanroommc/groovyscript for the latest version. -groovyscript_version = 1.3.3 +groovyscript_version = 1.3.4 # Should the GroovyScript language server be run when executing the 'runClient' task? grs_run_ls = false @@ -55,7 +55,7 @@ use_hei = true # The version of HadEnoughItems to use, should be compatible with the Minecraft version you are using # Check https://repo.cleanroommc.com/#/releases/mezz/jei -hei_version = 4.29.14 +hei_version = 4.29.15 diff --git a/buildSrc/src/main/resources/sync-file-list.txt b/buildSrc/src/main/resources/sync-file-list.txt new file mode 100644 index 0000000..b55d2da --- /dev/null +++ b/buildSrc/src/main/resources/sync-file-list.txt @@ -0,0 +1,18 @@ +buildSrc/src/main/kotlin/plugins/DepLoader.kt +buildSrc/src/main/kotlin/plugins/IJScopeCreator.kt +buildSrc/src/main/kotlin/plugins/Loader.kt +buildSrc/src/main/kotlin/plugins/Logger.kt +buildSrc/src/main/kotlin/plugins/PropSync.kt +buildSrc/src/main/kotlin/plugins/ReferenceCreator.kt +buildSrc/src/main/kotlin/plugins/ScriptSync.kt +buildSrc/src/main/kotlin/plugins/Secrets.kt +buildSrc/src/main/kotlin/util/DependencyProvider.kt +buildSrc/src/main/kotlin/util/OnlineUtils.kt +buildSrc/src/main/kotlin/BaseSetup.kt +buildSrc/src/main/kotlin/Dependencies.kt +buildSrc/src/main/kotlin/PropertyExtension.kt +buildSrc/src/main/kotlin/Repositories.kt +buildSrc/build.gradle.kts +buildSrc/CHANGELOG.md +build.gradle.kts +settings.gradle.kts diff --git a/buildSrc/src/main/resources/utilities.properties b/buildSrc/src/main/resources/utilities.properties index 79412f3..377556b 100644 --- a/buildSrc/src/main/resources/utilities.properties +++ b/buildSrc/src/main/resources/utilities.properties @@ -23,7 +23,7 @@ use_dependency_at_files = true # You MUST state a class name for `coremod_plugin_class_name` if you are making a coremod, the class should implement `IFMLLoadingPlugin` is_coremod = true coremod_includes_mod = true -coremod_plugin_class_name = org.ender_development.catalyx.core.CatalyxCore +coremod_plugin_class_name = org.ender_development.catalyx.core.CatalyxCoreMod @@ -39,7 +39,7 @@ use_spotless = true # - roz: Uses a heavily customized .editorconfig created by rozbrajaczpoziomow editorconfig = roz flexmark_version = 0.64.8 -google_java_format_version = 1.33.0 +google_java_format_version = 1.34.0 ktlint_version = 1.8.0 diff --git a/gradle.properties b/gradle.properties index e94d044..5852456 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,7 +20,7 @@ generate_javadocs_jar = true # <-- Kotlin --> # <------------> # The version of Kotlin to use. -kotlin_version = 2.2.20 +kotlin_version = 2.3.0 diff --git a/src/main/kotlin/org/ender_development/catalyx/Catalyx.kt b/src/main/kotlin/org/ender_development/catalyx/Catalyx.kt index ea64be0..e13fb9a 100644 --- a/src/main/kotlin/org/ender_development/catalyx/Catalyx.kt +++ b/src/main/kotlin/org/ender_development/catalyx/Catalyx.kt @@ -2,14 +2,13 @@ package org.ender_development.catalyx import net.minecraft.creativetab.CreativeTabs import net.minecraft.util.ResourceLocation +import net.minecraftforge.common.ForgeVersion import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.event.FMLConstructionEvent -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent import org.apache.logging.log4j.LogManager -import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.Reference +import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.module.ModuleManager -import org.ender_development.catalyx.core.network.PacketHandler import org.ender_development.catalyx.core.utils.persistence.ConfigPersistentData import kotlin.random.Random @@ -19,6 +18,7 @@ import kotlin.random.Random version = Reference.VERSION, dependencies = ICatalyxMod.DEPENDENCIES, modLanguageAdapter = ICatalyxMod.MOD_LANGUAGE_ADAPTER, + acceptedMinecraftVersions = ForgeVersion.mcVersion, acceptableRemoteVersions = "*" ) @Mod.EventBusSubscriber(modid = Reference.MODID) @@ -41,9 +41,4 @@ object Catalyx : ICatalyxMod { fun construction(e: FMLConstructionEvent) { ModuleManager.setup(e.asmHarvestedData) } - - @Mod.EventHandler - fun preInit(e: FMLPreInitializationEvent) { - PacketHandler.init() - } } diff --git a/src/main/kotlin/org/ender_development/catalyx/api/.gitkeep b/src/main/kotlin/org/ender_development/catalyx/api/.gitkeep index e69de29..9f21392 100644 --- a/src/main/kotlin/org/ender_development/catalyx/api/.gitkeep +++ b/src/main/kotlin/org/ender_development/catalyx/api/.gitkeep @@ -0,0 +1 @@ +Do not remove until v2 package added at sometime because of IJ diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/client/Client.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/client/Client.kt new file mode 100644 index 0000000..18a932c --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/client/Client.kt @@ -0,0 +1,9 @@ +package org.ender_development.catalyx.api.v1.client + +import org.ender_development.catalyx.api.v1.client.interfaces.IAreaHighlighter +import org.ender_development.catalyx.core.client.AreaHighlighter + +object Client { + fun newAreaHighlighter(): IAreaHighlighter = + AreaHighlighter() +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/client/interfaces/IAreaHighlighter.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/client/interfaces/IAreaHighlighter.kt new file mode 100644 index 0000000..6a8b820 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/client/interfaces/IAreaHighlighter.kt @@ -0,0 +1,91 @@ +package org.ender_development.catalyx.api.v1.client.interfaces + +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import org.ender_development.catalyx.api.v1.common.extensions.mapToArray + +/** + * A helper allowing you to highlight an area, block or blocks in 3D space + * @see [highlightBlock] + * @see [highlightBlocks] + * @see [highlightArea] + */ +interface IAreaHighlighter { + /** + * Whether this AreaHighlighter is actually rendering anything + */ + val shown: Boolean + + /** + * Array of outlines that are currently being drawn + */ + val drawOutlinesFor: Array> + + /** + * A BlockPos instance from the integer part of the starting coordinates for the first outline from [drawOutlinesFor] + * + * Returns [BlockPos.ORIGIN] (0, 0, 0) when not [drawing][shown] anything + */ + val pos1: BlockPos + get() = BlockPos((drawOutlinesFor.getOrNull(0) ?: return BlockPos.ORIGIN).first) + + /** + * A BlockPos instance from the integer part of the ending coordinates for the first outline from [drawOutlinesFor] + * + * Returns [BlockPos.ORIGIN] (0, 0, 0) when not [drawing][shown] anything + */ + val pos2: BlockPos + get() = BlockPos((drawOutlinesFor.getOrNull(0) ?: return BlockPos.ORIGIN).second) + + // R, G, B colour channels + val r: Float + val g: Float + val b: Float + + /** + * Absolute time in milliseconds when this AreaHighlighter will automatically [hide] + */ + val until: Long + + /** + * Line thickness used in the renderer + */ + var thickness: Float + + /** + * Highlight a [block position][pos] with a specific colour ([red][r], [green][g], [blue][b]) for a specified [time] in milliseconds + */ + fun highlightBlock(pos: BlockPos, r: Float, g: Float, b: Float, time: Int) = + highlightAreas(arrayOf(pos.area()), r, g, b, time) + + /** + * Highlight an area between ([x1], [y1], [z1]) and ([x2], [y2], [z2]) with a specific colour ([red][r], [green][g], [blue][b]) for a specified [time] in milliseconds + */ + fun highlightArea(x1: Double, y1: Double, z1: Double, x2: Double, y2: Double, z2: Double, r: Float, g: Float, b: Float, time: Int) = + highlightAreas(arrayOf(Vec3d(x1, y1, z1) to Vec3d(x2, y2, z2)), r, g, b, time) + + /** + * Highlight the specified [blocks][blockPositions] with a specific colour ([red][r], [green][g], [blue][b]) for a specified [time] in milliseconds + */ + fun highlightBlocks(blockPositions: Array, r: Float, g: Float, b: Float, time: Int) = + highlightAreas(blockPositions.mapToArray(BlockPos::area), r, g, b, time) + + /** + * Highlight the specified [areas] with a specific colour ([red][r], [green][g], [blue][b]) for a specified [time] in milliseconds + */ + fun highlightAreas(areas: Array>, r: Float, g: Float, b: Float, time: Int) + + /** + * Highlight the specified [areas] with a specific colour ([red][r], [green][g], [blue][b]) for a specified [time] in milliseconds + */ + fun highlightAreas(areas: Collection>, r: Float, g: Float, b: Float, time: Int) = + highlightAreas(areas.toTypedArray(), r, g, b, time) + + /** + * Stop this AreaHighlighter from rendering anything, does nothing when not [shown] + */ + fun hide() +} + +private fun BlockPos.area(): Pair = + Vec3d(x.toDouble(), y.toDouble(), z.toDouble()) to Vec3d(x + 1.0, y + 1.0, z + 1.0) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/ColorMapping.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/ColorMapping.kt similarity index 98% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/ColorMapping.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/ColorMapping.kt index 35c76af..719e4dc 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/ColorMapping.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/ColorMapping.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils +package org.ender_development.catalyx.api.v1.common import net.minecraft.item.EnumDyeColor import net.minecraft.item.EnumRarity diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Math.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Math.kt new file mode 100644 index 0000000..5fa1ea9 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Math.kt @@ -0,0 +1,4 @@ +package org.ender_development.catalyx.api.v1.common + +object Math { +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/Mods.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Mods.kt similarity index 71% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/Mods.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/Mods.kt index e0416b6..67b8eb0 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/Mods.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Mods.kt @@ -1,7 +1,10 @@ -package org.ender_development.catalyx.core.utils +package org.ender_development.catalyx.api.v1.common import org.ender_development.catalyx.core.Reference +/** + * Common mod ids for integration and other things + */ object Mods { const val CATALYX = Reference.MODID const val GROOVYSCRIPT = "groovyscript" diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Severity.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Severity.kt new file mode 100644 index 0000000..a735660 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/Severity.kt @@ -0,0 +1,9 @@ +package org.ender_development.catalyx.api.v1.common + +import org.apache.logging.log4j.Level + +enum class Severity(val loggerLevel: Level, val emoji: String) { + WARNING(Level.WARN, "⚠️"), + ERROR(Level.ERROR, "❌"), + CRITICAL(Level.FATAL, "🚨") +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Any.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Any.kt similarity index 54% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Any.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Any.kt index 7d509bb..cb27d63 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Any.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Any.kt @@ -1,10 +1,11 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions -import org.ender_development.catalyx.core.utils.validation.IValidator -import org.ender_development.catalyx.core.utils.validation.ValidationBuilder -import org.ender_development.catalyx.core.utils.validation.ValidationResult +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationResult +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidator +import org.ender_development.catalyx.core.validation.ValidationBuilder +import org.ender_development.catalyx.core.validation.ValidationResult -fun T?.validateWith(vararg validators: IValidator): ValidationResult { +fun T?.validateWith(vararg validators: IValidator): IValidationResult { val builder = ValidationBuilder() val error = validators.any { diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Array.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Array.kt new file mode 100644 index 0000000..e030b2a --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Array.kt @@ -0,0 +1,4 @@ +package org.ender_development.catalyx.api.v1.common.extensions + +inline fun Array.mapToArray(crossinline mapper: (T) -> R) = + Array(size) { mapper(this[it]) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/AxisAlignedBB.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/AxisAlignedBB.kt similarity index 93% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/AxisAlignedBB.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/AxisAlignedBB.kt index 1f63156..e3ba858 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/AxisAlignedBB.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/AxisAlignedBB.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.util.math.AxisAlignedBB diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Block.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Block.kt similarity index 82% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Block.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Block.kt index 78f2901..9114281 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Block.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Block.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.block.Block import net.minecraft.item.ItemStack diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/BlockPos.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/BlockPos.kt new file mode 100644 index 0000000..f6f9ced --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/BlockPos.kt @@ -0,0 +1,70 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package org.ender_development.catalyx.api.v1.common.extensions + +import net.minecraft.entity.Entity +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import kotlin.math.cos +import kotlin.math.roundToInt +import kotlin.math.sin + +fun BlockPos.rotateX(degrees: Int): BlockPos { + val rad = Math.toRadians(degrees.toDouble()) + val cos = cos(rad) + val sin = sin(rad) + return BlockPos( + this.x, + (this.y * cos - this.z * sin).roundToInt(), + (this.y * sin + this.z * cos).roundToInt() + ) +} + +fun BlockPos.rotateY(degrees: Int): BlockPos { + val rad = Math.toRadians(degrees.toDouble()) + val cos = cos(rad) + val sin = sin(rad) + return BlockPos( + (this.x * cos - this.z * sin).roundToInt(), + this.y, + (this.x * sin + this.z * cos).roundToInt() + ) +} + +fun BlockPos.rotateZ(degrees: Int): BlockPos { + val rad = Math.toRadians(degrees.toDouble()) + val cos = cos(rad) + val sin = sin(rad) + return BlockPos( + (this.x * cos - this.y * sin).roundToInt(), + (this.x * sin + this.y * cos).roundToInt(), + this.z + ) +} + +inline operator fun BlockPos.minus(other: BlockPos): BlockPos = + subtract(other) + +inline operator fun BlockPos.plus(other: BlockPos): BlockPos = + add(other) + +inline operator fun BlockPos.times(scalar: Int) = + BlockPos(x * scalar, y * scalar, z * scalar) + +inline fun Pair.getAllInBox(): Iterable = + BlockPos.getAllInBox(first, second) + +inline fun BlockPos.getFacingFromEntityPosition(entityX: Float, entityZ: Float): EnumFacing = + EnumFacing.getFacingFromVector(entityX - x, 0f, entityZ - z) + +inline fun BlockPos.getFacingFromEntity(entity: Entity): EnumFacing = + getFacingFromEntityPosition(entity.posX.toFloat(), entity.posZ.toFloat()) + +/** + * @see org.ender_development.catalyx.core.blocks.multiblock.parts.AbstractEdgeBlock + */ +fun BlockPos.getHorizontalSurroundings() = arrayOf( + north().west(), north(), north().east(), + west(), /* us */ east(), + south().west(), south(), south().east() +) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/ByteBuf.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/ByteBuf.kt similarity index 93% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/ByteBuf.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/ByteBuf.kt index c348684..96e5a4c 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/ByteBuf.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/ByteBuf.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import io.netty.buffer.ByteBuf import net.minecraft.item.ItemStack diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Color.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Color.kt similarity index 88% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Color.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Color.kt index 8f2e8c3..53d0a58 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Color.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Color.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import java.awt.Color diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Container.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Container.kt new file mode 100644 index 0000000..da33444 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Container.kt @@ -0,0 +1,13 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package org.ender_development.catalyx.api.v1.common.extensions + +import net.minecraft.inventory.Container +import net.minecraft.inventory.Slot +import net.minecraft.item.ItemStack + +inline operator fun Container.get(slotId: Int): Slot = + getSlot(slotId) + +inline operator fun Container.set(slotId: Int, stack: ItemStack) = + putStackInSlot(slotId, stack) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnchantmentRarity.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnchantmentRarity.kt similarity index 73% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnchantmentRarity.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnchantmentRarity.kt index 52a65f6..10018c8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnchantmentRarity.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnchantmentRarity.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.enchantment.Enchantment import net.minecraft.item.EnumRarity diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EntityPlayer.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EntityPlayer.kt similarity index 83% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EntityPlayer.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EntityPlayer.kt index 089317f..28500b4 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EntityPlayer.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EntityPlayer.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.client.entity.EntityPlayerSP import net.minecraft.entity.player.EntityPlayer diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumDyeColor.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumDyeColor.kt similarity index 57% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumDyeColor.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumDyeColor.kt index 3d427cf..eadcbb9 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumDyeColor.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumDyeColor.kt @@ -1,7 +1,7 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.item.EnumDyeColor -import org.ender_development.catalyx.core.utils.ColorMapping +import org.ender_development.catalyx.api.v1.common.ColorMapping val EnumDyeColor.colorValue inline get() = ColorMapping[this] diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumFacing.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumFacing.kt similarity index 96% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumFacing.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumFacing.kt index f0e800b..b78c7a4 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumFacing.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumFacing.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.client.renderer.GlStateManager import net.minecraft.util.EnumFacing diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumRarity.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumRarity.kt similarity index 71% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumRarity.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumRarity.kt index 430a6d8..8550b0e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/EnumRarity.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/EnumRarity.kt @@ -1,8 +1,8 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.enchantment.Enchantment import net.minecraft.item.EnumRarity -import org.ender_development.catalyx.core.utils.ColorMapping +import org.ender_development.catalyx.api.v1.common.ColorMapping val EnumRarity.colorValue inline get() = ColorMapping[this] diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Fluid.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Fluid.kt similarity index 70% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Fluid.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Fluid.kt index d67c501..569e1b6 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Fluid.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Fluid.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraftforge.fluids.Fluid import net.minecraftforge.fluids.FluidStack diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/FluidStack.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/FluidStack.kt similarity index 90% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/FluidStack.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/FluidStack.kt index 12a116b..7d4b0ff 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/FluidStack.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/FluidStack.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraftforge.fluids.FluidRegistry import net.minecraftforge.fluids.FluidStack diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/IItemHandler.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/IItemHandler.kt new file mode 100644 index 0000000..b460763 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/IItemHandler.kt @@ -0,0 +1,49 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package org.ender_development.catalyx.api.v1.common.extensions + +import net.minecraft.item.ItemStack +import net.minecraftforge.items.IItemHandler + +inline operator fun IItemHandler.get(idx: Int) = + getStackInSlot(idx) + +fun IItemHandler.tryInsertInto(otherHandler: IItemHandler): Boolean { + for(i in 0.. ItemStack): ItemStack = + if(isEmpty) + ItemStack.EMPTY + else + notEmpty(this) fun ItemStack.areStacksEqualIgnoreQuantity(other: ItemStack) = item === other.item && metadata == other.metadata && ItemStack.areItemStackTagsEqual(this, other) @@ -12,7 +34,7 @@ fun ItemStack.canMergeWith(target: ItemStack, allowEmpty: Boolean) = else item === target.item && count + target.count <= maxStackSize && itemDamage == target.itemDamage && tagCompound == target.tagCompound -fun ItemStack.toIngredient(): Ingredient = +inline fun ItemStack.toIngredient(): Ingredient = Ingredient.fromStacks(this) fun ItemStack.equalsIgnoreMeta(other: ItemStack) = diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/List.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/List.kt new file mode 100644 index 0000000..6f0ce60 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/List.kt @@ -0,0 +1,55 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package org.ender_development.catalyx.api.v1.common.extensions + +import com.google.common.collect.ImmutableList +import it.unimi.dsi.fastutil.objects.ObjectLists +import net.minecraft.item.ItemStack +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.oredict.OreDictionary +import org.ender_development.catalyx.api.v1.common.Severity +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationResult + +fun List.containsItem(stack: ItemStack, strict: Boolean = false) = + any { OreDictionary.itemMatches(it, stack, strict) } + +fun List.toImmutableList(): ImmutableList = + ImmutableList.copyOf(this) + +fun List.toSingletonList(): List = + ObjectLists.singleton(this[0]) + +fun List.validateEach(validator: (idx: Int, T) -> IValidationResult) = + mapIndexed(validator) + +@JvmName("copyOfIS") +inline fun List.copyOf() = + map { + it.orIfNotEmpty(ItemStack::copy) + } + +@JvmName("copyOfFS") +inline fun List.copyOf() = + map(FluidStack::copy) + +inline fun List.mapUnique(transform: (T) -> R) = + mapTo(hashSetOf(), transform) + +fun List.getBySeverity(severity: Severity) = + filter { it.severity == severity } + +fun List.getByMinSeverity(severity: Severity) = + filter { it.severity >= severity } + +/** + * Get the specified [index][idx] in the list and apply the [mapper] function, or return the [default] + */ +inline fun List.getApplyOrDefault(idx: Int, crossinline mapper: (T) -> R, crossinline default: () -> R) = + if(idx in indices) + mapper(this[idx]) + else + default() + +inline fun List.mapToArray(crossinline mapper: (T) -> R) = + Array(size) { mapper(this[it]) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Logger.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Logger.kt similarity index 77% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Logger.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Logger.kt index aa9f38b..e286ad5 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Logger.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Logger.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/NBTTagCompound.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/NBTTagCompound.kt similarity index 90% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/NBTTagCompound.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/NBTTagCompound.kt index 0ba0d46..19e077e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/NBTTagCompound.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/NBTTagCompound.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagLongArray diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/PacketBuffer.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/PacketBuffer.kt new file mode 100644 index 0000000..031d11c --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/PacketBuffer.kt @@ -0,0 +1,45 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package org.ender_development.catalyx.api.v1.common.extensions + +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.network.PacketBuffer +import net.minecraftforge.fluids.FluidStack +import org.ender_development.catalyx.Catalyx +import java.io.IOException + +/* + * Utility functions for reading and writing ItemStacss and FluidStacks to PacketBuffers. + * Handles potential IOExceptions and logs them using the Catalyx logger. + * Loosely based on code from [ModularUI](https://github.com/CleanroomMC/ModularUI/blob/master/src/main/java/com/cleanroommc/modularui/network/NetworkUtils.java) licensed under GNU LGPL-3.0 + */ + +inline fun PacketBuffer.writeItemStackOrEmpty(stack: ItemStack?) = + writeItemStack(stack.orEmpty()) + +fun PacketBuffer.readItemStackOrEmpty(): ItemStack = + try { + readItemStack() + } catch(e: IOException) { + Catalyx.LOGGER.catching(e) + ItemStack.EMPTY + } + +fun PacketBuffer.writeFluidStack(fluidStack: FluidStack?) { + writeBoolean(fluidStack == null) + fluidStack?.let { + writeCompoundTag(it.writeToNBT(NBTTagCompound())) + } +} + +fun PacketBuffer.readFluidStack(): FluidStack? = + try { + if(readBoolean()) + null + else + FluidStack.loadFluidStackFromNBT(readCompoundTag()) + } catch(e: IOException) { + Catalyx.LOGGER.catching(e) + null + } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Set.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Set.kt similarity index 77% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Set.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Set.kt index 5d533c0..d06d75d 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Set.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Set.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import it.unimi.dsi.fastutil.objects.ObjectSets import java.util.* diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/String.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/String.kt similarity index 50% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/String.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/String.kt index eb7d9e7..fdb2bcc 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/String.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/String.kt @@ -1,8 +1,9 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.block.Block +import net.minecraft.block.state.IBlockState import net.minecraft.client.resources.I18n import net.minecraft.item.Item import net.minecraft.item.ItemStack @@ -12,7 +13,7 @@ import net.minecraft.util.ResourceLocation import net.minecraftforge.fml.common.Loader import net.minecraftforge.oredict.OreDictionary import net.minecraftforge.oredict.OreIngredient -import org.ender_development.catalyx.core.utils.SideUtils +import org.ender_development.catalyx.api.v1.utils.Utils inline fun String.toPotion(): Potion = Potion.getPotionFromResourceLocation(this)!! @@ -20,12 +21,29 @@ inline fun String.toPotion(): Potion = inline fun String.toOre() = OreIngredient(this) +fun String.toResourceLocation(): ResourceLocation { + val split = split(':') + return if(split.size == 1) ResourceLocation(this) else ResourceLocation(split[0], split[1]) +} + fun String.toStack(quantity: Int = 1, meta: Int = 0): ItemStack { val split = split(':') - val meta = split.getOrNull(2)?.toInt() ?: meta - val location = if(split.size == 1) ResourceLocation(this) else ResourceLocation(split[0], split[1]) + val meta = split.getApplyOrDefault(2, String::toInt) { meta } + + return toItem()?.toStack(quantity, meta) ?: toBlock()?.toStack(quantity, meta).orEmpty() +} + +inline fun String.toItem(): Item? = + Item.REGISTRY.registryObjects[toResourceLocation()] - return Item.REGISTRY.registryObjects[location]?.toStack(quantity, meta) ?: Block.REGISTRY.registryObjects[location]?.toStack(quantity, meta) ?: ItemStack.EMPTY +inline fun String.toBlock(): Block? = + Block.REGISTRY.registryObjects[toResourceLocation()] + +fun String.toBlockState(meta: Int = 0): IBlockState? { + val split = split(':') + val meta = split.getApplyOrDefault(2, String::toInt) { meta } + @Suppress("DEPRECATION") + return toBlock()?.getStateFromMeta(meta) } inline fun String.toIngredient(meta: Int = 0): Ingredient = @@ -35,11 +53,12 @@ inline fun String.toDict(prefix: String) = "$prefix${replaceFirstChar(Char::uppercaseChar)}" inline fun String.firstOre(): ItemStack = - OreDictionary.getOres(this).firstOrNull() ?: ItemStack.EMPTY + OreDictionary.getOres(this).firstOrNull().orEmpty() fun String.translate(vararg format: Any): String = - if(SideUtils.isServer) - this + if(Utils.environment.isServer) + @Suppress("DEPRECATION") + net.minecraft.util.text.translation.I18n.translateToLocalFormatted(this, *format) else I18n.format(this, *format) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/TextFormatting.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/TextFormatting.kt similarity index 59% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/TextFormatting.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/TextFormatting.kt index 589aa95..0104cd8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/TextFormatting.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/TextFormatting.kt @@ -1,7 +1,7 @@ -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.util.text.TextFormatting -import org.ender_development.catalyx.core.utils.ColorMapping +import org.ender_development.catalyx.api.v1.common.ColorMapping val TextFormatting.colorValue inline get() = ColorMapping[this] diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Vec3d.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Vec3d.kt similarity index 76% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Vec3d.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Vec3d.kt index 7d16a09..83232b6 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Vec3d.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Vec3d.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.util.math.Vec3d diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Vec3i.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Vec3i.kt similarity index 83% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Vec3i.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Vec3i.kt index 4aa1ef5..d582c3e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Vec3i.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/common/extensions/Vec3i.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package org.ender_development.catalyx.core.utils.extensions +package org.ender_development.catalyx.api.v1.common.extensions import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3i diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/Modules.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/Modules.kt new file mode 100644 index 0000000..65731d1 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/Modules.kt @@ -0,0 +1,38 @@ +package org.ender_development.catalyx.api.v1.modules + +/** + * API-Status: NOT-FROZEN + * Beware + */ + +import org.ender_development.catalyx.api.v1.modules.interfaces.IModuleIdentifier +import org.ender_development.catalyx.api.v1.modules.interfaces.IModuleManager +import org.ender_development.catalyx.core.module.ModuleIdentifier +import org.ender_development.catalyx.core.module.ModuleManager + +object Modules { + /** + * Contains the current [ModuleManager] implementation + */ + val moduleManager: IModuleManager = ModuleManager + + /** + * Factory for [IModuleManager], currently implemented by [ModuleIdentifier] + */ + fun newModuleIdentifier(containerId: String, moduleId: String): IModuleIdentifier = + ModuleIdentifier(containerId, moduleId) + + /** + * Factory for [IModuleManager], currently implemented by [ModuleIdentifier] + */ + fun newModuleIdentifier(identifier: String): IModuleIdentifier { + if(identifier.isBlank()) + error("Identifier is blank") + + val split = identifier.split(':') + if(split.size != 2) + error("Identifier does not follow the required format of 'containerId:moduleId'") + + return ModuleIdentifier(split[0], split[1]) + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/module/CatalyxModule.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/annotations/CatalyxModule.kt similarity index 89% rename from src/main/kotlin/org/ender_development/catalyx/core/module/CatalyxModule.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/modules/annotations/CatalyxModule.kt index 4868a63..3127e25 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/module/CatalyxModule.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/annotations/CatalyxModule.kt @@ -1,9 +1,10 @@ -package org.ender_development.catalyx.core.module +package org.ender_development.catalyx.api.v1.modules.annotations import org.ender_development.catalyx.core.Reference /** - * All of your [ICatalyxModule] classes must be annotated with this to be registered. + * All of your [org.ender_development.catalyx.api.v1.modules.interfaces.ICatalyxModule] + * classes must be annotated with this to be registered. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/module/CatalyxModuleContainer.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/annotations/CatalyxModuleContainer.kt similarity index 86% rename from src/main/kotlin/org/ender_development/catalyx/core/module/CatalyxModuleContainer.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/modules/annotations/CatalyxModuleContainer.kt index 6971f50..83e4e5e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/module/CatalyxModuleContainer.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/annotations/CatalyxModuleContainer.kt @@ -1,4 +1,4 @@ -package org.ender_development.catalyx.core.module +package org.ender_development.catalyx.api.v1.modules.annotations /** * Annotate your Module Containers with this for it to be automatically registered. diff --git a/src/main/kotlin/org/ender_development/catalyx/core/module/ICatalyxModule.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/ICatalyxModule.kt similarity index 83% rename from src/main/kotlin/org/ender_development/catalyx/core/module/ICatalyxModule.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/ICatalyxModule.kt index 8ac98d9..ce93122 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/module/ICatalyxModule.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/ICatalyxModule.kt @@ -1,14 +1,17 @@ -package org.ender_development.catalyx.core.module +package org.ender_development.catalyx.api.v1.modules.interfaces import net.minecraftforge.fml.common.event.* import org.apache.logging.log4j.Logger +import org.ender_development.catalyx.api.v1.modules.Modules /** * All modules must implement this interface. * * Provides methods for responding to FML lifecycle events and adding event bus subscribers. * - * Note: if your Module is an `object`, and other parts of your code access it, please don't have any side-effects in the class initialisation/instantiation, as any module can be disabled via the Catalyx config, or by its dependencies being unmet. + * Note: If your Module is a Kotlin `object`, and other parts of your code access it, + * please don't have any side effects in the class initialisation/instantiation, + * as any module can be disabled via the Catalyx config, or by its dependencies being unmet. */ interface ICatalyxModule { /** @@ -20,7 +23,7 @@ interface ICatalyxModule { * A boolean indicating whether this module is enabled. */ val enabled: Boolean - get() = ModuleManager.isModuleEnabled(this) + get() = Modules.moduleManager.isModuleEnabled(this) /** * Called when this module is loaded. diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/IModuleIdentifier.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/IModuleIdentifier.kt new file mode 100644 index 0000000..616ac83 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/IModuleIdentifier.kt @@ -0,0 +1,17 @@ +package org.ender_development.catalyx.api.v1.modules.interfaces + +import net.minecraft.util.ResourceLocation + +/** + * An identifier thet identifies a module + */ +interface IModuleIdentifier { + val containerId: String + val moduleId: String + + /** + * Convert this to a [ResourceLocation], for whatever reason. + */ + fun toResourceLocation() = + ResourceLocation(containerId, moduleId) +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/IModuleManager.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/IModuleManager.kt new file mode 100644 index 0000000..d5e40a2 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/modules/interfaces/IModuleManager.kt @@ -0,0 +1,38 @@ +package org.ender_development.catalyx.api.v1.modules.interfaces + +import org.ender_development.catalyx.api.v1.modules.Modules + +/** + * Interface for the actual [ModuleManager][org.ender_development.catalyx.core.module.ModuleManager] + * + * @see [org.ender_development.catalyx.api.v1.modules.Modules.moduleManager] + */ +interface IModuleManager { + /** + * Check if a module with the given [containerId] and [moduleId] is enabled + */ + fun isModuleEnabled(containerId: String, moduleId: String) = + isModuleEnabled(Modules.newModuleIdentifier(containerId, moduleId)) + + /** + * Check if a module with the given [identifier] is enabled + */ + fun isModuleEnabled(identifier: IModuleIdentifier): Boolean + + /** + * Checkup if a given module is enabled + */ + fun isModuleEnabled(module: ICatalyxModule): Boolean + + /** + * Registers a Module Container + */ + fun registerContainer(container: Any) + + /** + * The active Module Container instance, if any. + * + * Set during initialisation and lifecycle calls. + */ + val activeContainer: Any? +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/ICatalyxProviderRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/ICatalyxProviderRegistry.kt new file mode 100644 index 0000000..5a6157d --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/ICatalyxProviderRegistry.kt @@ -0,0 +1,18 @@ +package org.ender_development.catalyx.api.v1.registry + +import net.minecraft.util.ResourceLocation + +interface ICatalyxProviderRegistry> : Map> { + /** + * Adds a provider to this collection + * + * @return true, unless something stupid happened + */ + fun add(provider: V): Boolean + + /** + * List of all enabled providers + */ + val enabled: List + get() = values.mapNotNull { (provider, enabled) -> provider.takeIf { enabled } } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/ICatalyxRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/ICatalyxRegistry.kt new file mode 100644 index 0000000..b24a937 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/ICatalyxRegistry.kt @@ -0,0 +1,39 @@ +package org.ender_development.catalyx.api.v1.registry + +import net.minecraftforge.client.event.ModelBakeEvent +import net.minecraftforge.client.event.ModelRegistryEvent +import net.minecraftforge.client.event.TextureStitchEvent +import net.minecraftforge.event.RegistryEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.registries.IForgeRegistryEntry +import org.ender_development.catalyx.core.registry.CatalyxProviderRegistry + +/** + * A hook for a [CatalyxProviderRegistry] that lets register their content + * + * @param E the corresponding [IForgeRegistryEntry] + * @param P the [IProvider] type + */ +interface ICatalyxRegistry, P : IProvider> { + /** + * The set of providers to be registered. + */ + val registry: CatalyxProviderRegistry

+ + /** + * Register all enabled providers with the given event. + * + * @param event The registry event. + */ + fun registerProvider(event: RegistryEvent.Register) + + @SideOnly(Side.CLIENT) + fun registerModel(event: ModelRegistryEvent) + + @SideOnly(Side.CLIENT) + fun bakeModel(event: ModelBakeEvent) + + @SideOnly(Side.CLIENT) + fun stitchTexture(event: TextureStitchEvent.Pre) +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/IProvider.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/IProvider.kt new file mode 100644 index 0000000..e3799d5 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/IProvider.kt @@ -0,0 +1,106 @@ +package org.ender_development.catalyx.api.v1.registry + +import net.minecraft.block.Block +import net.minecraft.client.renderer.block.model.ModelResourceLocation +import net.minecraft.item.Item +import net.minecraft.item.ItemBlock +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.event.ModelRegistryEvent +import net.minecraftforge.client.model.ModelLoader +import net.minecraftforge.event.RegistryEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.registries.IForgeRegistryEntry + +/** + * A provider of items or blocks to be registered. + */ +interface IProvider> { + /** + * The instance provided by this provider. + */ + val instance: T + + /** + * Whether this provider is enabled and should be registered. + */ + fun isEnabled() = + true + + /** + * Register this provider's item/block with the given event. + * This will only be called when the provider is [enabled][isEnabled]. + * + * @param event The registry event. + */ + fun register(event: RegistryEvent.Register) = + event.registry.register(instance) + + /** + * Register this provider's model, this comes with a default implementation. + * + * @param event The registry event. + */ + @SideOnly(Side.CLIENT) + fun registerModel(event: ModelRegistryEvent) + + /** + * [ResourceLocation] of the model parent + */ + val modelParent: ResourceLocation + + /** + * [ResourceLocation] of the model file + */ + val modelLocation: ResourceLocation + + /** + * [ResourceLocation] of the texture file + */ + val textureLocation: ResourceLocation +} + +interface IItemProvider : IProvider { + @SideOnly(Side.CLIENT) + override fun registerModel(event: ModelRegistryEvent) = + ModelLoader.setCustomModelResourceLocation(instance, 0, ModelResourceLocation(instance.registryName!!, "inventory")) + + override val modelParent: ResourceLocation + get() = ResourceLocation("minecraft", "item/generated") + + override val modelLocation: ResourceLocation + get() = ResourceLocation(instance.registryName!!.namespace, "item/${instance.registryName!!.path}") + + override val textureLocation: ResourceLocation + get() = ResourceLocation(instance.registryName!!.namespace, "items/${instance.registryName!!.path}") +} + +interface IBlockProvider : IProvider { + /** + * Override this instead of [registerItemBlock] if you only want to change the registered Item associated with this Block (like with a [org.ender_development.catalyx.core.items.TooltipItemBlock]) + */ + val item: Item + get() = ItemBlock(instance).setRegistryName(instance.registryName) + + /** + * Register the Item for this Block with the given event. + * This will only be called, when the provider is [enabled][isEnabled]. + * + * @param event The registry event for Items. + */ + fun registerItemBlock(event: RegistryEvent.Register) = + event.registry.register(item) + + @SideOnly(Side.CLIENT) + override fun registerModel(event: ModelRegistryEvent) = + ModelLoader.setCustomModelResourceLocation(item, 0, ModelResourceLocation(item.registryName!!, "inventory")) + + override val textureLocation: ResourceLocation + get() = ResourceLocation(instance.registryName!!.namespace, "blocks/${instance.registryName!!.path}") + + override val modelLocation: ResourceLocation + get() = ResourceLocation(instance.registryName!!.namespace, "block/${instance.registryName!!.path}") + + override val modelParent: ResourceLocation + get() = ResourceLocation("minecraft", "block/cube_all") +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/Registry.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/Registry.kt new file mode 100644 index 0000000..1ddc22e --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/registry/Registry.kt @@ -0,0 +1,31 @@ +package org.ender_development.catalyx.api.v1.registry + +import net.minecraft.block.Block +import net.minecraft.item.Item +import org.ender_development.catalyx.core.registry.CatalyxBlockRegistry +import org.ender_development.catalyx.core.registry.CatalyxItemRegistry +import org.ender_development.catalyx.core.registry.CatalyxProviderRegistry + +/** + * API-Status: NOT-FROZEN + * Beware + */ + + +object Registry { + /** + * Factory for a new [CatalyxProviderRegistry] + */ + fun > newCatalyxProviderRegistry(): ICatalyxProviderRegistry = + CatalyxProviderRegistry() + + /** + * Contains the Catalyx implementation of the [ICatalyxRegistry] for [Item] + */ + val catalyxItemRegistry: ICatalyxRegistry = CatalyxItemRegistry + + /** + * Contains the Catalyx implementation of the [ICatalyxRegistry] for [Block] + */ + val catalyxBlockRegistry: ICatalyxRegistry = CatalyxBlockRegistry +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/Utils.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/Utils.kt new file mode 100644 index 0000000..874f920 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/Utils.kt @@ -0,0 +1,53 @@ +package org.ender_development.catalyx.api.v1.utils + +import net.minecraft.tileentity.TileEntity +import net.minecraftforge.fluids.Fluid +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.FluidTank +import org.ender_development.catalyx.api.v1.utils.interfaces.IBlockPosUtils +import org.ender_development.catalyx.api.v1.utils.interfaces.IEnvironmentUtils +import org.ender_development.catalyx.core.utils.BlockPosUtils +import org.ender_development.catalyx.core.utils.EnvironmentUtils + +object Utils { + val blockPos: IBlockPosUtils = BlockPosUtils + + val environment: IEnvironmentUtils = EnvironmentUtils + + // TODO find an abstraction + /** + * [This can't be an extension as of right now there is no way to create a static extension of a JVM class.](https://youtrack.jetbrains.com/issue/KT-11968) + */ + @Suppress("ClassName") + object fluidTank { + inline fun create(tile: TileEntity, capacity: Int, canFill: Boolean, canDrain: Boolean, crossinline onContentsChangedCallback: () -> Unit) = + object : FluidTank(capacity) { + init { + setTileEntity(tile) + setCanFill(canFill) + setCanDrain(canDrain) + } + + override fun onContentsChanged() = + onContentsChangedCallback() + } + + inline fun create(tile: TileEntity, capacity: Int, canFill: Boolean, canDrain: Boolean, vararg fluidWhitelist: Fluid, crossinline onContentsChangedCallback: () -> Unit) = + object : FluidTank(capacity) { + init { + setTileEntity(tile) + setCanFill(canFill) + setCanDrain(canDrain) + } + + override fun onContentsChanged() = + onContentsChangedCallback() + + override fun canFillFluidType(fluid: FluidStack?) = + fluid != null && fluidWhitelist.any { fluid.fluid === it } + + override fun canDrainFluidType(fluid: FluidStack?) = + canFillFluidType(fluid) + } + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/math/BlockPosUtils.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/interfaces/IBlockPosUtils.kt similarity index 53% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/math/BlockPosUtils.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/utils/interfaces/IBlockPosUtils.kt index 94402a0..e3c84dc 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/math/BlockPosUtils.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/interfaces/IBlockPosUtils.kt @@ -1,11 +1,8 @@ -package org.ender_development.catalyx.core.utils.math +package org.ender_development.catalyx.api.v1.utils.interfaces import net.minecraft.util.math.BlockPos -import org.ender_development.catalyx.core.utils.extensions.minus -import org.ender_development.catalyx.core.utils.extensions.plus -import org.ender_development.catalyx.core.utils.extensions.rotateY -object BlockPosUtils { +interface IBlockPosUtils { /** * Creates a wall shape centered at [center] with radius [r] and height [h]. * @@ -17,23 +14,7 @@ object BlockPosUtils { * @param shrink Reduces wall width by shrink blocks on its far end to avoid corner overlaps. * @return A [Pair] of [BlockPos] representing the minimum and maximum corners of the wall. */ - fun wall(center: BlockPos, r: Int, h: Int, offset: Int = 0, degrees: Int = 0, shrink: Int = 0): Pair { - val baseOrigin = BlockPos(center.x - r, center.y, center.z + r + offset) - val v1 = BlockPos(2 * r - shrink, 0, 0) - val v2 = BlockPos(0, h, 0) - - val origin = (baseOrigin - center).rotateY(degrees) + center - val v1Rot = v1.rotateY(degrees) - - val corners = listOf( - origin, - origin + v1Rot, - origin + v2, - origin + v1Rot + v2 - ) - - return BlockPos(corners.minOf { it.x }, corners.minOf { it.y }, corners.minOf { it.z }) to BlockPos(corners.maxOf { it.x }, corners.maxOf { it.y }, corners.maxOf { it.z }) - } + fun wall(center: BlockPos, r: Int, h: Int, offset: Int = 0, degrees: Int = 0, shrink: Int = 0): Pair /** * Creates a hollow cuboid shape centered at [center] with radius [r] and height [h]. @@ -43,10 +24,7 @@ object BlockPosUtils { * @param r The radius from the center to the edges of the cuboid. * @param h The height of the cuboid. * @param offset An optional vertical offset to apply to the base of the cuboid. - * @return A [List] of [Pair]`s` of [BlockPos] representing the minimum and maximum corners of each wall. + * @return A length 4 array of [Pair]s of [BlockPos] representing the minimum and maximum corners of each wall, see [BlockPosUtils#wall][wall]. */ - fun hollowCuboid(center: BlockPos, r: Int, h: Int, offset: Int = 1, shrink: Int = 1) = - (0..3).map { - wall(center, r, h, offset, it * 90, shrink) - } + fun hollowCuboid(center: BlockPos, r: Int, h: Int, offset: Int = 1, shrink: Int = 1): Array> } diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/interfaces/IEnvironmentUtils.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/interfaces/IEnvironmentUtils.kt new file mode 100644 index 0000000..48f08ef --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/utils/interfaces/IEnvironmentUtils.kt @@ -0,0 +1,17 @@ +package org.ender_development.catalyx.api.v1.utils.interfaces + +/** + * Utility object for checking the current environment - side (client or server) and deobfuscation. + */ +interface IEnvironmentUtils { + val isClient: Boolean + val isServer: Boolean + val isDedicatedClient: Boolean + val isDedicatedServer: Boolean + + /** + * Whether you're in a deobfuscated (dev) environment + * @see [CoreModManager:208][net.minecraftforge.fml.relauncher.CoreModManager] + */ + val isDeobfuscated: Boolean +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/CommonValidators.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/CommonValidators.kt similarity index 58% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/validation/CommonValidators.kt rename to src/main/kotlin/org/ender_development/catalyx/api/v1/validation/CommonValidators.kt index 6ea7edd..b684fc9 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/CommonValidators.kt +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/CommonValidators.kt @@ -1,5 +1,11 @@ -package org.ender_development.catalyx.core.utils.validation - +package org.ender_development.catalyx.api.v1.validation + +import net.minecraft.item.ItemStack +import org.ender_development.catalyx.api.v1.common.extensions.toBlock +import org.ender_development.catalyx.api.v1.common.extensions.toBlockState +import org.ender_development.catalyx.api.v1.common.extensions.toItem +import org.ender_development.catalyx.api.v1.common.extensions.toStack +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidator import org.ender_development.catalyx.core.config.ConfigParser @Suppress("UNUSED") @@ -34,12 +40,12 @@ object CommonValidators { fun atMost(value: Number): IValidator = IValidator { it != null && it.toDouble() <= value.toDouble() } - fun oneOf(vararg values: T): IValidator = - IValidator { it != null && values.contains(it) } + fun oneOf(vararg allowed: T): IValidator = + IValidator { it != null && it in allowed } fun listAll(elementValidator: IValidator): IValidator?> = IValidator { list -> - list != null && list.all { elementValidator.validate(it) } + list != null && list.all(elementValidator::validate) } fun mapAll(keyValidator: IValidator, valueValidator: IValidator): IValidator?> = @@ -49,37 +55,15 @@ object CommonValidators { } } - fun isItemStack(): IValidator = IValidator { - if(it == null) - return@IValidator false - - return@IValidator try { - ConfigParser.ConfigItemStack(it).toItemStack() - true - } catch(_: Exception) { - false - } - } - - fun isBlockState(): IValidator = IValidator { - if(it == null) - return@IValidator false + fun isItemStack(): IValidator = + IValidator { it != null && it.toStack() != ItemStack.EMPTY } - return@IValidator try { - ConfigParser.ConfigBlockState(it).state != null - } catch(_: Exception) { - false - } - } + fun isBlockState(): IValidator = + IValidator { it != null && it.toBlockState() != null } - fun isBlock(): IValidator = IValidator { - if(it == null) - return@IValidator false + fun isBlock(): IValidator = + IValidator { it != null && it.toBlock() != null } - return@IValidator try { - ConfigParser.ConfigBlockState(it).block != null - } catch(_: Exception) { - false - } - } + fun isItem(): IValidator = + IValidator { it != null && it.toItem() != null } } diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/Validation.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/Validation.kt new file mode 100644 index 0000000..84856ed --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/Validation.kt @@ -0,0 +1,23 @@ +package org.ender_development.catalyx.api.v1.validation + +import org.ender_development.catalyx.api.v1.common.Severity +import org.ender_development.catalyx.api.v1.validation.interfaces.IFieldValidationBuilder +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationBuilder +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationResult +import org.ender_development.catalyx.core.validation.ValidationError +import org.ender_development.catalyx.core.validation.ValidationResult + +object Validation { + fun newValidationError(field: String? = null, message: String, code: String? = null, severity: Severity = Severity.ERROR): IValidationError = + ValidationError(field, message, code, severity) + + fun newValidationBuilder(): IValidationBuilder = TODO() + fun newFieldValidationBuilder(): IFieldValidationBuilder = TODO() + + fun IValidationResult.success(data: T): IValidationResult = + ValidationResult.success(data) + + fun IValidationResult.failure(errors: List): IValidationResult = + ValidationResult.failure(errors) +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IFieldValidationBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IFieldValidationBuilder.kt new file mode 100644 index 0000000..4895f4f --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IFieldValidationBuilder.kt @@ -0,0 +1,28 @@ +package org.ender_development.catalyx.api.v1.validation.interfaces + +import org.ender_development.catalyx.core.validation.FieldValidationBuilder + +interface IFieldValidationBuilder { + // TODO ask Ender for whether these KDocs are accurate/correct, this is his system after all + // this is kinda confusing to document + + /** + * Validate the current value of this builder with the [validator]. + */ + fun validate(validator: IValidator): IFieldValidationBuilder + + /** + * If the last message in the parent validator is related to this field, replace it with the passed in [message]. + */ + fun withMessage(message: String): FieldValidationBuilder + + /** + * Get the final validated field, or, if null, the specified [defaultValue]. + */ + fun orElse(defaultValue: V): V + + /** + * Get the final validated field. + */ + fun get(): V? +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationBuilder.kt new file mode 100644 index 0000000..6fbbe5a --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationBuilder.kt @@ -0,0 +1,5 @@ +package org.ender_development.catalyx.api.v1.validation.interfaces + +interface IValidationBuilder { + // TODO +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationError.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationError.kt new file mode 100644 index 0000000..e61f443 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationError.kt @@ -0,0 +1,14 @@ +package org.ender_development.catalyx.api.v1.validation.interfaces + +import org.apache.logging.log4j.Logger +import org.ender_development.catalyx.api.v1.common.Severity + +interface IValidationError { + val field: String? + val message: String + val code: String? + val severity: Severity + + fun log(logger: Logger) = + logger.log(severity.loggerLevel, toString()) +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationResult.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationResult.kt new file mode 100644 index 0000000..39e2683 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidationResult.kt @@ -0,0 +1,12 @@ +package org.ender_development.catalyx.api.v1.validation.interfaces + +interface IValidationResult { + val data: T? + val errors: List + val success: Boolean + get() = errors.isEmpty() + val failure: Boolean + get() = !success + val errorMessages: List + get() = errors.map(IValidationError::message) +} diff --git a/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidator.kt b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidator.kt new file mode 100644 index 0000000..0913199 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/api/v1/validation/interfaces/IValidator.kt @@ -0,0 +1,5 @@ +package org.ender_development.catalyx.api.v1.validation.interfaces + +fun interface IValidator { + fun validate(value: T): Boolean +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/ICatalyxMod.kt b/src/main/kotlin/org/ender_development/catalyx/core/ICatalyxMod.kt index c06d6ad..28163f3 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/ICatalyxMod.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/ICatalyxMod.kt @@ -1,11 +1,14 @@ +@file:Suppress("NOTHING_TO_INLINE", "UnusedReceiverParameter") + package org.ender_development.catalyx.core import net.minecraft.creativetab.CreativeTabs +import net.minecraft.util.ResourceLocation import net.minecraftforge.fml.common.Mod +import org.ender_development.catalyx.api.v1.registry.IBlockProvider +import org.ender_development.catalyx.api.v1.registry.IItemProvider import org.ender_development.catalyx.core.registry.CatalyxBlockRegistry import org.ender_development.catalyx.core.registry.CatalyxItemRegistry -import org.ender_development.catalyx.core.registry.IBlockProvider -import org.ender_development.catalyx.core.registry.IItemProvider interface ICatalyxMod { companion object { @@ -36,10 +39,14 @@ interface ICatalyxMod { } // helper functions -@Suppress("NOTHING_TO_INLINE") inline fun ICatalyxMod.register(item: IItemProvider) = CatalyxItemRegistry.registry.add(item) -@Suppress("NOTHING_TO_INLINE") inline fun ICatalyxMod.register(block: IBlockProvider) = CatalyxBlockRegistry.registry.add(block) + +inline fun ICatalyxMod.toResourceLocation(name: String) = + ResourceLocation(modId, name) + +inline fun ICatalyxMod.toLanguageKey(langKey: String) = + "$modId.$langKey" diff --git a/src/main/kotlin/org/ender_development/catalyx/core/animation/NoopAnimationStateMachine.kt b/src/main/kotlin/org/ender_development/catalyx/core/animation/NoopAnimationStateMachine.kt index 2deea36..3fa5138 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/animation/NoopAnimationStateMachine.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/animation/NoopAnimationStateMachine.kt @@ -5,12 +5,12 @@ import net.minecraft.util.ResourceLocation import net.minecraftforge.client.model.ModelLoaderRegistry import net.minecraftforge.common.animation.ITimeValue import net.minecraftforge.common.model.animation.IAnimationStateMachine -import org.ender_development.catalyx.core.utils.SideUtils +import org.ender_development.catalyx.api.v1.utils.Utils class NoopAnimationStateMachine() : IAnimationStateMachine { companion object { fun loadASM(location: ResourceLocation, customParameters: Map): IAnimationStateMachine = - if(SideUtils.isDedicatedServer) + if(Utils.environment.isDedicatedServer) NoopAnimationStateMachine() else ModelLoaderRegistry.loadASM(location, ImmutableMap.copyOf(customParameters)) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseBlock.kt index ccbb5fa..8ed7f1d 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseBlock.kt @@ -4,20 +4,14 @@ import net.minecraft.block.Block import net.minecraft.block.material.Material import net.minecraft.block.state.BlockFaceShape import net.minecraft.block.state.IBlockState -import net.minecraft.client.renderer.block.model.ModelResourceLocation -import net.minecraft.item.Item -import net.minecraft.item.ItemBlock import net.minecraft.util.EnumFacing import net.minecraft.util.ResourceLocation import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos import net.minecraft.world.IBlockAccess -import net.minecraftforge.client.model.ModelLoader -import net.minecraftforge.event.RegistryEvent +import org.ender_development.catalyx.api.v1.registry.IBlockProvider import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.register -import org.ender_development.catalyx.core.registry.IBlockProvider -import org.ender_development.catalyx.core.utils.SideUtils /** * A base Catalyx Block @@ -25,7 +19,7 @@ import org.ender_development.catalyx.core.utils.SideUtils open class BaseBlock(val mod: ICatalyxMod, name: String, material: Material = Material.ROCK, hardness: Float = 3f) : Block(material), IBlockProvider { init { registryName = ResourceLocation(mod.modId, name) - translationKey = "$registryName" + translationKey = "${mod.modId}:$name" blockHardness = hardness creativeTab = mod.creativeTab } @@ -36,31 +30,7 @@ open class BaseBlock(val mod: ICatalyxMod, name: String, material: Material = Ma override val instance = this - override var modDependencies = "" - - override val item = ItemBlock(this) - - override fun isEnabled() = - true - - override fun register(event: RegistryEvent.Register) = - event.registry.register(this) - - override fun registerItemBlock(event: RegistryEvent.Register) { - item.registryName = registryName - event.registry.register(item) - if(SideUtils.isClient) - ModelLoader.setCustomModelResourceLocation(item, 0, ModelResourceLocation(registryName!!, "inventory")) - } - - override fun requires(modDependencies: String): Block { - this.modDependencies = modDependencies - mod.register(this) - return this - } - init { - // TODO: why do we have 2 init blocks? mod.register(this) } @@ -74,7 +44,8 @@ open class BaseBlock(val mod: ICatalyxMod, name: String, material: Material = Ma * @param state The block state of the edge block. * @return The AABB of the edge block. */ - open fun getAABB(state: IBlockState): AxisAlignedBB = FULL_BLOCK_AABB + open fun getAABB(state: IBlockState): AxisAlignedBB = + FULL_BLOCK_AABB // We override these methods with a AABB check instead of hardcoding its return value @Deprecated("Implementation is fine.") @@ -96,12 +67,12 @@ open class BaseBlock(val mod: ICatalyxMod, name: String, material: Material = Ma override fun getBlockFaceShape(worldIn: IBlockAccess, state: IBlockState, pos: BlockPos, face: EnumFacing): BlockFaceShape { val aabb = getAABB(state) return when (face) { - EnumFacing.UP -> if (aabb.maxY >= 1.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED - EnumFacing.DOWN -> if (aabb.minY <= 0.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED - EnumFacing.NORTH -> if (aabb.minZ <= 0.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED - EnumFacing.SOUTH -> if (aabb.maxZ >= 1.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED - EnumFacing.WEST -> if (aabb.minX <= 0.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED - EnumFacing.EAST -> if (aabb.maxX >= 1.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED + EnumFacing.UP -> if(aabb.maxY >= 1.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED + EnumFacing.DOWN -> if(aabb.minY <= .0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED + EnumFacing.NORTH -> if(aabb.minZ <= .0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED + EnumFacing.SOUTH -> if(aabb.maxZ >= 1.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED + EnumFacing.WEST -> if(aabb.minX <= .0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED + EnumFacing.EAST -> if(aabb.maxX >= 1.0) BlockFaceShape.SOLID else BlockFaceShape.UNDEFINED } } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseMachineBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseMachineBlock.kt index e841eb7..ce8249f 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseMachineBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseMachineBlock.kt @@ -15,7 +15,7 @@ import org.ender_development.catalyx.core.tiles.BaseTile open class BaseMachineBlock : BaseTileBlock { constructor(mod: ICatalyxMod, name: String, tileClass: Class, guiId: Int) : super(mod, name, tileClass, guiId) /** - * Only use this constructor if you used a [org.ender_development.catalyx.client.gui.CatalyxGuiHandler] for the guiId + * Only use this constructor if you used a [org.ender_development.catalyx.core.client.gui.CatalyxGuiHandler] for the guiId */ constructor(mod: ICatalyxMod, name: String, guiId: Int) : super(mod, name, guiId) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableMachineBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableMachineBlock.kt index 20e45f0..0e2f4b5 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableMachineBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableMachineBlock.kt @@ -14,7 +14,7 @@ import org.ender_development.catalyx.core.ICatalyxMod open class BaseRotatableMachineBlock : BaseMachineBlock { constructor(mod: ICatalyxMod, name: String, tileClass: Class, guiId: Int) : super(mod, name, tileClass, guiId) /** - * Only use this constructor if you used a [org.ender_development.catalyx.client.gui.CatalyxGuiHandler] for the guiId + * Only use this constructor if you used a [org.ender_development.catalyx.core.client.gui.CatalyxGuiHandler] for the guiId */ constructor(mod: ICatalyxMod, name: String, guiId: Int) : super(mod, name, guiId) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableTileBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableTileBlock.kt index a51911c..c984d5e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableTileBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseRotatableTileBlock.kt @@ -14,7 +14,7 @@ import org.ender_development.catalyx.core.ICatalyxMod open class BaseRotatableTileBlock : BaseTileBlock { constructor(mod: ICatalyxMod, name: String, tileClass: Class, guiId: Int) : super(mod, name, tileClass, guiId) /** - * Only use this constructor if you used a [org.ender_development.catalyx.client.gui.CatalyxGuiHandler] for the guiId + * Only use this constructor if you used a [org.ender_development.catalyx.core.client.gui.CatalyxGuiHandler] for the guiId */ constructor(mod: ICatalyxMod, name: String, guiId: Int) : super(mod, name, guiId) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseTileBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseTileBlock.kt index 30e79b0..cdc0bc0 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseTileBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/BaseTileBlock.kt @@ -26,7 +26,7 @@ import org.ender_development.catalyx.core.tiles.BaseTile */ open class BaseTileBlock(mod: ICatalyxMod, name: String, val tileClass: Class, val guiId: Int) : BaseBlock(mod, name), ITileEntityProvider { /** - * Only use this constructor if you used a [org.ender_development.catalyx.client.gui.CatalyxGuiHandler] for the guiId + * Only use this constructor if you used a [org.ender_development.catalyx.core.client.gui.CatalyxGuiHandler] for the guiId */ constructor(mod: ICatalyxMod, name: String, guiId: Int) : this(mod, name, CatalyxGuiHandler.instances[mod]?.tileEntities[guiId] ?: error("Tried to use the BaseTileBlock constructor without a tileClass without using a CatalyxGuiHandler to register the GUI handler"), guiId) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/TESRTileBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/TESRTileBlock.kt index 25aa692..2e665df 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/TESRTileBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/TESRTileBlock.kt @@ -1,17 +1,17 @@ package org.ender_development.catalyx.core.blocks import net.minecraftforge.fml.client.registry.ClientRegistry +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.client.tesr.TileRenderer import org.ender_development.catalyx.core.tiles.TESRTile -import org.ender_development.catalyx.core.utils.SideUtils /** * A rotatable block that has a TESR. Binds the [TileRenderer] to the tile entity on the client side. */ open class TESRTileBlock(mod: ICatalyxMod, name: String, tileClass: Class, guiId: Int) : BaseRotatableTileBlock(mod, name, tileClass, guiId) { init { - if(SideUtils.isClient) + if(Utils.environment.isClient) ClientRegistry.bindTileEntitySpecialRenderer(tileClass, TileRenderer) } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/blocks/multiblock/CenterBlock.kt b/src/main/kotlin/org/ender_development/catalyx/core/blocks/multiblock/CenterBlock.kt index 1a55403..edf9c94 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/blocks/multiblock/CenterBlock.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/blocks/multiblock/CenterBlock.kt @@ -8,9 +8,9 @@ import net.minecraft.tileentity.TileEntity import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos import net.minecraft.world.World +import org.ender_development.catalyx.api.v1.common.extensions.getHorizontalSurroundings import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.blocks.BaseRotatableTileBlock -import org.ender_development.catalyx.core.utils.extensions.getHorizontalSurroundings open class CenterBlock(mod: ICatalyxMod, name: String, tileClass: Class, guiId: Int, vararg components: IMultiblockEdge) : BaseRotatableTileBlock( mod, name, tileClass, guiId diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/AreaHighlighter.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/AreaHighlighter.kt index b950bb3..42a7853 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/AreaHighlighter.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/AreaHighlighter.kt @@ -4,115 +4,50 @@ import io.netty.util.internal.ConcurrentSet import net.minecraft.client.Minecraft import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.GlStateManager -import net.minecraft.client.renderer.Tessellator import net.minecraft.client.renderer.vertex.DefaultVertexFormats -import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d import net.minecraftforge.client.event.RenderWorldLastEvent import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly +import org.ender_development.catalyx.api.v1.client.interfaces.IAreaHighlighter +import org.ender_development.catalyx.core.utils.RenderUtils import org.lwjgl.opengl.GL11 -/** - * A helper class allowing you to highlight an area or a block in 3D space - * @see [highlightBlock] - * @see [highlightBlocks] - * @see [highlightArea] - */ @SideOnly(Side.CLIENT) -class AreaHighlighter { - private var counter = 0 - private var counterDirection = 1 - - var shown = false - private set - var x1 = .0 - private set - var y1 = .0 - private set - var z1 = .0 - private set - val pos1 - get() = BlockPos(x1, y1, z1) - var x2 = .0 - private set - var y2 = .0 +internal class AreaHighlighter : IAreaHighlighter { + override var shown = false private set - var z2 = .0 + override var drawOutlinesFor = emptyArray>() private set - val pos2 - get() = BlockPos(x2, y2, z2) - var drawBlockPositions = false + override var r = 1f private set - var drawnBlockPositions = emptyArray() + override var g = 1f private set - var r = 1f + override var b = 1f private set - var g = 1f + override var until = 0L private set - var b = 1f - private set - var until = 0L - private set - var thickness = 3f - - /** - * r, g, b are colours between 0 and 1, time is in milliseconds - */ - fun highlightBlock(pos: BlockPos, r: Float, g: Float, b: Float, time: Int) { - x1 = pos.x.toDouble() - y1 = pos.y.toDouble() - z1 = pos.z.toDouble() - x2 = x1 + 1 - y2 = y1 + 1 - z2 = z1 + 1 - this.r = r - this.g = g - this.b = b - until = System.currentTimeMillis() + time.toLong() - show() - } + override var thickness = 3f - /** - * r, g, b are colours between 0 and 1, time is in milliseconds - */ - fun highlightArea(x1: Double, y1: Double, z1: Double, x2: Double, y2: Double, z2: Double, r: Float, g: Float, b: Float, time: Int) { - this.x1 = x1 - this.y1 = y1 - this.z1 = z1 - this.x2 = x2 - this.y2 = y2 - this.z2 = z2 - this.r = r - this.g = g - this.b = b - until = System.currentTimeMillis() + time.toLong() - show() - } + override fun highlightAreas(areas: Array>, r: Float, g: Float, b: Float, time: Int) { + if(areas.isEmpty()) + return - /** - * r, g, b are colours between 0 and 1, time is in milliseconds - */ - fun highlightBlocks(blockPositions: Array, r: Float, g: Float, b: Float, time: Int) { - drawBlockPositions = true - drawnBlockPositions = blockPositions + drawOutlinesFor = areas + shown = true this.r = r this.g = g this.b = b - until = System.currentTimeMillis() + time.toLong() + until = System.currentTimeMillis() + time show() } - /** - * call this if you want to prematurely hide the block highlight; - * otherwise, this is automatically called after the {time} passes - */ - fun hide() { + override fun hide() { eventHandlers.remove(::eventHandler) shown = false counter = 0 counterDirection = 1 - drawBlockPositions = false - drawnBlockPositions = emptyArray() + drawOutlinesFor = emptyArray() } internal fun show() { @@ -120,10 +55,9 @@ class AreaHighlighter { shown = true } - internal companion object { - val eventHandlers = ConcurrentSet<(RenderWorldLastEvent) -> Unit>() - } - + private var counter = 0 + private var counterDirection = 1 + private fun eventHandler(event: RenderWorldLastEvent) { if(!shown) return hide() @@ -141,30 +75,26 @@ class AreaHighlighter { val alpha = .5f + counter / 100f val p = Minecraft.getMinecraft().player - val doubleX = p.lastTickPosX + (p.posX - p.lastTickPosX) * event.partialTicks - val doubleY = p.lastTickPosY + (p.posY - p.lastTickPosY) * event.partialTicks - val doubleZ = p.lastTickPosZ + (p.posZ - p.lastTickPosZ) * event.partialTicks + val translateX = p.lastTickPosX + (p.posX - p.lastTickPosX) * event.partialTicks + val translateY = p.lastTickPosY + (p.posY - p.lastTickPosY) * event.partialTicks + val translateZ = p.lastTickPosZ + (p.posZ - p.lastTickPosZ) * event.partialTicks GlStateManager.pushMatrix() GlStateManager.enableBlend() GlStateManager.color(r, g, b, alpha) GlStateManager.glLineWidth(thickness) - GlStateManager.translate(-doubleX, -doubleY, -doubleZ) + GlStateManager.translate(-translateX, -translateY, -translateZ) GlStateManager.disableDepth() GlStateManager.disableTexture2D() + + RenderUtils.bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR) + + drawOutlinesFor.forEach { (from, to) -> + renderOutline(RenderUtils.bufferBuilder, from.x, from.y, from.z, to.x, to.y, to.z, r, g, b, alpha) + } - val tessellator = Tessellator.getInstance() - val buffer = tessellator.buffer - buffer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR) - if(!drawBlockPositions) - renderOutline(buffer, x1, y1, z1, x2 - x1, y2 - y1, z2 - z1, r, g, b, alpha) - else - drawnBlockPositions.forEach { - renderOutline(buffer, it.x.toDouble(), it.y.toDouble(), it.z.toDouble(), 1.0, 1.0, 1.0, r, g, b, alpha) - } - - tessellator.draw() + RenderUtils.tessellator.draw() GlStateManager.enableTexture2D() GlStateManager.enableDepth() @@ -172,33 +102,37 @@ class AreaHighlighter { GlStateManager.popMatrix() } - private fun renderOutline(buffer: BufferBuilder, mx: Double, my: Double, mz: Double, dx: Double, dy: Double, dz: Double, red: Float, green: Float, blue: Float, alpha: Float) { - buffer.pos(mx, my, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my + dy, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my + dy, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my + dy, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my + dy, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my + dy, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my + dy, mz ).color(red, green, blue, alpha).endVertex() - - buffer.pos(mx, my + dy, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my + dy, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my + dy, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my + dy, mz ).color(red, green, blue, alpha).endVertex() - - buffer.pos(mx + dx, my, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my, mz ).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my + dy, mz ).color(red, green, blue, alpha).endVertex() - - buffer.pos(mx, my, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx + dx, my, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my, mz + dz).color(red, green, blue, alpha).endVertex() - buffer.pos(mx, my + dy, mz + dz).color(red, green, blue, alpha).endVertex() + private fun renderOutline(buffer: BufferBuilder, mx: Double, my: Double, mz: Double, tx: Double, ty: Double, tz: Double, red: Float, green: Float, blue: Float, alpha: Float) { + buffer.pos(mx, my, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, my, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, my, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, ty, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, my, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, my, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, ty, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, ty, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, ty, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, my, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, ty, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, ty, mz).color(red, green, blue, alpha).endVertex() + + buffer.pos(mx, ty, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, ty, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, ty, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, ty, mz).color(red, green, blue, alpha).endVertex() + + buffer.pos(tx, my, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, my, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, my, mz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, ty, mz).color(red, green, blue, alpha).endVertex() + + buffer.pos(mx, my, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(tx, my, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, my, tz).color(red, green, blue, alpha).endVertex() + buffer.pos(mx, ty, tz).color(red, green, blue, alpha).endVertex() + } + + internal companion object { + val eventHandlers = ConcurrentSet<(RenderWorldLastEvent) -> Unit>() } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/ICustomModel.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/ICustomModel.kt new file mode 100644 index 0000000..b1b8eb0 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/ICustomModel.kt @@ -0,0 +1,43 @@ +package org.ender_development.catalyx.core.client + +import com.google.common.collect.ImmutableMap +import net.minecraft.client.renderer.block.model.ModelResourceLocation +import net.minecraft.client.renderer.block.model.ModelRotation +import net.minecraft.client.renderer.vertex.DefaultVertexFormats +import net.minecraftforge.client.event.ModelBakeEvent +import net.minecraftforge.client.event.TextureStitchEvent +import net.minecraftforge.client.model.ModelLoader +import net.minecraftforge.client.model.ModelLoaderRegistry +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.registry.IItemProvider +import org.ender_development.catalyx.core.client.sprite.DefaultSprite + +interface ICustomModel { + @SideOnly(Side.CLIENT) + fun onBakeModel(event: ModelBakeEvent) + + @SideOnly(Side.CLIENT) + fun onTextureStitch(event: TextureStitchEvent.Pre) +} + +interface IAutoModel : ICustomModel, IItemProvider { + @SideOnly(Side.CLIENT) + override fun onTextureStitch(event: TextureStitchEvent.Pre) { + event.map.setTextureEntry(DefaultSprite(textureLocation)) + } + + @SideOnly(Side.CLIENT) + override fun onBakeModel(event: ModelBakeEvent) { + try { + val baseModel = ModelLoaderRegistry.getModel(modelParent) + val retexturedModel = baseModel.retexture(ImmutableMap.of("layer0", textureLocation.toString())) + val bakedModel = retexturedModel.bake(ModelRotation.X0_Y0, DefaultVertexFormats.ITEM, ModelLoader.defaultTextureGetter()) + val bakedModelLoc = ModelResourceLocation(instance.delegate.name(), "inventory") + event.modelRegistry.putObject(bakedModelLoc, bakedModel) + } catch(e: Throwable) { + Catalyx.LOGGER.catching(e) + } + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/button/AbstractButtonWrapper.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/button/AbstractButtonWrapper.kt index d0dcbff..7ac5676 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/button/AbstractButtonWrapper.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/button/AbstractButtonWrapper.kt @@ -3,15 +3,14 @@ package org.ender_development.catalyx.core.client.button import io.netty.buffer.ByteBuf import net.minecraft.client.Minecraft import net.minecraft.client.gui.GuiButton -import net.minecraft.client.renderer.GlStateManager import net.minecraft.util.ResourceLocation import net.minecraftforge.fml.common.network.simpleimpl.MessageContext import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.client.button.AbstractButtonWrapper.Companion.getWrapper import org.ender_development.catalyx.core.client.button.AbstractButtonWrapper.Companion.registerWrapper -import org.ender_development.catalyx.core.utils.SideUtils /** * Wrapper class for stateful buttons sent from client-side to server-side @@ -24,9 +23,9 @@ import org.ender_development.catalyx.core.utils.SideUtils * - add a button to the buttonList by instantiating this class and doing [net.minecraft.client.gui.GuiScreen.buttonList].add(instance.[button]) * - override [net.minecraft.client.gui.GuiScreen.actionPerformed] and use [getWrapper] to identify/get buttons and their wrappers, if need be * - * On server-side in TEs that extend [org.ender_development.catalyx.tiles.helper.IButtonTile] - * - implement [org.ender_development.catalyx.tiles.helper.IButtonTile.handleButtonPress] and handle your button from there - * - if you cannot guarantee this class will be instantiated before any button clicks are received, call [registerWrapper] (ideally in your TE init {} block, see [org.ender_development.catalyx.tiles.BaseTile] for an example) + * On server-side in TEs that extend [org.ender_development.catalyx.core.tiles.helper.IButtonTile] + * - implement [org.ender_development.catalyx.core.tiles.helper.IButtonTile.handleButtonPress] and handle your button from there + * - if you cannot guarantee this class will be instantiated before any button clicks are received, call [registerWrapper] (ideally in your TE init {} block, see [org.ender_development.catalyx.core.tiles.BaseTile] for an example) */ abstract class AbstractButtonWrapper(x: Int, y: Int, width: Int = 16, height: Int = 16) { open val textureLocation = ResourceLocation(Reference.MODID, "textures/gui/container/gui.png") @@ -47,7 +46,6 @@ abstract class AbstractButtonWrapper(x: Int, y: Int, width: Int = 16, height: In if(!hovered) return - GlStateManager.color(1f, 1f, 1f) // +1/-1 to account for the border and only highlight the contents drawRect(x + 1, y + 1, x + width - 1, y + height - 1, 0x64ffffff) } @@ -82,7 +80,7 @@ abstract class AbstractButtonWrapper(x: Int, y: Int, width: Int = 16, height: In } /** Guaranteed to be non-null on client-side */ - open val button = if(SideUtils.isClient) + open val button = if(Utils.environment.isClient) WrappedGuiButton(x, y, width, height, this) else null diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/container/BaseContainer.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/container/BaseContainer.kt index 4ff938d..d44b5b8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/container/BaseContainer.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/container/BaseContainer.kt @@ -64,11 +64,11 @@ abstract class BaseContainer(playerInv: IInventory, val tileEntity: IBaseContain val stack = slot.stack // transfer TE Container -> Anywhere else (Player Inventory) - if(index < tileEntity.SIZE) { - if(!mergeItemStack(stack, tileEntity.SIZE, inventorySlots.size, true)) + if(index < tileEntity.inventorySlotCount) { + if(!mergeItemStack(stack, tileEntity.inventorySlotCount, inventorySlots.size, true)) return ItemStack.EMPTY // transfer Anywhere else (Player Inventory) -> TE Container - } else if(!mergeItemStack(stack, 0, tileEntity.SIZE, false)) + } else if(!mergeItemStack(stack, 0, tileEntity.inventorySlotCount, false)) return ItemStack.EMPTY if(stack.isEmpty) @@ -80,8 +80,7 @@ abstract class BaseContainer(playerInv: IInventory, val tileEntity: IBaseContain } interface IBaseContainerCompat : IGuiTile { - // TODO rename someday - val SIZE: Int + val inventorySlotCount: Int fun canInteractWith(player: EntityPlayer): Boolean } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/gui/BaseGuiTyped.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/gui/BaseGuiTyped.kt index b276f9c..044b772 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/gui/BaseGuiTyped.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/gui/BaseGuiTyped.kt @@ -5,6 +5,8 @@ import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager import net.minecraft.inventory.Container import net.minecraft.util.ResourceLocation +import org.ender_development.catalyx.api.v1.common.extensions.get +import org.ender_development.catalyx.api.v1.common.extensions.translate import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.client.button.AbstractButtonWrapper import org.ender_development.catalyx.core.client.button.PauseButtonWrapper @@ -19,8 +21,6 @@ import org.ender_development.catalyx.core.tiles.BaseTile import org.ender_development.catalyx.core.tiles.helper.IGuiTile import org.ender_development.catalyx.core.utils.RenderAlignment import org.ender_development.catalyx.core.utils.RenderUtils -import org.ender_development.catalyx.core.utils.extensions.get -import org.ender_development.catalyx.core.utils.extensions.translate // TODO fully rewrite this whole mess at some point abstract class BaseGuiTyped(container: Container, val tileEntity: T) : GuiContainer(container) where T : IGuiTile, T : BaseTile, T : BaseGuiTyped.IDefaultButtonVariables { @@ -108,11 +108,11 @@ abstract class BaseGuiTyped(container: Container, val tileEntity: T) : GuiCon PacketHandler.channel.sendToServer(ButtonPacket(tileEntity.pos, button.wrapper)) } - fun drawFluidTank(wrapper: CapabilityFluidDisplayWrapper, x: Int, y: Int, width: Int = 16, height: Int = 70) { + open fun drawFluidTank(wrapper: CapabilityFluidDisplayWrapper, x: Int, y: Int, width: Int = 16, height: Int = 70) { // draw the actual fluid texture if(wrapper.stored > 5) { RenderUtils.bindBlockTexture() - RenderUtils.renderGuiTank(wrapper.fluid, wrapper.capacity, wrapper.stored, x.toDouble(), y.toDouble(), zLevel.toDouble(), width.toDouble(), height.toDouble()) + RenderUtils.renderGuiTank(wrapper.fluid, wrapper.capacity, x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) } // draw the empty tank overlay overtop @@ -155,7 +155,7 @@ abstract class BaseGuiTyped(container: Container, val tileEntity: T) : GuiCon } } - fun isHovered(x: Int, y: Int, width: Int, height: Int, mouseX: Int, mouseY: Int) = + open fun isHovered(x: Int, y: Int, width: Int, height: Int, mouseX: Int, mouseY: Int) = mouseX >= x && mouseX < x + width && mouseY >= y && mouseY < y + height interface IDefaultButtonVariables { diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/gui/CatalyxGuiHandler.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/gui/CatalyxGuiHandler.kt index c8ae7cf..42ee25e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/gui/CatalyxGuiHandler.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/gui/CatalyxGuiHandler.kt @@ -8,13 +8,13 @@ import net.minecraft.tileentity.TileEntity import net.minecraft.util.math.BlockPos import net.minecraft.world.World import net.minecraftforge.fml.common.network.IGuiHandler +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.ICatalyxMod -import org.ender_development.catalyx.core.utils.SideUtils /** * A GUI handler you can use for your machines * - * Use the return value of [registerId] in the [org.ender_development.catalyx.blocks.BaseTileBlock.guiId] field + * Use the return value of [registerId] in the [org.ender_development.catalyx.core.blocks.BaseTileBlock.guiId] field * * Remember to register it with [net.minecraftforge.fml.common.network.NetworkRegistry.registerGuiHandler] */ @@ -24,13 +24,13 @@ class CatalyxGuiHandler(mod: ICatalyxMod) : IGuiHandler { internal val tileEntities = mutableListOf>() init { - instances.put(mod, this) + instances[mod] = this } fun registerId(te: Class, container: Class, gui: () -> Class): Int { tileEntities.add(te) containers.add(container) - if(SideUtils.isClient) + if(Utils.environment.isClient) guis.add(gui()) return tileEntities.size - 1 } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/sprite/DefaultSprite.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/sprite/DefaultSprite.kt new file mode 100644 index 0000000..2f9cb3b --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/sprite/DefaultSprite.kt @@ -0,0 +1,6 @@ +package org.ender_development.catalyx.core.client.sprite + +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.util.ResourceLocation + +class DefaultSprite(loc: ResourceLocation) : TextureAtlasSprite(loc.toString()) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/HudInfoRenderer.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/HudInfoRenderer.kt index e3724fb..b9ba768 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/HudInfoRenderer.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/HudInfoRenderer.kt @@ -4,13 +4,12 @@ import net.minecraft.client.renderer.GlStateManager import net.minecraft.util.EnumFacing import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly +import org.ender_development.catalyx.api.v1.common.extensions.getFacingFromEntity +import org.ender_development.catalyx.api.v1.common.extensions.glRotate import org.ender_development.catalyx.core.tiles.BaseTile import org.ender_development.catalyx.core.tiles.helper.HudInfoLine import org.ender_development.catalyx.core.tiles.helper.IHudInfoProvider -import org.ender_development.catalyx.core.utils.RenderUtils.FONT_RENDERER import org.ender_development.catalyx.core.utils.RenderUtils.drawRectangle -import org.ender_development.catalyx.core.utils.extensions.getFacingFromEntity -import org.ender_development.catalyx.core.utils.extensions.glRotate @SideOnly(Side.CLIENT) object HudInfoRenderer : AbstractTESRenderer() { @@ -70,17 +69,17 @@ object HudInfoRenderer : AbstractTESRenderer() { drawRectangle(padding, y, blockSize, height, message.border, false, -.01) val maxWidth = blockSize.toInt() - 2 - val line = FONT_RENDERER.trimStringToWidth(message.text, maxWidth) + val line = fontRenderer.trimStringToWidth(message.text, maxWidth) val colour = message.color?.let { it.rgb and 0xFFFFFF } ?: 0xFFFFFF println("colour=$colour; GlSM state={r=${GlStateManager.colorState.red}; g=${GlStateManager.colorState.green}; b=${GlStateManager.colorState.blue}; a=${GlStateManager.colorState.alpha}}") if(message.alignment == HudInfoLine.TextAlign.LEFT) - FONT_RENDERER.drawString(line, padding.toInt() + 1, y.toInt() + 2, colour) + fontRenderer.drawString(line, padding.toInt() + 1, y.toInt() + 2, colour) else { - var x = FONT_RENDERER.getStringWidth(line).coerceAtMost(maxWidth) + var x = fontRenderer.getStringWidth(line).coerceAtMost(maxWidth) if(message.alignment == HudInfoLine.TextAlign.CENTER) x = x shr 1 - FONT_RENDERER.drawString(line, x, y.toInt() + 2, colour) + fontRenderer.drawString(line, x, y.toInt() + 2, colour) } y += height } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/IORenderer.kt b/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/IORenderer.kt index d5a2be1..9ced2d0 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/IORenderer.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/client/tesr/IORenderer.kt @@ -6,16 +6,16 @@ import net.minecraft.util.EnumFacing import net.minecraft.util.ResourceLocation import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly +import org.ender_development.catalyx.api.v1.common.extensions.glOffsetX +import org.ender_development.catalyx.api.v1.common.extensions.glOffsetZ +import org.ender_development.catalyx.api.v1.common.extensions.glRotate +import org.ender_development.catalyx.api.v1.common.extensions.glRotationAngle import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.blocks.helper.IOType import org.ender_development.catalyx.core.tiles.BaseTile import org.ender_development.catalyx.core.tiles.helper.IPortRenderer import org.ender_development.catalyx.core.utils.RenderUtils import org.ender_development.catalyx.core.utils.RenderUtils.drawScaledCustomSizeModalRect -import org.ender_development.catalyx.core.utils.extensions.glOffsetX -import org.ender_development.catalyx.core.utils.extensions.glOffsetZ -import org.ender_development.catalyx.core.utils.extensions.glRotate -import org.ender_development.catalyx.core.utils.extensions.glRotationAngle import org.lwjgl.opengl.GL11 @SideOnly(Side.CLIENT) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/common/config/ConfigEntry.kt b/src/main/kotlin/org/ender_development/catalyx/core/common/config/ConfigEntry.kt new file mode 100644 index 0000000..b6ebb7f --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/common/config/ConfigEntry.kt @@ -0,0 +1,74 @@ +package org.ender_development.catalyx.core.common.config + +import net.minecraft.block.Block +import net.minecraft.block.state.IBlockState +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import org.ender_development.catalyx.api.v1.common.extensions.toBlock +import org.ender_development.catalyx.api.v1.common.extensions.toBlockState +import org.ender_development.catalyx.api.v1.common.extensions.toItem +import org.ender_development.catalyx.api.v1.common.extensions.toStack +import java.util.Objects + +open class GenericConfigEntry { + companion object { + const val IGNORE_META = -1 + } + + val mod: String + val id: String + val meta: Int + val value: T? + + val item: Item? + get() = "$mod:$id".toItem() + + val itemStack: ItemStack + get() = "$mod:$id".toStack(meta = meta) + + val block: Block? + get() = "$mod:$id".toBlock() + + val blockState: IBlockState? + get() = "$mod:$id".toBlockState(if(meta == IGNORE_META) 0 else meta) + + constructor(input: String, parser: (String) -> T) { + var split = input.split(";") + if(split.size > 2) + error("Invalid Config Entry: $input") + value = if(split.size == 2) + parser.invoke(split[1]) + else + null + split = split[0].split(":") + if(split.size !in 2..3) + error("Invalid Config Entry: $input") + mod = split[0] + id = split[1] + meta = if(split.size != 3 || split[2] == "-1") + IGNORE_META + else + split[2].toInt() + } + + override fun equals(other: Any?): Boolean { + return when (other) { + is Item -> other == item + is ItemStack -> if(meta == IGNORE_META) + other.isItemEqualIgnoreDurability(itemStack) + else + other.isItemEqual(itemStack) + is Block -> other == block + is IBlockState -> other == blockState + else -> this === other + } + } + + override fun hashCode(): Int = + Objects.hash(mod, id, meta, value) +} + +class ConfigEntry(input: String) : GenericConfigEntry(input, String::toString) +class ConfigEntryWithInt(input: String) : GenericConfigEntry(input, String::toInt) +class ConfigEntryWithFloat(input: String) : GenericConfigEntry(input, String::toFloat) +class ConfigEntryWithBoolean(input: String) : GenericConfigEntry(input, String::toBoolean) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/common/config/ConfigHandler.kt b/src/main/kotlin/org/ender_development/catalyx/core/common/config/ConfigHandler.kt new file mode 100644 index 0000000..618d944 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/common/config/ConfigHandler.kt @@ -0,0 +1,47 @@ +package org.ender_development.catalyx.core.common.config + +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import org.ender_development.catalyx.Catalyx + +class ConfigHandler>(configData: Iterable, parser: (String) -> T) { + private val configEntries = try { + configData.map { parser } + } catch (e: Exception) { + Catalyx.LOGGER.error("Error parsing config data", e) + emptyList() + } + + /** + * Check if the list contains the given input. + * @param stack The object to check. + * @return True if the list contains the item stack, false otherwise. + */ + fun contains(stack: Any) = + configEntries.any { it == stack } + + /** + * Check if the player has any of the entries in the list equipped. + * @param player The player to check. + * @return True if the player has any of the entries equipped, false otherwise. + */ + fun equipped(player: EntityPlayer) = + player.equipmentAndArmor.any(::contains) + + /** + * Get the first equipped config entry that matches any of the entries in the list. + * @param player The player to check. + * @return The first matching entry, or null if none found. + */ + fun getEquipped(player: EntityPlayer) = + player.equipmentAndArmor.firstOrNull(::contains)?.let(::get) + + /** + * Get the first config entry in the list that matches the given item stack. + * @param stack The item stack to check. + * @return The first matching entry, or null if none found. + */ + operator fun get(stack: ItemStack) = + configEntries.firstOrNull { it == stack } + +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/common/statemachine/StateMachine.kt b/src/main/kotlin/org/ender_development/catalyx/core/common/statemachine/StateMachine.kt new file mode 100644 index 0000000..2205a19 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/common/statemachine/StateMachine.kt @@ -0,0 +1,51 @@ +package org.ender_development.catalyx.core.common.statemachine + +import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.core.utils.EnvironmentUtils + +typealias StateTransition = (S, E) -> S? +typealias StateAction = (S) -> Unit + +class StateMachine(initialState: S) { + private val transitions = mutableMapOf, StateTransition>() + private val onEnterActions = mutableMapOf>>() + private val onExitActions = mutableMapOf>>() + + var currentState = initialState + private set + + fun transition(from: S, on: E, to: S) { + transitions[from to on] = { _, _ -> to } + } + + fun transition(from: S, on: E, handler: StateTransition) { + transitions[from to on] = handler + } + + fun onEnter(state: S, action: StateAction) { + onEnterActions.getOrPut(state) { mutableListOf() }.add(action) + } + + fun onExit(state: S, action: StateAction) { + onExitActions.getOrPut(state) { mutableListOf() }.add(action) + } + + fun sendEvent(event: E): Boolean { + val transition = transitions[currentState to event] + val newState = transition?.invoke(currentState, event) + + return if(newState != null && newState != currentState) { + // Exit current state + onExitActions[currentState]?.forEach { it(currentState) } + + val previousState = currentState + currentState = newState + + // Enter new state + onEnterActions[currentState]?.forEach { it(currentState) } + if(EnvironmentUtils.isDeobfuscated) + Catalyx.LOGGER.debug("Transition: $previousState -> $event -> $currentState") + true + } else false + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/common/statemachine/StateMachineBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/core/common/statemachine/StateMachineBuilder.kt new file mode 100644 index 0000000..3bb1379 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/common/statemachine/StateMachineBuilder.kt @@ -0,0 +1,44 @@ +package org.ender_development.catalyx.core.common.statemachine + +class StateMachineDSL(initialState: S) { + private val machine = StateMachine(initialState) + + fun state(state: S, block: StateBuilder.() -> Unit) { + val builder = StateBuilder(state, machine) + builder.block() + } + + fun build(): StateMachine = + machine +} + +class StateBuilder(private val state: S, private val machine: StateMachine) { + + fun on(event: E, block: TransitionBuilder.() -> Unit) { + val builder = TransitionBuilder(state, event, machine) + builder.block() + } + + fun onEnter(action: StateAction) = + machine.onEnter(state, action) + + fun onExit(action: StateAction) = + machine.onExit(state, action) +} + +class TransitionBuilder(private val from: S, private val event: E, private val machine: StateMachine) { + + fun goto(to: S) = + machine.transition(from, event, to) + + fun gotoIf(condition: (S, E) -> Boolean, to: S) = + machine.transition(from, event) { s, e -> + if (condition(s, e)) to else null + } +} + +fun stateMachine(initialState: S, block: StateMachineDSL.() -> Unit): StateMachine { + val dsl = StateMachineDSL(initialState) + dsl.block() + return dsl.build() +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/config/ConfigHandler.kt b/src/main/kotlin/org/ender_development/catalyx/core/config/ConfigHandler.kt deleted file mode 100644 index 311c03f..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/config/ConfigHandler.kt +++ /dev/null @@ -1,46 +0,0 @@ -package org.ender_development.catalyx.core.config - -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.item.ItemStack -import org.ender_development.catalyx.Catalyx - -class ConfigHandler(configData: Iterable, parser: (String) -> T) { - private val configItems = try { - configData.map(parser) - } catch(e: Exception) { - Catalyx.LOGGER.error("Error parsing config data", e) - emptyList() - } - - /** - * Check if the list contains the given item stack. - * @param stack The item stack to check. - * @return True if the list contains the item stack, false otherwise. - */ - fun contains(stack: ItemStack) = - configItems.any { it.compare(stack) } - - /** - * Check if the player has any of the items in the list equipped. - * @param player The player to check. - * @return True if the player has any of the items equipped, false otherwise. - */ - fun equipped(player: EntityPlayer) = - player.equipmentAndArmor.any { contains(it) } - - /** - * Get the first equipped config item that matches any of the items in the list. - * @param player The player to check. - * @return The first matching ConfigItem, or null if none found. - */ - fun getEquipped(player: EntityPlayer) = - player.equipmentAndArmor.firstOrNull { contains(it) }?.let { get(it) } - - /** - * Get the first config item in the list that matches the given item stack. - * @param stack The item stack to check. - * @return The first matching ConfigItem, or null if none found. - */ - operator fun get(stack: ItemStack) = - configItems.firstOrNull { it.compare(stack) } -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/config/ConfigParser.kt b/src/main/kotlin/org/ender_development/catalyx/core/config/ConfigParser.kt deleted file mode 100644 index fe44990..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/config/ConfigParser.kt +++ /dev/null @@ -1,232 +0,0 @@ -package org.ender_development.catalyx.core.config - -import net.minecraft.block.Block -import net.minecraft.block.state.IBlockState -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.util.ResourceLocation -import org.ender_development.catalyx.core.config.ConfigParser.ConfigBlockState.Companion.IGNORE_META -import org.ender_development.catalyx.core.utils.extensions.modLoaded -import java.util.* - -/** - * Utility object for parsing configuration strings into different representations. - * - * This object provides classes to handle items with different configurations, - * including those with additional values. - */ -object ConfigParser { - open class ConfigItemStack { - companion object { - internal const val IGNORE_META = -1 - } - - protected var modid: String? = null - protected var itemid: String? = null - protected var item: Item? = null - protected var meta: Int = IGNORE_META - - /* - * Default constructor for ConfigItem. - * It initializes the object without any specific configuration. - * Use the constructor with a config string for actual item configuration. - * Parsing and validation need to be done in the specific constructors. - */ - constructor() - - /** - * Constructor that takes a configuration string in the format "modid:item:meta" or "modid:item". - * The meta value is optional and defaults to -1 if not provided. - * Should be used if config consists of a single item or list of items. - * - * @param configString The configuration string to parse. - */ - constructor(configString: String) { - parseConfigString(configString) - validateConfigItem() - } - - open fun compare(other: Any?) = - when(other) { - is ItemStack -> - if(meta == IGNORE_META) - other.isItemEqualIgnoreDurability(toItemStack()) - else - other.isItemEqual(toItemStack()) - is ConfigItemStack -> modid == other.modid && itemid == other.itemid && meta == other.meta - else -> super.equals(other) - } - - open fun toItemStack() = - ItemStack(item ?: throw NullPointerException("Item not found: $modid:$itemid"), 1, meta) - - protected fun parseConfigString(configString: String) { - val parts = configString.split(":") - if(parts.size != 2 && parts.size != 3) - throw IllegalArgumentException("Invalid config string format: $configString") - - modid = parts[0] - itemid = parts[1] - if(parts.size == 3) - meta = parts[2].toInt() - - item = Item.getByNameOrId("$modid:$itemid") // check this in validateConfigItem? - } - - protected fun validateConfigItem() { - if(modid == null || itemid == null) - throw IllegalArgumentException("Mod ID and item name cannot be null") - - if(!modid.modLoaded()) - throw IllegalArgumentException("Mod ID is not loaded: $modid") - - if(meta < IGNORE_META) - throw IllegalArgumentException("Meta value cannot be negative") - } - } - - /** - * Constructor that takes a configuration string in the format "modid:item:meta;value". - * - * @param configString The configuration string to parse. - * @param parser The parser with which the value should be parsed to produce the expected value - */ - open class ConfigItemStackWith(configString: String, parser: (String) -> T) : ConfigItemStack() { - val value: T - - init { - val parts = configString.split(';', ',') - if(parts.size != 2) - throw IllegalArgumentException("Invalid config string format: $configString") - - parseConfigString(parts[0]) - validateConfigItem() - value = parser(parts[1]) - } - } - - /** - * Constructor that takes a configuration string in the format "modid:item:meta;value". - * - * @param configString The configuration string to parse. - */ - class ConfigItemStackWithFloat(configString: String) : ConfigItemStackWith(configString, String::toFloat) - - /** - * Constructor that takes a configuration string in the format "modid:item:meta;value". - * - * @param configString The configuration string to parse. - */ - class ConfigItemStackWithInt(configString: String) : ConfigItemStackWith(configString, String::toInt) - - /** - * Constructor that takes a configuration string in the format "modid:item:meta;value". - * - * @param configString The configuration string to parse. - */ - class ConfigItemStackWithBoolean(configString: String) : ConfigItemStackWith(configString, String::toBoolean) - - open class ConfigBlockState() { - companion object { - internal const val IGNORE_META = -1 - } - - private var modId: String? = null - private var blockId: String? = null - private var meta: Int = IGNORE_META - - open val block: Block? - get() { - val id = ResourceLocation(modId ?: return null, blockId ?: return null) - if(!Block.REGISTRY.containsKey(id)) - return null - return Block.REGISTRY.getObject(id) - } - - open val state: IBlockState? - @Suppress("DEPRECATION") - get() = block?.getStateFromMeta(if(meta == IGNORE_META) 0 else meta) - - /** - * Constructor that takes a configuration string in the format "modId:blockId:meta" or "modId:blockId" - * Meta defaults to [IGNORE_META] if not set - * Should be used if config consists of a single block or list of blocks. - * - * @param configString The configuration string to parse. - */ - constructor(configString: String) : this() { - parseConfigString(configString) - validate() - } - - override fun equals(other: Any?) = - when { - this === other -> true - other is IBlockState -> block === other.block && (meta == IGNORE_META || block?.getMetaFromState(other) == meta) - other is ConfigBlockState -> modId == other.modId && blockId == other.blockId && meta == other.meta - else -> false - } - - override fun hashCode() = - Objects.hash(modId, blockId, meta) - - open fun parseConfigString(configString: String) { - val parts = configString.split(":") - if(parts.size != 2 && parts.size != 3) - error("Invalid config string format: '$configString'") - - modId = parts[0] - blockId = parts[1] - if(parts.size == 3) - meta = parts[2].toInt() - } - - open fun validate() { - if(modId == null || blockId == null) - error("Mod Id and Block Id cannot be null") - - if(!modId.modLoaded()) - error("Mod ID is not loaded: $modId") - - if(meta < IGNORE_META) - error("Meta value cannot be negative") - } - } - - /** - * Helper class - * - * @param configString The configuration string to parse in the format "modId:blockId:meta;value" - * @param optional Whether the argument is optional or not - * @param parser The parser with which the value should be parsed to produce the expected value - */ - open class ConfigBlockStateWith(configString: String, optional: Boolean, parser: (String) -> T) : ConfigBlockState() { - /** - * Only nullable when [optional] is true - */ - val value: T? - - init { - val parts = configString.split(';', ',') - if(parts.size == 2) { - parseConfigString(parts[0]) - value = parser(parts[1]) - } else { - if(!optional) - error("Invalid config string format: '$configString'") - else { - parseConfigString(configString) - value = null - } - } - validate() - } - } - - class ConfigBlockStateWithInt(configString: String, optional: Boolean) : ConfigBlockStateWith(configString, optional, String::toInt) - - class ConfigBlockStateWithFloat(configString: String, optional: Boolean) : ConfigBlockStateWith(configString, optional, String::toFloat) - - class ConfigBlockStateWithBoolean(configString: String, optional: Boolean) : ConfigBlockStateWith(configString, optional, String::toBoolean) -} - diff --git a/src/main/kotlin/org/ender_development/catalyx/core/items/BaseItem.kt b/src/main/kotlin/org/ender_development/catalyx/core/items/BaseItem.kt index bdbf632..1f250c6 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/items/BaseItem.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/items/BaseItem.kt @@ -1,14 +1,10 @@ package org.ender_development.catalyx.core.items -import net.minecraft.client.renderer.block.model.ModelResourceLocation import net.minecraft.item.Item import net.minecraft.util.ResourceLocation -import net.minecraftforge.client.model.ModelLoader -import net.minecraftforge.event.RegistryEvent +import org.ender_development.catalyx.api.v1.registry.IItemProvider import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.register -import org.ender_development.catalyx.core.registry.IItemProvider -import org.ender_development.catalyx.core.utils.SideUtils /** * A base Catalyx item @@ -16,29 +12,12 @@ import org.ender_development.catalyx.core.utils.SideUtils open class BaseItem(val mod: ICatalyxMod, val name: String) : Item(), IItemProvider { init { registryName = ResourceLocation(mod.modId, name) - translationKey = "$registryName" + translationKey = "${mod.modId}:$name" creativeTab = mod.creativeTab } override val instance = this - override fun isEnabled() = - true - - override var modDependencies = "" - - override fun requires(modDependencies: String): Item { - this.modDependencies = modDependencies - mod.register(this) - return this - } - - override fun register(event: RegistryEvent.Register) { - event.registry.register(this) - if(SideUtils.isClient) - ModelLoader.setCustomModelResourceLocation(this, 0, ModelResourceLocation(registryName!!, "inventory")) - } - init { mod.register(this) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/items/CopyPasteTool.kt b/src/main/kotlin/org/ender_development/catalyx/core/items/CopyPasteTool.kt index ea89130..ed1f0f8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/items/CopyPasteTool.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/items/CopyPasteTool.kt @@ -1,5 +1,7 @@ package org.ender_development.catalyx.core.items +import net.minecraft.block.Block +import net.minecraft.client.gui.GuiScreen import net.minecraft.client.util.ITooltipFlag import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack @@ -7,16 +9,23 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumActionResult import net.minecraft.util.EnumFacing import net.minecraft.util.EnumHand +import net.minecraft.util.ResourceLocation import net.minecraft.util.math.BlockPos +import net.minecraft.util.text.Style +import net.minecraft.util.text.TextComponentString +import net.minecraft.util.text.TextFormatting import net.minecraft.world.World import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.translate +import org.ender_development.catalyx.api.v1.utils.Utils +import org.ender_development.catalyx.core.Reference +import org.ender_development.catalyx.core.client.IAutoModel import org.ender_development.catalyx.core.client.gui.BaseGuiTyped import org.ender_development.catalyx.core.tiles.BaseTile -import org.ender_development.catalyx.core.tiles.helper.ICopyPasteExtraTile -import org.ender_development.catalyx.core.utils.DevUtils +import org.ender_development.catalyx.core.tiles.helper.ICopyPasteExtraDataTile -class CopyPasteTool() : BaseItem(Catalyx, "copy_paste_tool") { - private companion object { +class CopyPasteTool : BaseItem(Catalyx, "copy_paste_tool"), IAutoModel { + companion object { const val NBT_COPIED_BLOCK_KEY = "CopiedBlock" const val NBT_COPIED_DATA_KEY = "CopiedData" const val NBT_IS_PAUSED_KEY = "IsPaused" @@ -30,7 +39,7 @@ class CopyPasteTool() : BaseItem(Catalyx, "copy_paste_tool") { val clickedBlockId = world.getBlockState(pos).block.registryName!!.toString() val copy = player.isSneaking - if(!copy && (copiedBlock.isEmpty() || copiedBlock != clickedBlockId)) + if(!copy && (copiedBlock.isBlank() || copiedBlock != clickedBlockId)) return EnumActionResult.PASS val te = world.getTileEntity(pos) @@ -45,11 +54,13 @@ class CopyPasteTool() : BaseItem(Catalyx, "copy_paste_tool") { copyTag.setBoolean(NBT_NEEDS_REDSTONE_KEY, te.needsRedstonePower) } - if(te is ICopyPasteExtraTile) + if(te is ICopyPasteExtraDataTile) te.copyData(copyTag) - if(copyTag.isEmpty) // don't copy emptiness + if(copyTag.isEmpty) { // don't copy emptiness + player.sendMessage(TextComponentString("Couldn't copy anything from this block").setStyle(Style().setColor(TextFormatting.RED))) return EnumActionResult.PASS + } tag.setTag(NBT_COPIED_DATA_KEY, copyTag) tag.setString(NBT_COPIED_BLOCK_KEY, clickedBlockId) @@ -68,11 +79,11 @@ class CopyPasteTool() : BaseItem(Catalyx, "copy_paste_tool") { te.needsRedstonePower = pasteTag.getBoolean(NBT_NEEDS_REDSTONE_KEY) } - if(te is ICopyPasteExtraTile) + if(te is ICopyPasteExtraDataTile) te.pasteData(pasteTag, player) } - if(!stack.hasTagCompound()) + if(!stack.hasTagCompound() && !tag.isEmpty) stack.tagCompound = tag return EnumActionResult.SUCCESS @@ -80,19 +91,31 @@ class CopyPasteTool() : BaseItem(Catalyx, "copy_paste_tool") { override fun addInformation(stack: ItemStack, world: World?, tooltip: List, flag: ITooltipFlag) { tooltip as MutableList - tooltip.add("TODO ;p") - - if(DevUtils.isDeobfuscated) { - tooltip.add("") - tooltip.add("${stack.tagCompound?.getString(NBT_COPIED_BLOCK_KEY)}") - tooltip.add("${stack.tagCompound?.getCompoundTag(NBT_COPIED_DATA_KEY)}") + tooltip.add("$translationKey.desc.1".translate()) + tooltip.add("$translationKey.desc.2".translate()) + + val tag = stack.tagCompound + val copiedBlock = tag?.getString(NBT_COPIED_BLOCK_KEY) + if(tag == null || copiedBlock.isNullOrBlank()) { + tooltip.add("$translationKey.desc.empty".translate()) + return } + + val shift = GuiScreen.isShiftKeyDown() + + val block = Block.REGISTRY.registryObjects[ResourceLocation(copiedBlock)] + tooltip.add("$translationKey.desc.copying".translate(if(shift || block == null) copiedBlock else block.localizedName)) + + if(shift) + tooltip.add(tag.getCompoundTag(NBT_COPIED_DATA_KEY).toString()) } /** * don't register if this isn't a dev environment, as this item is not finished - * TODO tooltip, name translation, maybe signify what blocks you can actually copy across ;p + * TODO texture */ override fun isEnabled() = - DevUtils.isDeobfuscated + Utils.environment.isDeobfuscated + + override val textureLocation = ResourceLocation(Reference.MODID, "logo") } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/module/IModuleManager.kt b/src/main/kotlin/org/ender_development/catalyx/core/module/IModuleManager.kt deleted file mode 100644 index 9c7c464..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/module/IModuleManager.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.ender_development.catalyx.core.module - -interface IModuleManager { - fun isModuleEnabled(containerId: String, moduleId: String) = - isModuleEnabled(ModuleIdentifier(containerId, moduleId)) - - fun isModuleEnabled(identifier: ModuleIdentifier): Boolean - fun isModuleEnabled(module: ICatalyxModule): Boolean - - fun registerContainer(container: Any) - - val activeContainer: Any? -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleIdentifier.kt b/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleIdentifier.kt index d8481fd..a566589 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleIdentifier.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleIdentifier.kt @@ -1,11 +1,8 @@ package org.ender_development.catalyx.core.module -import net.minecraft.util.ResourceLocation +import org.ender_development.catalyx.api.v1.modules.interfaces.IModuleIdentifier -class ModuleIdentifier : ResourceLocation { - val containerId: String = namespace - val moduleId: String = path - - constructor(identifier: String) : super(identifier) - constructor(containerId: String, moduleId: String) : super(containerId, moduleId) +data class ModuleIdentifier(override val containerId: String, override val moduleId: String) : IModuleIdentifier { + override fun toString() = + "$containerId:$moduleId" } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleManager.kt b/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleManager.kt index 9226ab3..8d8cb85 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleManager.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/module/ModuleManager.kt @@ -11,14 +11,20 @@ import net.minecraftforge.fml.common.ModContainer import net.minecraftforge.fml.common.discovery.ASMDataTable import net.minecraftforge.fml.common.event.* import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.modLoaded +import org.ender_development.catalyx.api.v1.modules.Modules +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModuleContainer +import org.ender_development.catalyx.api.v1.modules.interfaces.ICatalyxModule +import org.ender_development.catalyx.api.v1.modules.interfaces.IModuleIdentifier +import org.ender_development.catalyx.api.v1.modules.interfaces.IModuleManager +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.module.ModuleManager.configuration import org.ender_development.catalyx.core.module.ModuleManager.discoveredContainers import org.ender_development.catalyx.core.module.ModuleManager.discoveredModules import org.ender_development.catalyx.core.module.ModuleManager.stateEvent import org.ender_development.catalyx.core.utils.Delegates -import org.ender_development.catalyx.core.utils.DevUtils -import org.ender_development.catalyx.core.utils.extensions.modLoaded import java.io.File import java.util.* @@ -31,7 +37,7 @@ object ModuleManager : IModuleManager { const val MODULE_CFG_FILE_NAME = "$MODULE_CFG_CATEGORY_NAME.cfg" private val loadedModules = ReferenceLinkedOpenHashSet() - private val loadedModuleIds = hashSetOf() // ender, you can go and turn this into some fastutil bs + private val loadedModuleIds = hashSetOf() // TODO: turn this into some fastutil bs private val loadedContainers = Object2ReferenceLinkedOpenHashMap() private val configDirectory = File(Loader.instance().configDir, Reference.MODID) @@ -61,7 +67,7 @@ object ModuleManager : IModuleManager { * * @param asmDataTable the data table containing all the Module Container and Module classes */ - fun setup(asmDataTable: ASMDataTable) { + internal fun setup(asmDataTable: ASMDataTable) { discoverContainers(asmDataTable) discoverModules(asmDataTable) } @@ -260,30 +266,27 @@ object ModuleManager : IModuleManager { val discoveredModules = discoveredModules.remove(containerId) if(discoveredModules.isNullOrEmpty()) { - Catalyx.LOGGER.debug("> Module Container {}:{} has no modules", modId, containerId) + Catalyx.LOGGER.warn("> Module Container {}:{} has no modules", modId, containerId) return@forEach } - // Check module ids before instantiating modules + // Check module dependencies before instantiating val willInstantiate = mutableListOf() - val willInstantiateIds = mutableListOf() + val willInstantiateIds = mutableListOf() do { - var changed = false - val iter = discoveredModules.iterator() - while(iter.hasNext()) { - val module = iter.next() - val moduleId = ModuleIdentifier(module.annotationInfo["containerId"] as String, module.annotationInfo["moduleId"] as String) + val changed = discoveredModules.removeIf { module -> + val moduleId = Modules.newModuleIdentifier(module.annotationInfo["containerId"] as String, module.annotationInfo["moduleId"] as String) val unmetDependencies = (module.annotationInfo["moduleDependencies"] as List<*>? ?: emptyList()) .filterIsInstance() - .map(::ModuleIdentifier) + .map(Modules::newModuleIdentifier) .filterNot { willInstantiateIds.contains(it) || loadedModuleIds.contains(it) } if(unmetDependencies.isEmpty()) { - iter.remove() - changed = true willInstantiate.add(module) willInstantiateIds.add(moduleId) - } + true + } else + false } } while(changed) @@ -321,7 +324,7 @@ object ModuleManager : IModuleManager { * @param loader The loader to load the class with * @param asm The ASM class to load * @param type What is being loaded - used for error messages - * @return An instance of [asm] casted to [I], or null if anything fails + * @return An instance of [asm] cast to [I], or null if anything fails */ private inline fun loadClassAndCreateInstance(loader: ModClassLoader, asm: ASMDataTable.ASMData, type: String): I? { try { @@ -356,7 +359,7 @@ object ModuleManager : IModuleManager { * @param identifier the id of the module to check * @return true if the module is enabled, false otherwise */ - override fun isModuleEnabled(identifier: ModuleIdentifier) = + override fun isModuleEnabled(identifier: IModuleIdentifier) = loadedModuleIds.contains(identifier) override fun isModuleEnabled(module: ICatalyxModule) = @@ -383,7 +386,7 @@ object ModuleManager : IModuleManager { private fun shouldModuleBeEnabled(module: ICatalyxModule): Boolean { val annotation = module.annotation val prop = configuration.get(MODULE_CFG_CATEGORY_NAME, "${annotation.containerId}:${annotation.moduleId}", true, getConfigComment(module)) - return prop.boolean && (!annotation.testModule || DevUtils.isDeobfuscated) + return prop.boolean && (!annotation.testModule || Utils.environment.isDeobfuscated) } // --- Helper properties --- diff --git a/src/main/kotlin/org/ender_development/catalyx/core/network/ButtonPacket.kt b/src/main/kotlin/org/ender_development/catalyx/core/network/ButtonPacket.kt index a2387c1..6c4579d 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/network/ButtonPacket.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/network/ButtonPacket.kt @@ -8,10 +8,10 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler import net.minecraftforge.fml.common.network.simpleimpl.MessageContext import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.readString +import org.ender_development.catalyx.api.v1.common.extensions.writeString import org.ender_development.catalyx.core.client.button.AbstractButtonWrapper import org.ender_development.catalyx.core.tiles.helper.IButtonTile -import org.ender_development.catalyx.core.utils.extensions.readString -import org.ender_development.catalyx.core.utils.extensions.writeString class ButtonPacket() : IMessage { private lateinit var blockPos: BlockPos diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/Recipe.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/Recipe.kt index 8031b37..b9c8def 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/Recipe.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/Recipe.kt @@ -7,16 +7,17 @@ import net.minecraftforge.fluids.capability.IFluidHandler import net.minecraftforge.items.IItemHandlerModifiable import net.minecraftforge.items.ItemHandlerHelper import net.minecraftforge.oredict.OreDictionary +import org.ender_development.catalyx.api.v1.common.extensions.copyOf +import org.ender_development.catalyx.api.v1.common.extensions.isNullOrEmpty import org.ender_development.catalyx.core.recipes.chance.output.ChancedFluidOutput import org.ender_development.catalyx.core.recipes.chance.output.ChancedItemOutput import org.ender_development.catalyx.core.recipes.chance.output.ChancedOutputList import org.ender_development.catalyx.core.recipes.ingredients.RecipeInput import org.ender_development.catalyx.core.recipes.ingredients.RecipeInputCache import org.ender_development.catalyx.core.utils.IItemStackHash -import org.ender_development.catalyx.core.utils.extensions.copyOf import org.ender_development.catalyx.modules.integration.groovyscript.ModuleGroovyScript -class Recipe( +class Recipe ( inputs: List, val outputs: List, val chancedOutputs: ChancedOutputList, @@ -30,7 +31,7 @@ class Recipe( ) { val inputs = RecipeInputCache.deduplicateInputs(inputs) val fluidInputs = RecipeInputCache.deduplicateInputs(fluidInputs) - val hashCode = makeHashCode() + private val hashCode = 31 * this.inputs.hashItemList() + this.fluidInputs.hashFluidList() val groovyRecipe = ModuleGroovyScript.isRunning companion object { @@ -61,28 +62,42 @@ class Recipe( return currentRecipe } - fun hashFluidList(fluidList: List): Int { - var hash = 1 - fluidList.forEach { - hash = 31 * hash + it.hashCode() + private fun List.hashFluidList() = + fold(0) { hash, it -> + 31 * hash + it.hashCode() } - return hash - } - fun hashItemList(itemList: List): Int { - var hash = 1 - itemList.forEach { - when { - !it.isOreDict() -> it.getInputStacks()?.forEach { stack -> hash = 31 * hash + IItemStackHash.comparingAll.hashCode(stack) } - else -> hash = 31 * hash + it.getOreDict() - } + private fun List.hashItemList() = + fold(0) { hash, it -> + if(it.isOreDict()) + 31 * hash + it.getOreDict() + else + it.getInputStacks().orEmpty().fold(hash) { hash, stack -> + 31 * hash + IItemStackHash.comparingAll.hashCode(stack) + } } - return hash - } } + /** + * Copy constructor + * + * @param other the object to copy data from + */ + constructor(other: Recipe) : this( + other.inputs, + other.outputs, + other.chancedOutputs, + other.fluidInputs, + other.fluidOutputs, + other.chancedFluidOutputs, + other.duration, + other.energyPerTick, + other.hidden, + other.recipeCategory + ) + fun copy() = - Recipe(inputs, outputs, chancedOutputs, fluidInputs, fluidOutputs, chancedFluidOutputs, duration, energyPerTick, hidden, recipeCategory) + Recipe(this) override fun equals(other: Any?) = this === other || (other is Recipe && hasSameInputs(other) && hasSameFluidInputs(other)) @@ -93,12 +108,6 @@ class Recipe( override fun hashCode() = hashCode - private fun makeHashCode(): Int { - var hash = 31 * hashItemList(inputs) - hash = 31 * hash + hashFluidList(fluidInputs) - return hash - } - private fun hasSameInputs(other: Recipe): Boolean { val otherStackList = ObjectArrayList(other.inputs.size) @@ -146,10 +155,10 @@ class Recipe( val inputStack = inputs[i] if(i == indexed) { ++indexed - itemAmountInSlot[i] = if(inputStack?.isEmpty != false) 0 else inputStack.count + itemAmountInSlot[i] = if(inputStack.isNullOrEmpty()) 0 else inputStack.count } - if(inputStack?.isEmpty != false || !it.acceptsStack(inputStack)) + if(inputStack.isNullOrEmpty() || !it.acceptsStack(inputStack)) continue val itemAmountToConsume = itemAmountInSlot[i].coerceAtMost(ingredientAmount) @@ -420,7 +429,7 @@ class Recipe( inputs.forEachIndexed { index, itemStack -> val itemAmount = itemAmountInSlot[index] - if(itemStack?.isEmpty != false || itemStack.count == itemAmount) + if(itemStack.isNullOrEmpty() || itemStack.count == itemAmount) return@forEachIndexed itemStack.count = itemAmount diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeBuilder.kt index fc46b0c..414758e 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeBuilder.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeBuilder.kt @@ -4,6 +4,8 @@ import com.cleanroommc.groovyscript.api.GroovyLog import net.minecraft.item.ItemStack import net.minecraftforge.fluids.FluidStack import net.minecraftforge.fml.common.Optional +import org.ender_development.catalyx.api.v1.common.Mods +import org.ender_development.catalyx.api.v1.common.extensions.plural import org.ender_development.catalyx.core.recipes.chance.output.ChancedFluidOutput import org.ender_development.catalyx.core.recipes.chance.output.ChancedItemOutput import org.ender_development.catalyx.core.recipes.chance.output.ChancedOutputList @@ -12,7 +14,6 @@ import org.ender_development.catalyx.core.recipes.ingredients.RecipeInput import org.ender_development.catalyx.core.recipes.validation.Result import org.ender_development.catalyx.core.recipes.validation.ValidationState import org.ender_development.catalyx.core.recipes.validation.Validator -import org.ender_development.catalyx.core.utils.Mods import org.ender_development.catalyx.modules.integration.groovyscript.ModuleGroovyScript import java.util.function.Supplier @@ -21,10 +22,8 @@ class RecipeBuilder> { fun getRequiredString(max: Int, found: Int, type: String): String { if(max <= 0) return "No ${type}s allowed, but found $found" - var out = "Must have at most $max $type" - if(max != 1) - out += "s" - return "$out, but found $found" + + return "Must have at most $max $type${max.plural}, but found $found" } } @@ -49,12 +48,12 @@ class RecipeBuilder> { var recipeStatus: ValidationState = ValidationState.VALID private constructor() { - this.inputs = ArrayList() - this.outputs = ArrayList() - this.chancedOutputs = ArrayList() - this.fluidInputs = ArrayList() - this.fluidOutputs = ArrayList() - this.chancedFluidOutputs = ArrayList() + this.inputs = mutableListOf() + this.outputs = mutableListOf() + this.chancedOutputs = mutableListOf() + this.fluidInputs = mutableListOf() + this.fluidOutputs = mutableListOf() + this.chancedFluidOutputs = mutableListOf() } constructor(recipe: Recipe, recipeMap: RecipeMap) { diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeMap.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeMap.kt index c61c6c0..ae96648 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeMap.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/RecipeMap.kt @@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap import it.unimi.dsi.fastutil.objects.ObjectArrayList import it.unimi.dsi.fastutil.objects.ObjectLists import net.minecraft.util.SoundEvent +import org.ender_development.catalyx.api.v1.common.Mods import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.module.ModuleManager import org.ender_development.catalyx.core.recipes.chance.boost.IBoostFunction @@ -14,7 +15,6 @@ import org.ender_development.catalyx.core.recipes.validation.Result import org.ender_development.catalyx.core.recipes.validation.ValidationState import org.ender_development.catalyx.core.recipes.validation.Validator import org.ender_development.catalyx.core.utils.Delegates -import org.ender_development.catalyx.core.utils.Mods import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer import org.ender_development.catalyx.modules.integration.groovyscript.VirtualizedRecipeMap import java.lang.ref.WeakReference @@ -26,7 +26,7 @@ class RecipeMap> { internal val RECIPE_DURATION_THEN_ENERGY = Comparator .comparingInt(Recipe::duration) .thenComparingLong(Recipe::energyPerTick) - .thenComparingInt { it.hashCode } + .thenComparingInt(Recipe::hashCode) internal val INGREDIENT_ROOT = WeakHashMap>() internal var foundInvalidRecipe = false @@ -114,7 +114,7 @@ class RecipeMap> { this.maxFluidInputs = maxFluidInputs this.maxOutputs = maxOutputs this.maxFluidOutputs = maxFluidOutputs - translationKey = "recipemap.${mod.modId}.$unlocalizedName.name" + translationKey = "recipemap.${mod.modId}:$unlocalizedName.name" primaryRecipeCategory = RecipeCategory.create(mod.modId, unlocalizedName, translationKey, this) defaultRecipeBuilder.recipeMap = this @@ -214,7 +214,7 @@ class RecipeMap> { ingredients.indices.forEach { i -> val mappedIngredient = ingredients[i] // attempt to use the cached version if it exists, otherwise cache it - INGREDIENT_ROOT.get(mappedIngredient)?.get()?.let { ingredients[i] = it } ?: run { + INGREDIENT_ROOT[mappedIngredient]?.get()?.let { ingredients[i] = it } ?: run { INGREDIENT_ROOT[mappedIngredient] = WeakReference(mappedIngredient) } } @@ -272,7 +272,7 @@ class RecipeMap> { return true if(index >= ingredients.size) - throw IllegalStateException("Index $index is out of bounds for ingredients list of size ${ingredients.size}") + error("Index $index is out of bounds for ingredients list of size ${ingredients.size}") val current = ingredients[index] val branchRight = Branch() diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedFluidOutput.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedFluidOutput.kt index dfb7add..47ead13 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedFluidOutput.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedFluidOutput.kt @@ -2,15 +2,17 @@ package org.ender_development.catalyx.core.recipes.chance.output import net.minecraft.network.PacketBuffer import net.minecraftforge.fluids.FluidStack -import org.ender_development.catalyx.core.utils.NetworkUtils +import org.ender_development.catalyx.api.v1.common.extensions.readFluidStack +import org.ender_development.catalyx.api.v1.common.extensions.writeFluidStack +import org.ender_development.catalyx.api.v1.utils.Utils class ChancedFluidOutput(ingredient: FluidStack, chance: Int, boost: Int) : BoostableChancedOutput(ingredient, chance, boost) { companion object { fun fromBuffer(buffer: PacketBuffer) = - ChancedFluidOutput(NetworkUtils.readFluidStack(buffer)!!, buffer.readVarInt(), buffer.readVarInt()) + ChancedFluidOutput(buffer.readFluidStack()!!, buffer.readVarInt(), buffer.readVarInt()) fun toBuffer(buffer: PacketBuffer, output: ChancedFluidOutput) { - NetworkUtils.writeFluidStack(buffer, output.ingredient) + buffer.writeFluidStack(output.ingredient) buffer.writeVarInt(output.chance) buffer.writeVarInt(output.boost) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedItemOutput.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedItemOutput.kt index 3923f8e..5cdfcbd 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedItemOutput.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/ChancedItemOutput.kt @@ -2,15 +2,15 @@ package org.ender_development.catalyx.core.recipes.chance.output import net.minecraft.item.ItemStack import net.minecraft.network.PacketBuffer -import org.ender_development.catalyx.core.utils.NetworkUtils +import org.ender_development.catalyx.api.v1.common.extensions.readItemStackOrEmpty class ChancedItemOutput(ingredient: ItemStack, chance: Int, boost: Int) : BoostableChancedOutput(ingredient, chance, boost) { companion object { fun fromBuffer(buffer: PacketBuffer) = - ChancedItemOutput(NetworkUtils.readItemStack(buffer), buffer.readVarInt(), buffer.readVarInt()) + ChancedItemOutput(buffer.readItemStackOrEmpty(), buffer.readVarInt(), buffer.readVarInt()) fun toBuffer(buffer: PacketBuffer, output: ChancedItemOutput) { - NetworkUtils.writeItemStack(buffer, output.ingredient) + buffer.writeItemStack(output.ingredient) buffer.writeVarInt(output.chance) buffer.writeVarInt(output.boost) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/IChancedOutputLogic.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/IChancedOutputLogic.kt index a56234e..05c037c 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/IChancedOutputLogic.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/chance/output/IChancedOutputLogic.kt @@ -43,7 +43,7 @@ interface IChancedOutputLogic { override fun > roll(chancedEntries: List, boostFunction: IBoostFunction, baseTier: Int, machineTier: Int) = null - override val translationKey = "${Reference.MODID}.chance_logic.none" + override val translationKey = "chance_logic.${Reference.MODID}:none" override fun toString() = "ChancedOutputLogic{type=NONE}" @@ -58,7 +58,7 @@ interface IChancedOutputLogic { passesChance(getChance(it, boostFunction, baseTier, machineTier)) } - override val translationKey = "${Reference.MODID}.chance_logic.or" + override val translationKey = "chance_logic.${Reference.MODID}:or" override fun toString() = "ChancedOutputLogic{type=OR}" @@ -76,7 +76,7 @@ interface IChancedOutputLogic { else null - override val translationKey = "${Reference.MODID}.chance_logic.and" + override val translationKey = "chance_logic.${Reference.MODID}:and" override fun toString() = "ChancedOutputLogic{type=AND}" @@ -94,7 +94,7 @@ interface IChancedOutputLogic { null } - override val translationKey = "${Reference.MODID}.chance_logic.first" + override val translationKey = "chance_logic.${Reference.MODID}:first" override fun toString() = "ChancedOutputLogic{type=FIRST}" diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/ItemInput.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/ItemInput.kt index ed9e693..0f279eb 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/ItemInput.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/ItemInput.kt @@ -5,6 +5,7 @@ import net.minecraft.creativetab.CreativeTabs import net.minecraft.item.ItemStack import net.minecraft.util.NonNullList import net.minecraftforge.oredict.OreDictionary +import org.ender_development.catalyx.api.v1.common.extensions.isNullOrEmpty import org.ender_development.catalyx.core.recipes.ingredients.entries.ItemToMetaList import java.util.* @@ -68,7 +69,7 @@ class ItemInput : RecipeInput { inputStacks override fun acceptsStack(stack: ItemStack?): Boolean { - if(stack == null || stack.isEmpty) + if(stack.isNullOrEmpty()) return false itemList.forEach { metaList -> diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/OreInput.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/OreInput.kt index 1cbab02..44603e3 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/OreInput.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/OreInput.kt @@ -2,6 +2,7 @@ package org.ender_development.catalyx.core.recipes.ingredients import net.minecraft.item.ItemStack import net.minecraftforge.oredict.OreDictionary +import org.ender_development.catalyx.api.v1.common.extensions.isNullOrEmpty import java.util.* class OreInput : RecipeInput { @@ -65,7 +66,7 @@ class OreInput : RecipeInput { ore override fun acceptsStack(stack: ItemStack?): Boolean { - if(stack == null || stack.isEmpty) + if(stack.isNullOrEmpty()) return false nbtMatcher?.let { matcher -> diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/RecipeInputCache.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/RecipeInputCache.kt index 362e536..28db14f 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/RecipeInputCache.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/RecipeInputCache.kt @@ -80,7 +80,7 @@ object RecipeInputCache { if(inputs.isEmpty()) return inputs - return inputs.map { deduplicate(it) } + return inputs.map(::deduplicate) } /** diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/IMatcher.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/IMatcher.kt index 3f16596..8d8b6c8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/IMatcher.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/IMatcher.kt @@ -3,7 +3,7 @@ package org.ender_development.catalyx.core.recipes.ingredients.nbt import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.fluids.FluidStack -import org.ender_development.catalyx.core.utils.extensions.getLongArray +import org.ender_development.catalyx.api.v1.common.extensions.getLongArray interface IMatcher { companion object { @@ -32,7 +32,7 @@ interface IMatcher { if(tag == null || condition == null || condition.tagType == null) return false - if(!TagType.isNumeric(condition.tagType) || !hasKey(tag, condition.nbtKey!!, condition.tagType.typeId)) + if(!condition.tagType.isNumeric() || !hasKey(tag, condition.nbtKey!!, condition.tagType.typeId)) return false return inequality(tag.getLong(condition.nbtKey), (condition.value as Number).toLong()) @@ -73,10 +73,7 @@ interface IMatcher { tagValue >= conditionValue } - /** - * Check if the NBT tag contains the key specified in the condition and if its value is equal to the value specified in the condition. - */ - object EQUAL_TO : IMatcher { + private interface EqualityBase : IMatcher { override fun evaluate(tag: NBTTagCompound?, condition: NBTCondition?): Boolean { if(tag == null || condition == null || condition.tagType == null) return false @@ -84,7 +81,7 @@ interface IMatcher { if(!hasKey(tag, condition.nbtKey!!, condition.tagType.typeId)) return false - return if(TagType.isNumeric(condition.tagType)) + return if(condition.tagType.isNumeric()) tag.getLong(condition.nbtKey) == (condition.value as Number).toLong() else when(condition.tagType) { @@ -93,39 +90,31 @@ interface IMatcher { TagType.LONG_ARRAY -> tag.getLongArray(condition.nbtKey) contentEquals condition.value as LongArray TagType.LIST -> condition is NBTListCondition && tag.getTagList(condition.nbtKey, condition.listTagType.typeId).tagList == condition.value TagType.STRING -> tag.getString(condition.nbtKey) == condition.value - TagType.COMPOUND -> tag.getCompoundTag(condition.nbtKey) == condition.value - else -> throw IllegalStateException("TagType#isNumeric returned false on a numeric TagType") + TagType.COMPOUND -> compound(tag, condition) + else -> error("TagType#isNumeric returned false on a numeric TagType") } } + + fun compound(tag: NBTTagCompound, condition: NBTCondition): Boolean } /** * Check if the NBT tag contains the key specified in the condition and if its value is equal to the value specified in the condition. - * If the value is a compound tag, it will recursively check if all keys and values match. */ - object RECURSIVE_EQUAL_TO : IMatcher { // TODO: this and EQUAL_TO are basically the same matcher except for TagType.COMPOUND, could abstract them away to not basically duplicate the same code twice - override fun evaluate(tag: NBTTagCompound?, condition: NBTCondition?): Boolean { - if(tag == null || condition == null || condition.tagType == null) - return false - - if(!hasKey(tag, condition.nbtKey!!, condition.tagType.typeId)) - return false + object EQUAL_TO : EqualityBase { + override fun compound(tag: NBTTagCompound, condition: NBTCondition) = + tag.getCompoundTag(condition.nbtKey!!) == condition.value + } - return if(TagType.isNumeric(condition.tagType)) - tag.getLong(condition.nbtKey) == (condition.value as Number).toLong() - else - when(condition.tagType) { - TagType.BYTE_ARRAY -> tag.getByteArray(condition.nbtKey) contentEquals condition.value as ByteArray - TagType.INT_ARRAY -> tag.getIntArray(condition.nbtKey) contentEquals condition.value as IntArray - TagType.LONG_ARRAY -> tag.getLongArray(condition.nbtKey) contentEquals condition.value as LongArray - TagType.LIST -> condition is NBTListCondition && tag.getTagList(condition.nbtKey, condition.listTagType.typeId).tagList == condition.value - TagType.STRING -> tag.getString(condition.nbtKey).equals(condition.value as String) - TagType.COMPOUND -> tag.getCompoundTag(condition.nbtKey).let { tag -> - condition.value is NBTCondition && evaluate(tag, condition.value) || tag == condition.value - } - else -> throw IllegalStateException("TagType#isNumeric returned false on a numeric TagType") - } - } + /** + * Check if the NBT tag contains the key specified in the condition and if its value is equal to the value specified in the condition. + * If the value is a compound tag, it will recursively check if all keys and values match. + */ + object RECURSIVE_EQUAL_TO : EqualityBase { + override fun compound(tag: NBTTagCompound, condition: NBTCondition) = + tag.getCompoundTag(condition.nbtKey!!).let { tag -> + condition.value is NBTCondition && evaluate(tag, condition.value) || tag == condition.value + } } /** @@ -140,7 +129,7 @@ interface IMatcher { if(!hasKey(tag, condition.nbtKey!!, condition.tagType.typeId)) return true - return if(TagType.isNumeric(condition.tagType)) + return if(condition.tagType.isNumeric()) tag.getLong(condition.nbtKey) == 0L else { when(condition.tagType) { @@ -150,7 +139,7 @@ interface IMatcher { TagType.LIST -> condition is NBTListCondition && tag.getTagList(condition.nbtKey, condition.listTagType.typeId).isEmpty TagType.STRING -> tag.getString(condition.nbtKey).isEmpty() TagType.COMPOUND -> tag.getCompoundTag(condition.nbtKey).isEmpty - else -> throw IllegalStateException("TagType#isNumeric returned false on a numeric TagType") + else -> error("TagType#isNumeric returned false on a numeric TagType") } } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTCondition.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTCondition.kt index abe8696..c036633 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTCondition.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTCondition.kt @@ -34,5 +34,5 @@ open class NBTCondition { Objects.hash(tagType, nbtKey, value) override fun equals(other: Any?) = - this === other || (other is NBTCondition && tagType == other.tagType && nbtKey.equals(other.nbtKey) && value == other.value) + this === other || (other is NBTCondition && tagType == other.tagType && nbtKey == other.nbtKey && value == other.value) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTListCondition.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTListCondition.kt index 0fcfa88..d5d6747 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTListCondition.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/NBTListCondition.kt @@ -22,5 +22,5 @@ class NBTListCondition : NBTCondition { Objects.hash(tagType, nbtKey, value, listTagType) override fun equals(other: Any?) = - this === other || (other is NBTListCondition && tagType == other.tagType && nbtKey.equals(other.nbtKey) && value == other.value && listTagType == other.listTagType) + this === other || (other is NBTListCondition && tagType == other.tagType && nbtKey == other.nbtKey && value == other.value && listTagType == other.listTagType) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/TagType.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/TagType.kt index 241650e..b39a1f1 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/TagType.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/ingredients/nbt/TagType.kt @@ -16,11 +16,9 @@ enum class TagType(val typeId: Int) { LONG_ARRAY(12), NUMBER(99); - companion object { - fun isNumeric(tagType: TagType) = - when(tagType) { - BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, NUMBER -> true - else -> false - } - } + fun isNumeric() = + when(this) { + BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, NUMBER -> true + else -> false + } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/recipes/validation/Validator.kt b/src/main/kotlin/org/ender_development/catalyx/core/recipes/validation/Validator.kt index 294dc6c..c7f6492 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/recipes/validation/Validator.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/recipes/validation/Validator.kt @@ -2,11 +2,11 @@ package org.ender_development.catalyx.core.recipes.validation import org.apache.logging.log4j.Logger import org.ender_development.catalyx.Catalyx -import org.ender_development.catalyx.core.utils.extensions.validateWith -import org.ender_development.catalyx.core.utils.validation.ValidationError +import org.ender_development.catalyx.api.v1.common.extensions.validateWith +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError class Validator { - private val errors = mutableListOf() + private val errors = mutableListOf() fun error(condition: Boolean, message: String) = errors.addAll(message.validateWith({ !condition }).errors) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxBlockRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxBlockRegistry.kt index 71ad83b..a9a7f7f 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxBlockRegistry.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxBlockRegistry.kt @@ -2,35 +2,67 @@ package org.ender_development.catalyx.core.registry import net.minecraft.block.Block import net.minecraft.item.Item +import net.minecraftforge.client.event.ModelBakeEvent +import net.minecraftforge.client.event.ModelRegistryEvent +import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.event.RegistryEvent import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.plural +import org.ender_development.catalyx.api.v1.registry.IBlockProvider +import org.ender_development.catalyx.api.v1.registry.ICatalyxRegistry +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.Reference -import org.ender_development.catalyx.core.utils.DevUtils +import org.ender_development.catalyx.core.client.ICustomModel -@Suppress("unused") @Mod.EventBusSubscriber(modid = Reference.MODID) object CatalyxBlockRegistry : ICatalyxRegistry { - override val registry = CatalyxRegistry() + override val registry = CatalyxProviderRegistry() @SubscribeEvent - override fun register(event: RegistryEvent.Register) { - Catalyx.LOGGER.debug("Block Registry has ${registry.size} entries, but only gonna register ${registry.enabled.size} block${registry.plural}") + override fun registerProvider(event: RegistryEvent.Register) { + Catalyx.LOGGER.debug("Block Registry has ${registry.size} entries, but only gonna register ${registry.enabled.size} block${registry.size.plural}") registry.enabled.forEach { it.register(event) - if(DevUtils.isDeobfuscated) + if(Utils.environment.isDeobfuscated) Catalyx.LOGGER.debug("Registered block: {}", it.instance.registryName) } } @SubscribeEvent fun registerItemBlocks(event: RegistryEvent.Register) { - Catalyx.LOGGER.debug("Item Block Registry has ${registry.size} entries, but only gonna register ${registry.enabled.size} block item${registry.plural}") + Catalyx.LOGGER.debug("Item Block Registry has ${registry.size} entries, but only gonna register ${registry.enabled.size} block item${registry.size.plural}") registry.enabled.forEach { it.registerItemBlock(event) - if(DevUtils.isDeobfuscated) + if(Utils.environment.isDeobfuscated) Catalyx.LOGGER.debug("Registered block item: {}", it.item.registryName) } } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + override fun registerModel(event: ModelRegistryEvent) { + registry.enabled.forEach { + it.registerModel(event) + } + } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + override fun bakeModel(event: ModelBakeEvent) { + registry.enabled.filterIsInstance().forEach { + it.onBakeModel(event) + } + } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + override fun stitchTexture(event: TextureStitchEvent.Pre) { + registry.enabled.filterIsInstance().forEach { + it.onTextureStitch(event) + } + } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxItemRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxItemRegistry.kt index 2dbab09..210a9f0 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxItemRegistry.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxItemRegistry.kt @@ -1,25 +1,57 @@ package org.ender_development.catalyx.core.registry import net.minecraft.item.Item +import net.minecraftforge.client.event.ModelBakeEvent +import net.minecraftforge.client.event.ModelRegistryEvent +import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.event.RegistryEvent import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.plural +import org.ender_development.catalyx.api.v1.registry.ICatalyxRegistry +import org.ender_development.catalyx.api.v1.registry.IItemProvider +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.Reference -import org.ender_development.catalyx.core.utils.DevUtils +import org.ender_development.catalyx.core.client.ICustomModel -@Suppress("unused") @Mod.EventBusSubscriber(modid = Reference.MODID) object CatalyxItemRegistry : ICatalyxRegistry { - override val registry = CatalyxRegistry() + override val registry = CatalyxProviderRegistry() @SubscribeEvent - override fun register(event: RegistryEvent.Register) { - Catalyx.LOGGER.debug("Item Registry has ${registry.size} entries, but only gonna register ${registry.enabled.size} item${registry.plural}") + override fun registerProvider(event: RegistryEvent.Register) { + Catalyx.LOGGER.debug("Item Registry has ${registry.size} entries, but only gonna register ${registry.enabled.size} item${registry.size.plural}") registry.enabled.forEach { it.register(event) - if(DevUtils.isDeobfuscated) + if(Utils.environment.isDeobfuscated) Catalyx.LOGGER.debug("Registered item: {}", it.instance.registryName) } } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + override fun registerModel(event: ModelRegistryEvent) { + registry.enabled.forEach { + it.registerModel(event) + } + } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + override fun bakeModel(event: ModelBakeEvent) { + registry.enabled.filterIsInstance().forEach { + it.onBakeModel(event) + } + } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + override fun stitchTexture(event: TextureStitchEvent.Pre) { + registry.enabled.filterIsInstance().forEach { + it.onTextureStitch(event) + } + } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxProviderRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxProviderRegistry.kt new file mode 100644 index 0000000..9d0ad80 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxProviderRegistry.kt @@ -0,0 +1,18 @@ +package org.ender_development.catalyx.core.registry + +import net.minecraft.util.ResourceLocation +import org.ender_development.catalyx.api.v1.registry.ICatalyxProviderRegistry +import org.ender_development.catalyx.api.v1.registry.IProvider + +/** + * Collection of all [IProvider] of a given type + * + * @param V the Type of the Provider for the things that should be managed here + */ +class CatalyxProviderRegistry> : HashMap>(), ICatalyxProviderRegistry { + override fun add(provider: V): Boolean = + provider.instance.registryName?.let { + this[it] = provider to provider.isEnabled() + true + } ?: false +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxRegistry.kt deleted file mode 100644 index fb3ffda..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/registry/CatalyxRegistry.kt +++ /dev/null @@ -1,29 +0,0 @@ -package org.ender_development.catalyx.core.registry - -import net.minecraft.util.ResourceLocation -import org.ender_development.catalyx.core.utils.extensions.modLoaded - -class CatalyxRegistry> : HashMap>() { - fun add(provider: V): Boolean = - provider.instance.registryName?.let { - this[it] = provider to (provider.isEnabled() && provider.modDependencies.evaluateModDependencies()) - true - } ?: false - - val enabled: List - get() = values.filter { it.second }.map { it.first } - - val plural - get() = if(enabled.size == 1) "" else "s" - - /** - * Special expansion to evaluate modDependencies strings. - */ - fun String.evaluateModDependencies(): Boolean = - isEmpty() || split(',', ';').all { - if(it[0] == '!') - !it.substring(1).modLoaded() - else - it.modLoaded() - } -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/registry/ICatalyxRegistry.kt b/src/main/kotlin/org/ender_development/catalyx/core/registry/ICatalyxRegistry.kt deleted file mode 100644 index 73c06f3..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/registry/ICatalyxRegistry.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.ender_development.catalyx.core.registry - -import net.minecraftforge.event.RegistryEvent -import net.minecraftforge.registries.IForgeRegistryEntry - -interface ICatalyxRegistry, P : IProvider> { - /** - * The set of providers to be registered. - */ - val registry: CatalyxRegistry

- - /** - * Register all enabled providers with the given event. - * - * @param event The registry event. - */ - fun register(event: RegistryEvent.Register) -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/registry/IProvider.kt b/src/main/kotlin/org/ender_development/catalyx/core/registry/IProvider.kt deleted file mode 100644 index 91adc13..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/registry/IProvider.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.ender_development.catalyx.core.registry - -import net.minecraft.block.Block -import net.minecraft.item.Item -import net.minecraftforge.event.RegistryEvent -import net.minecraftforge.registries.IForgeRegistryEntry - -/** - * A provider of items or blocks to be registered. - */ -interface IProvider> { - /** - * The instance provided by this provider. - */ - val instance: T - - /** - * The mod ID(s) required for this provider to be enabled, separated by semicolons. Prefixes of "!" can be used to indicate that a mod must NOT be present. - * - * Default is an empty string, meaning no dependencies. - */ - var modDependencies: String - - // Note to self: do not make this a `val` as we wanna enforce a getter here (https://discord.com/channels/@me/1232745201009819749/1423296686691717220) - /** - * Whether this provider is enabled and should be registered. - */ - fun isEnabled(): Boolean - - /** - * Register this provider's item/block with the given event. - * - * @param event The registry event. - */ - fun register(event: RegistryEvent.Register) - - /** - * Specify that this provider requires the given mod dependency to be present. - * - * @param modDependencies The mod ID(s) required, separated by semicolons. Prefixes of "!" can be used to indicate that a mod must NOT be present. - * @return This instance, for chaining. - */ - fun requires(modDependencies: String): T -} - -interface IItemProvider : IProvider - -interface IBlockProvider : IProvider { - /** - * Override this instead of [registerItemBlock] if you only want to change the registered Item associated with this Block (like with a [org.ender_development.catalyx.core.items.TooltipItemBlock]) - */ - val item: Item - - /** - * Register the Item for this Block with the given event. - * - * @param event The registry event for Items. - */ - fun registerItemBlock(event: RegistryEvent.Register) -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseMachineTile.kt b/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseMachineTile.kt index c4974a3..ffab667 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseMachineTile.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseMachineTile.kt @@ -54,7 +54,8 @@ abstract class BaseMachineTile(mod: ICatalyxMod) : BaseTile(mod), ITickable, /** * Check if the recipe progress should reset if shouldProcess() is false */ - open fun shouldResetProgress() = true + open fun shouldResetProgress() = + true /** * Called every tick when the machine is idle. @@ -63,10 +64,14 @@ abstract class BaseMachineTile(mod: ICatalyxMod) : BaseTile(mod), ITickable, open fun onIdleTick() = updateRecipe() override fun update() { - if(world.isRemote) return + if(world.isRemote) + return + markDirtyGUIEvery(5) - if(isPaused || needsRedstonePower != this.world.isBlockPowered(this.pos)) return + if(isPaused || needsRedstonePower != world.isBlockPowered(pos)) + return + if(!shouldTick()) { progressTicks = 0 return diff --git a/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseTile.kt b/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseTile.kt index 1536417..ce66e92 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseTile.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/tiles/BaseTile.kt @@ -25,6 +25,7 @@ import net.minecraftforge.items.CapabilityItemHandler import net.minecraftforge.items.IItemHandler import net.minecraftforge.items.IItemHandlerModifiable import net.minecraftforge.items.wrapper.CombinedInvWrapper +import org.ender_development.catalyx.api.v1.common.extensions.orIfNotEmpty import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.client.button.AbstractButtonWrapper import org.ender_development.catalyx.core.client.button.PauseButtonWrapper @@ -36,11 +37,11 @@ import org.ender_development.catalyx.core.tiles.helper.* /** * A base TileEntity in Catalyx, implementing separate input and output inventories; saving/loading from NBT; energy, fluid and item capability handling */ -@Suppress("UNUSED") +@Suppress("unused") abstract class BaseTile(open val mod: ICatalyxMod) : TileEntity(), BaseContainer.IBaseContainerCompat { var inputSlots = 0 var outputSlots = 0 - override val SIZE + override val inventorySlotCount get() = inventory.slots var dirtyTicks = 0 @@ -62,10 +63,12 @@ abstract class BaseTile(open val mod: ICatalyxMod) : TileEntity(), BaseContainer open val facing: EnumFacing get() = world.getBlockState(pos).properties.getOrDefault(BlockHorizontal.FACING, EnumFacing.NORTH) as EnumFacing - open val inventory: IItemHandler + // note: this has to be a getter + open val inventory get() = CombinedInvWrapper(input, output) - open val automationInvHandler: CombinedInvWrapper + // note: this has to be a getter + open val automationInvHandler get() = CombinedInvWrapper(automationInput, automationOutput) override fun canInteractWith(player: EntityPlayer) = @@ -80,16 +83,18 @@ abstract class BaseTile(open val mod: ICatalyxMod) : TileEntity(), BaseContainer initInventoryInputCapability() automationInput = object : WrappedItemHandler(input) { - override fun extractItem(slot: Int, amount: Int, simulate: Boolean) = ItemStack.EMPTY + override fun extractItem(slot: Int, amount: Int, simulate: Boolean) = + ItemStack.EMPTY } output = object : TileStackHandler(outputSlots, this) { - override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean) = stack + override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean) = + stack } automationOutput = object : WrappedItemHandler(output) { override fun extractItem(slot: Int, amount: Int, simulate: Boolean) = - if(!getStackInSlot(slot).isEmpty) super.extractItem(slot, amount, simulate) else ItemStack.EMPTY + getStackInSlot(slot).orIfNotEmpty { super.extractItem(slot, amount, simulate) } } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/tiles/CenterTile.kt b/src/main/kotlin/org/ender_development/catalyx/core/tiles/CenterTile.kt index 7017907..1f88977 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/tiles/CenterTile.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/tiles/CenterTile.kt @@ -7,15 +7,15 @@ import net.minecraft.util.EnumHand import net.minecraft.util.math.BlockPos import net.minecraft.world.World import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.getHorizontalSurroundings +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.blocks.multiblock.IMultiblockEdge import org.ender_development.catalyx.core.blocks.multiblock.IMultiblockTile -import org.ender_development.catalyx.core.utils.DevUtils -import org.ender_development.catalyx.core.utils.extensions.getHorizontalSurroundings open class CenterTile(mod: ICatalyxMod) : BaseTile(mod), IMultiblockTile { internal constructor() : this(Catalyx) { - if(!DevUtils.isDeobfuscated) + if(!Utils.environment.isDeobfuscated) error("use the full constructor") } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/tiles/TESRTile.kt b/src/main/kotlin/org/ender_development/catalyx/core/tiles/TESRTile.kt index 83914c1..735ce54 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/tiles/TESRTile.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/tiles/TESRTile.kt @@ -4,14 +4,14 @@ import net.minecraft.client.Minecraft import net.minecraft.util.EnumFacing import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly +import org.ender_development.catalyx.api.v1.common.extensions.relativeDirectionTo +import org.ender_development.catalyx.api.v1.common.extensions.withAlpha import org.ender_development.catalyx.core.ICatalyxMod import org.ender_development.catalyx.core.client.tesr.AbstractTESRenderer import org.ender_development.catalyx.core.client.tesr.HudInfoRenderer import org.ender_development.catalyx.core.tiles.helper.HudInfoLine import org.ender_development.catalyx.core.tiles.helper.IHudInfoProvider import org.ender_development.catalyx.core.tiles.helper.ITESRTile -import org.ender_development.catalyx.core.utils.extensions.relativeDirectionTo -import org.ender_development.catalyx.core.utils.extensions.withAlpha import java.awt.Color open class TESRTile(mod: ICatalyxMod) : BaseTile(mod), ITESRTile, IHudInfoProvider { diff --git a/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/ICopyPasteExtraTile.kt b/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/ICopyPasteExtraDataTile.kt similarity index 51% rename from src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/ICopyPasteExtraTile.kt rename to src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/ICopyPasteExtraDataTile.kt index 9e17fdb..7f5b921 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/ICopyPasteExtraTile.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/ICopyPasteExtraDataTile.kt @@ -3,12 +3,15 @@ package org.ender_development.catalyx.core.tiles.helper import net.minecraft.entity.player.EntityPlayer import net.minecraft.nbt.NBTTagCompound -/** TODO come up with a better name lmfao */ -interface ICopyPasteExtraTile { +// TODO move somewhere into API +/** + * An interface for Tile Entities to implement if they want to copy/paste extra data with the Catalyx [CopyPasteTool][org.ender_development.catalyx.core.items.CopyPasteTool] + */ +interface ICopyPasteExtraDataTile { /** * Write data into the NBT Tag to be copied and stored * - * Note: if your TE implements [org.ender_development.catalyx.client.gui.BaseGuiTyped.IDefaultButtonVariables] (like [org.ender_development.catalyx.tiles.BaseMachineTile] does), the `isPaused` and `needsRedstonePower` fields are already copied + * Note: if your TE implements [BaseGuiTyped.IDefaultButtonVariables][org.ender_development.catalyx.core.client.gui.BaseGuiTyped.IDefaultButtonVariables] (like [BaseMachineTile][org.ender_development.catalyx.core.tiles.BaseMachineTile] does), the `isPaused` and `needsRedstonePower` fields are already copied */ fun copyData(tag: NBTTagCompound) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/TileStackHandler.kt b/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/TileStackHandler.kt index 8d04b96..2755eed 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/TileStackHandler.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/tiles/helper/TileStackHandler.kt @@ -3,10 +3,11 @@ package org.ender_development.catalyx.core.tiles.helper import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.items.ItemStackHandler +import org.ender_development.catalyx.api.v1.common.extensions.get +import org.ender_development.catalyx.api.v1.common.extensions.orEmpty +import org.ender_development.catalyx.api.v1.common.extensions.tryInsertInto import org.ender_development.catalyx.core.tiles.BaseTile import org.ender_development.catalyx.core.tiles.BaseTile.Companion.ITEM_CAP -import org.ender_development.catalyx.core.utils.extensions.get -import org.ender_development.catalyx.core.utils.extensions.tryInsertInto open class TileStackHandler(size: Int, val tile: BaseTile) : ItemStackHandler() { init { @@ -18,7 +19,10 @@ open class TileStackHandler(size: Int, val tile: BaseTile) : ItemStackHandler() tile.markDirty() } - fun clear() = (0.. 0) { incrementSlot(slot, increaseBy) stack.shrink(increaseBy) - if(stack.count <= 0 || stack.isEmpty) + if(stack.isEmpty) return ItemStack.EMPTY } } @@ -64,8 +68,7 @@ open class TileStackHandler(size: Int, val tile: BaseTile) : ItemStackHandler() if(temp.count - amount < 0) return temp.shrink(amount) - if(temp.count <= 0) this.setStackInSlot(slot, ItemStack.EMPTY) - else this.setStackInSlot(slot, temp) + setStackInSlot(slot, temp.orEmpty()) } fun eject(direction: EnumFacing): Boolean { diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/BlockPosUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/BlockPosUtils.kt new file mode 100644 index 0000000..d3599af --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/BlockPosUtils.kt @@ -0,0 +1,32 @@ +package org.ender_development.catalyx.core.utils + +import net.minecraft.util.math.BlockPos +import org.ender_development.catalyx.api.v1.common.extensions.minus +import org.ender_development.catalyx.api.v1.common.extensions.plus +import org.ender_development.catalyx.api.v1.common.extensions.rotateY +import org.ender_development.catalyx.api.v1.utils.interfaces.IBlockPosUtils + +object BlockPosUtils : IBlockPosUtils { + override fun wall(center: BlockPos, r: Int, h: Int, offset: Int, degrees: Int, shrink: Int): Pair { + val baseOrigin = BlockPos(center.x - r, center.y, center.z + r + offset) + val v1 = BlockPos(2 * r - shrink, 0, 0) + val v2 = BlockPos(0, h, 0) + + val origin = (baseOrigin - center).rotateY(degrees) + center + val v1Rot = v1.rotateY(degrees) + + val corners = arrayOf( + origin, + origin + v1Rot, + origin + v2, + origin + v1Rot + v2 + ) + + return BlockPos(corners.minOf { it.x }, corners.minOf { it.y }, corners.minOf { it.z }) to BlockPos(corners.maxOf { it.x }, corners.maxOf { it.y }, corners.maxOf { it.z }) + } + + override fun hollowCuboid(center: BlockPos, r: Int, h: Int, offset: Int, shrink: Int) = + Array(4) { + wall(center, r, h, offset, it * 90, shrink) + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/Delegates.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/Delegates.kt index 5684646..fe85c55 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/Delegates.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/Delegates.kt @@ -1,6 +1,6 @@ package org.ender_development.catalyx.core.utils -import org.ender_development.catalyx.core.utils.extensions.modLoaded +import org.ender_development.catalyx.api.v1.common.extensions.modLoaded import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -24,7 +24,7 @@ object Delegates { private class OnlyIfFalse(val modName: String) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): V { - throw IllegalStateException("Tried to get property '${property.name}' without mod '$modName' being loaded") + error("Tried to get property '${property.name}' without mod '$modName' being loaded") } override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {} @@ -34,7 +34,7 @@ object Delegates { var value: V? = null override fun getValue(thisRef: Any?, property: KProperty<*>): V { - return value ?: throw IllegalStateException("Tried to get property '${property.name}' before initializing it") + return value ?: error("Tried to get property '${property.name}' before initializing it") } override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) { diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/DevUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/DevUtils.kt deleted file mode 100644 index 229e382..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/DevUtils.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.ender_development.catalyx.core.utils - -import net.minecraft.launchwrapper.Launch - -/** - * Utility object for checking whether you're in a dev instance - */ -object DevUtils { - /** - * Whether the environment is deobfuscated (dev environment) - * @see net.minecraftforge.fml.relauncher.CoreModManager#L208 - * @return true if deobfuscated, false if obfuscated - */ - val isDeobfuscated: Boolean - //inline get() = CoreModManager.deobfuscatedEnvironment - inline get() = Launch.blackboard["fml.deobfuscatedEnvironment"] as Boolean -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/EnvironmentUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/EnvironmentUtils.kt new file mode 100644 index 0000000..beb74da --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/EnvironmentUtils.kt @@ -0,0 +1,18 @@ +package org.ender_development.catalyx.core.utils + +import net.minecraft.launchwrapper.Launch +import net.minecraftforge.fml.common.FMLCommonHandler +import org.ender_development.catalyx.api.v1.utils.interfaces.IEnvironmentUtils + +/** + * Utility object for checking the current side (client or server). + */ +object EnvironmentUtils : IEnvironmentUtils { + private val handler = FMLCommonHandler.instance() + + override val isClient = handler.effectiveSide.isClient + override val isServer = handler.effectiveSide.isServer + override val isDedicatedClient = handler.side.isClient + override val isDedicatedServer = handler.side.isServer + override val isDeobfuscated = Launch.blackboard["fml.deobfuscatedEnvironment"] as Boolean +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/FluidTankUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/FluidTankUtils.kt deleted file mode 100644 index c57e929..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/FluidTankUtils.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.ender_development.catalyx.core.utils - -import net.minecraft.tileentity.TileEntity -import net.minecraftforge.fluids.Fluid -import net.minecraftforge.fluids.FluidStack -import net.minecraftforge.fluids.FluidTank - -object FluidTankUtils { - // These cannot be an extension as there's currently no way to create a static extension for a JVM class afact (see https://youtrack.jetbrains.com/issue/KT-11968) - - inline fun create(tile: TileEntity, capacity: Int, canFill: Boolean, canDrain: Boolean, crossinline onContentsChangedCallback: () -> Unit) = - object : FluidTank(capacity) { - init { - setTileEntity(tile) - setCanFill(canFill) - setCanDrain(canDrain) - } - - override fun onContentsChanged() = - onContentsChangedCallback() - } - - inline fun create(tile: TileEntity, capacity: Int, canFill: Boolean, canDrain: Boolean, vararg fluidWhitelist: Fluid, crossinline onContentsChangedCallback: () -> Unit) = - object : FluidTank(capacity) { - init { - setTileEntity(tile) - setCanFill(canFill) - setCanDrain(canDrain) - } - - override fun onContentsChanged() = - onContentsChangedCallback() - - override fun canFillFluidType(fluid: FluidStack?) = - fluid != null && fluidWhitelist.any { fluid.fluid === it } - - override fun canDrainFluidType(fluid: FluidStack?) = - canFillFluidType(fluid) - } -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/IItemStackHash.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/IItemStackHash.kt index 4c5d9d2..ac6b0f8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/IItemStackHash.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/IItemStackHash.kt @@ -2,6 +2,7 @@ package org.ender_development.catalyx.core.utils import it.unimi.dsi.fastutil.Hash import net.minecraft.item.ItemStack +import org.ender_development.catalyx.api.v1.common.extensions.isNullOrEmpty import java.util.* /** @@ -17,42 +18,33 @@ interface IItemStackHash : Hash.Strategy { inline get() = Builder() /** - * Generates an [IItemStackHash] instance configured to compare every aspect of ItemStacks. - * - * @return a new [IItemStackHash] instance as described above. + * An [IItemStackHash] instance configured to compare every aspect of ItemStacks. */ - val comparingAll: IItemStackHash - inline get() = builder.apply { - item = true - meta = true - damage = true - nbt = true - amount = true - }.build() + val comparingAll = builder.apply { + item = true + meta = true + damage = true + nbt = true + amount = true + }.build() /** - * Generates an [IItemStackHash] instance configured to compare every aspect of ItemStacks except the quantity and meta. - * - * @return a new [IItemStackHash] instance as described above. + * An [IItemStackHash] instance configured to compare item type, damage and NBT (ergo everything except quantity and meta). */ - val comparingAllButCount: IItemStackHash - inline get() = builder.apply { - item = true - damage = true - nbt = true - }.build() + val comparingAllButCount = builder.apply { + item = true + damage = true + nbt = true + }.build() /** - * Generates an [IItemStackHash] instance configured to compare Item type and metadata only. - * - * @return a new [IItemStackHash] instance as described above. + * An [IItemStackHash] instance configured to compare item type, damage and quantity. */ - val comparingItemDamageCount: IItemStackHash - inline get() = builder.apply { - item = true - damage = true - amount = true - }.build() + val comparingItemDamageCount = builder.apply { + item = true + damage = true + amount = true + }.build() } /** @@ -89,7 +81,7 @@ interface IItemStackHash : Hash.Strategy { } override fun hashCode(stack: ItemStack?): Int { - if(stack == null || stack.isEmpty) + if(stack.isNullOrEmpty()) return 0 return Objects.hash( diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/NetworkUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/NetworkUtils.kt deleted file mode 100644 index b600c81..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/NetworkUtils.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.ender_development.catalyx.core.utils - -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound -import net.minecraft.network.PacketBuffer -import net.minecraftforge.fluids.FluidStack -import org.ender_development.catalyx.Catalyx -import java.io.IOException - -/** - * Utility functions for reading and writing ItemStacks and FluidStacks to PacketBuffers. - * Handles potential IOExceptions and logs them using the Catalyx logger. - * Loosely based on code from [ModularUI](https://github.com/CleanroomMC/ModularUI/blob/master/src/main/java/com/cleanroommc/modularui/network/NetworkUtils.java) licensed under GNU LGPL-3.0 - */ -object NetworkUtils { - fun writeItemStack(buffer: PacketBuffer, itemStack: ItemStack): PacketBuffer = - buffer.writeItemStack(itemStack) - - fun readItemStack(buffer: PacketBuffer): ItemStack = - try { - buffer.readItemStack() - } catch(e: IOException) { - Catalyx.LOGGER.catching(e) - ItemStack.EMPTY - } - - fun writeFluidStack(buffer: PacketBuffer, fluidStack: FluidStack?) { - buffer.writeBoolean(fluidStack == null) - fluidStack?.let { - buffer.writeCompoundTag(it.writeToNBT(NBTTagCompound())) - } - } - - fun readFluidStack(buffer: PacketBuffer): FluidStack? = - try { - if(buffer.readBoolean()) - null - else - FluidStack.loadFluidStackFromNBT(buffer.readCompoundTag()) - } catch(e: IOException) { - Catalyx.LOGGER.catching(e) - null - } -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/RenderUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/RenderUtils.kt index 464412d..3a32bc0 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/RenderUtils.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/RenderUtils.kt @@ -1,3 +1,5 @@ +@file:Suppress("NOTHING_TO_INLINE") + package org.ender_development.catalyx.core.utils import net.minecraft.client.Minecraft @@ -5,6 +7,7 @@ import net.minecraft.client.gui.FontRenderer import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.TextureManager import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.client.renderer.vertex.DefaultVertexFormats @@ -12,83 +15,63 @@ import net.minecraft.util.ResourceLocation import net.minecraftforge.fluids.Fluid import net.minecraftforge.fluids.FluidStack import net.minecraftforge.fluids.FluidTank -import org.ender_development.catalyx.core.utils.extensions.destructFloat +import org.ender_development.catalyx.api.v1.common.extensions.destructFloat +import org.ender_development.catalyx.api.v1.common.extensions.getColor import org.lwjgl.opengl.GL11 import java.awt.Color object RenderUtils { val minecraft: Minecraft = Minecraft.getMinecraft() - val TESSELLATOR: Tessellator = Tessellator.getInstance() - val BUFFER_BUILDER: BufferBuilder = TESSELLATOR.buffer - val FONT_RENDERER: FontRenderer = minecraft.fontRenderer - val renderEngine: TextureManager = minecraft.renderEngine - - val BLOCK_TEX: ResourceLocation = TextureMap.LOCATION_BLOCKS_TEXTURE + val tessellator: Tessellator = Tessellator.getInstance() + val bufferBuilder: BufferBuilder = tessellator.buffer + val fontRenderer: FontRenderer = minecraft.fontRenderer + val textureManager: TextureManager = minecraft.renderEngine - fun bindBlockTexture() = - renderEngine.bindTexture(BLOCK_TEX) + val blockTexture: ResourceLocation = TextureMap.LOCATION_BLOCKS_TEXTURE - fun bindTexture(string: String) = - renderEngine.bindTexture(ResourceLocation(string)) + inline fun bindBlockTexture() = + bindTexture(blockTexture) - fun bindTexture(tex: ResourceLocation) = - renderEngine.bindTexture(tex) + inline fun bindTexture(tex: ResourceLocation) = + textureManager.bindTexture(tex) fun getStillTexture(fluid: FluidStack?) = - fluid?.fluid?.let { - getStillTexture(it) - } + fluid?.fluid?.let(::getStillTexture) fun getStillTexture(fluid: Fluid) = - fluid.still?.let { - minecraft.textureMapBlocks.getTextureExtry("$it") - } + fluid.still?.toString()?.let(minecraft.textureMapBlocks::getTextureExtry) - fun renderGuiTank(tank: FluidTank, x: Double, y: Double, zLevel: Double, width: Double, height: Double) = - renderGuiTank(tank.fluid, tank.capacity, tank.fluidAmount, x, y, zLevel, width, height) + inline fun renderGuiTank(tank: FluidTank, x: Double, y: Double, width: Double, height: Double) = + renderGuiTank(tank.fluid, tank.capacity, x, y, width, height) - fun renderGuiTank(fluid: FluidStack?, capacity: Int, amount: Int, x: Double, y: Double, zLevel: Double, width: Double, height: Double) { - if(fluid == null || fluid.fluid == null || fluid.amount <= 0) + fun renderGuiTank(fluid: FluidStack?, capacity: Int, x: Double, y: Double, width: Double, height: Double) { + if(fluid == null || fluid.amount <= 0) return - val icon = getStillTexture(fluid) ?: return + val sprite = getStillTexture(fluid) ?: return - val renderAmount = (amount * height / capacity).coerceIn(.0, height) - val posY = (y + height - renderAmount) + val bottomY = y + height + val topY = bottomY - height * fluid.amount.coerceAtMost(capacity) / capacity + + val (red, green, blue) = Color(fluid.getColor()).destructFloat() + GlStateManager.color(red, green, blue, 1f) + GlStateManager.enableBlend() bindBlockTexture() - val color = fluid.fluid.getColor(fluid) - GL11.glColor3ub((color shr 16 and 0xFF).toByte(), (color shr 8 and 0xFF).toByte(), (color and 0xFF).toByte()) - // TODO clean up this mess - GlStateManager.enableBlend() - var i = 0 - while(i < width) { - var j = 0 - while(j < renderAmount) { - val drawWidth = (width - i).coerceAtMost(16.0) - val drawHeight = (renderAmount - j).coerceAtMost(16.0) - - val drawX = x + i - val drawY = posY + j - - val minU = icon.minU.toDouble() - val maxU = icon.maxU.toDouble() - val minV = icon.minV.toDouble() - val maxV = icon.maxV.toDouble() - - val tessellator = Tessellator.getInstance() - val tes = tessellator.buffer - tes.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX) - tes.pos(drawX, drawY + drawHeight, 0.0).tex(minU, minV + (maxV - minV) * drawHeight / 16f).endVertex() - tes.pos(drawX + drawWidth, drawY + drawHeight, 0.0).tex(minU + (maxU - minU) * drawWidth / 16f, minV + (maxV - minV) * drawHeight / 16f).endVertex() - tes.pos(drawX + drawWidth, drawY, 0.0).tex(minU + (maxU - minU) * drawWidth / 16f, minV).endVertex() - tes.pos(drawX, drawY, 0.0).tex(minU, minV).endVertex() - tessellator.draw() - j += 16 + // in any normal programming language, this would just be something like `for(double drawY = topY; drawY < bottomY; drawY += 16)` + var drawY = topY + while(drawY < bottomY) { + var xOffset = 0 + while(xOffset < width) { + val drawWidth = (width - xOffset).coerceAtMost(16.0) + val drawHeight = (bottomY - drawY).coerceAtMost(16.0) + + drawTexturedModalRect(x + xOffset, drawY, sprite, drawWidth, drawHeight) + xOffset += 16 } - i += 16 + drawY += 16 } GlStateManager.disableBlend() } @@ -105,7 +88,7 @@ object RenderUtils { GlStateManager.pushMatrix() GlStateManager.translate(x, y, .0) GlStateManager.scale(scale, scale, .0) - FONT_RENDERER.drawString(text, 0f, 0f, color, shadow) + fontRenderer.drawString(text, 0f, 0f, color, shadow) GlStateManager.popMatrix() } @@ -138,12 +121,12 @@ object RenderUtils { val tw = 1 / tileWidth val th = 1 / tileHeight val (red, green, blue, alpha) = color.destructFloat() - BUFFER_BUILDER.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR) - BUFFER_BUILDER.pos(x, y + height, zOffset).tex(u * tw, (v + vHeight) * th).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y + height, zOffset).tex((u + uWidth) * tw, (v + vHeight) * th).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y, zOffset).tex((u + uWidth) * tw, v * th).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x, y, zOffset).tex(u * tw, v * th).color(red, green, blue, alpha).endVertex() - TESSELLATOR.draw() + bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR) + bufferBuilder.pos(x, y + height, zOffset).tex(u * tw, (v + vHeight) * th).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y + height, zOffset).tex((u + uWidth) * tw, (v + vHeight) * th).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y, zOffset).tex((u + uWidth) * tw, v * th).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x, y, zOffset).tex(u * tw, v * th).color(red, green, blue, alpha).endVertex() + tessellator.draw() } /** @@ -157,23 +140,23 @@ object RenderUtils { GlStateManager.pushMatrix() if(!filled) { - BUFFER_BUILDER.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR) - - BUFFER_BUILDER.pos(x, y, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x, y + height, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x, y + height, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y + height, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y + height, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x, y, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR) + + bufferBuilder.pos(x, y, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x, y + height, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x, y + height, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y + height, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y + height, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x, y, .0).color(red, green, blue, alpha).endVertex() } else { - BUFFER_BUILDER.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR) + bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR) - BUFFER_BUILDER.pos(x, y + 0, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x, y + height, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y + height, .0).color(red, green, blue, alpha).endVertex() - BUFFER_BUILDER.pos(x + width, y + 0, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x, y + 0, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x, y + height, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y + height, .0).color(red, green, blue, alpha).endVertex() + bufferBuilder.pos(x + width, y + 0, .0).color(red, green, blue, alpha).endVertex() } GlStateManager.translate(.0, .0, zTranslate) @@ -182,7 +165,7 @@ object RenderUtils { GlStateManager.disableLighting() GlStateManager.disableTexture2D() GlStateManager.depthMask(false) - TESSELLATOR.draw() + tessellator.draw() GlStateManager.depthMask(true) GlStateManager.enableTexture2D() GlStateManager.enableLighting() @@ -190,17 +173,36 @@ object RenderUtils { GlStateManager.popMatrix() } - const val MAGIC_NUMBER = 0.00390625 + const val MAGIC_NUMBER = 1.0 / 256.0 /** * Draw a 2D textured rectangle. Adapted from [Gui#drawTexturedModalRect][net.minecraft.client.gui.Gui.drawTexturedModalRect]. */ fun drawTexturedModalRect(x: Double, y: Double, u: Float, v: Float, width: Double, height: Double, zLevel: Double = .0) { - BUFFER_BUILDER.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX) - BUFFER_BUILDER.pos(x, y + height, zLevel).tex(u * MAGIC_NUMBER, (v + height) * MAGIC_NUMBER).endVertex() - BUFFER_BUILDER.pos(x + width, y + height, zLevel).tex((u + width) * MAGIC_NUMBER, (v + height) * MAGIC_NUMBER).endVertex() - BUFFER_BUILDER.pos(x + width, y, zLevel).tex((u + width) * MAGIC_NUMBER, v * MAGIC_NUMBER).endVertex() - BUFFER_BUILDER.pos(x, y, zLevel).tex(u * MAGIC_NUMBER, v * MAGIC_NUMBER).endVertex() - TESSELLATOR.draw() + bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX) + bufferBuilder.pos(x, y + height, zLevel).tex(u * MAGIC_NUMBER, (v + height) * MAGIC_NUMBER).endVertex() + bufferBuilder.pos(x + width, y + height, zLevel).tex((u + width) * MAGIC_NUMBER, (v + height) * MAGIC_NUMBER).endVertex() + bufferBuilder.pos(x + width, y, zLevel).tex((u + width) * MAGIC_NUMBER, v * MAGIC_NUMBER).endVertex() + bufferBuilder.pos(x, y, zLevel).tex(u * MAGIC_NUMBER, v * MAGIC_NUMBER).endVertex() + tessellator.draw() + } + + /** + * Draw a textured rectangle using the [sprite]. Adapted from [Gui#drawTexturedModalRect][net.minecraft.client.gui.Gui.drawTexturedModalRect] + * + * @param sprite Sprite to render + * @param zLevel Z level to render at + */ + fun drawTexturedModalRect(x: Double, y: Double, sprite: TextureAtlasSprite, width: Double, height: Double, zLevel: Double = .0) { + val minU = sprite.minU.toDouble() + val maxU = sprite.maxU.toDouble() + val minV = sprite.minV.toDouble() + val maxV = sprite.maxV.toDouble() + bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX) + bufferBuilder.pos(x, y + height, zLevel).tex(minU, maxV).endVertex() + bufferBuilder.pos(x + width, y + height, zLevel).tex(maxU, maxV).endVertex() + bufferBuilder.pos(x + width, y, zLevel).tex(maxU, minV).endVertex() + bufferBuilder.pos(x, y, zLevel).tex(minU, minV).endVertex() + tessellator.draw() } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/SideUtils.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/SideUtils.kt deleted file mode 100644 index 8d711c9..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/SideUtils.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.ender_development.catalyx.core.utils - -import net.minecraftforge.fml.common.FMLCommonHandler - -/** - * Utility object for checking the current side (client or server). - */ -object SideUtils { - private val handler = FMLCommonHandler.instance() - - val isClient = handler.effectiveSide.isClient - val isServer = handler.effectiveSide.isServer - val isDedicatedClient = handler.side.isClient - val isDedicatedServer = handler.side.isServer -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/BlockPos.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/BlockPos.kt deleted file mode 100644 index d8e312e..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/BlockPos.kt +++ /dev/null @@ -1,44 +0,0 @@ -@file:Suppress("NOTHING_TO_INLINE") - -package org.ender_development.catalyx.core.utils.extensions - -import net.minecraft.entity.Entity -import net.minecraft.util.EnumFacing -import net.minecraft.util.math.BlockPos -import org.ender_development.catalyx.core.utils.math.BlockPosRotate - -inline fun BlockPos.rotateX(degrees: Int) = - BlockPosRotate.rotateX(this, degrees) - -inline fun BlockPos.rotateY(degrees: Int) = - BlockPosRotate.rotateY(this, degrees) - -inline fun BlockPos.rotateZ(degrees: Int) = - BlockPosRotate.rotateZ(this, degrees) - -inline operator fun BlockPos.minus(other: BlockPos): BlockPos = - subtract(other) - -inline operator fun BlockPos.plus(other: BlockPos): BlockPos = - add(other) - -inline operator fun BlockPos.times(scalar: Int) = - BlockPos(x * scalar, y * scalar, z * scalar) - -inline fun Pair.getAllInBox() = - BlockPos.getAllInBox(first, second) - -inline fun BlockPos.getFacingFromEntityPosition(entityX: Float, entityZ: Float): EnumFacing = - EnumFacing.getFacingFromVector(entityX - x, 0f, entityZ - z) - -inline fun BlockPos.getFacingFromEntity(entity: Entity): EnumFacing = - getFacingFromEntityPosition(entity.posX.toFloat(), entity.posZ.toFloat()) - -/** - * @see org.ender_development.catalyx.blocks.multiblock.parts.AbstractEdgeBlock - */ -fun BlockPos.getHorizontalSurroundings() = arrayOf( - north().west(), north(), north().east(), - west(), /* us */ east(), - south().west(), south(), south().east() -) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Container.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Container.kt deleted file mode 100644 index 6dd66cb..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/Container.kt +++ /dev/null @@ -1,9 +0,0 @@ -@file:Suppress("NOTHING_TO_INLINE") - -package org.ender_development.catalyx.core.utils.extensions - -import net.minecraft.inventory.Container -import net.minecraft.inventory.Slot - -inline operator fun Container.get(slotId: Int): Slot = - getSlot(slotId) diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/IItemHandler.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/IItemHandler.kt deleted file mode 100644 index a0b78db..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/extensions/IItemHandler.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.ender_development.catalyx.core.utils.extensions - -import net.minecraft.item.ItemStack -import net.minecraftforge.items.IItemHandler - -operator fun IItemHandler.get(idx: Int) = - getStackInSlot(idx) - -fun IItemHandler.tryInsertInto(otherHandler: IItemHandler): Boolean { - for(i in 0.. { - return (0...containsItem(stack: ItemStack, strict: Boolean = false) = - any { OreDictionary.itemMatches(it, stack, strict) } - -fun List.toImmutableList(): ImmutableList = - ImmutableList.copyOf(this) - -fun List.toSingletonList(): List = - ObjectLists.singleton(this[0]) - -fun List.validateEach(validator: (idx: Int, T) -> ValidationResult) = - mapIndexed(validator) - -@JvmName("copyOfIS") -fun List.copyOf() = - map { - if(it.isEmpty) - ItemStack.EMPTY - else - it.copy() - } - -@JvmName("copyOfFS") -fun List.copyOf() = - map { it.copy() } - -inline fun List.mapUnique(transform: (T) -> R) = - mapTo(hashSetOf(), transform) - -fun List.getBySeverity(severity: ValidationError.Severity) = - filter { it.severity == severity } - -fun List.getByMinSeverity(severity: ValidationError.Severity) = - filter { it.severity >= severity } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/math/BlockPosRotate.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/math/BlockPosRotate.kt deleted file mode 100644 index 2695ea8..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/math/BlockPosRotate.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.ender_development.catalyx.core.utils.math - -import net.minecraft.util.math.BlockPos -import kotlin.math.cos -import kotlin.math.roundToInt -import kotlin.math.sin - -object BlockPosRotate { - fun rotateX(vec: BlockPos, degrees: Int): BlockPos { - val rad = Math.toRadians(degrees.toDouble()) - val cos = cos(rad) - val sin = sin(rad) - return BlockPos( - vec.x, - (vec.y * cos - vec.z * sin).roundToInt(), - (vec.y * sin + vec.z * cos).roundToInt() - ) - } - - fun rotateY(vec: BlockPos, degrees: Int): BlockPos { - val rad = Math.toRadians(degrees.toDouble()) - val cos = cos(rad) - val sin = sin(rad) - return BlockPos( - (vec.x * cos - vec.z * sin).roundToInt(), - vec.y, - (vec.x * sin + vec.z * cos).roundToInt() - ) - } - - fun rotateZ(vec: BlockPos, degrees: Int): BlockPos { - val rad = Math.toRadians(degrees.toDouble()) - val cos = cos(rad) - val sin = sin(rad) - return BlockPos( - (vec.x * cos - vec.y * sin).roundToInt(), - (vec.x * sin + vec.y * cos).roundToInt(), - vec.z - ) - } -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/AbstractJsonParser.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/AbstractJsonParser.kt index 4197945..e802b93 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/AbstractJsonParser.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/AbstractJsonParser.kt @@ -4,10 +4,12 @@ import com.cleanroommc.groovyscript.helper.JsonHelper import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken import org.ender_development.catalyx.Catalyx -import org.ender_development.catalyx.core.utils.extensions.getByMinSeverity -import org.ender_development.catalyx.core.utils.extensions.getBySeverity -import org.ender_development.catalyx.core.utils.validation.ValidationError -import org.ender_development.catalyx.core.utils.validation.ValidationResult +import org.ender_development.catalyx.api.v1.common.Severity +import org.ender_development.catalyx.api.v1.common.extensions.getByMinSeverity +import org.ender_development.catalyx.api.v1.common.extensions.getBySeverity +import org.ender_development.catalyx.api.v1.validation.Validation.newValidationError +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError +import org.ender_development.catalyx.core.validation.ValidationResult import java.io.File import java.io.FileReader import java.io.FileWriter @@ -21,7 +23,7 @@ abstract class AbstractJsonParser : IParser { abstract fun sanitize(rawData: TRaw): ValidationResult override fun parse(): List { - val file = File(filePath) + val file = File(input) if(!file.exists()) createDefaultFile(file) @@ -35,18 +37,22 @@ abstract class AbstractJsonParser : IParser { val results = rawData.map(::sanitize) val successfulItems = mutableListOf() - val allErrors = mutableListOf() - val allWarnings = mutableListOf() + val allErrors = mutableListOf() + val allWarnings = mutableListOf() results.forEachIndexed { idx, result -> when { result.success -> successfulItems.add(result.data!!) result.failure -> { - val errors = result.errors.getByMinSeverity(ValidationError.Severity.ERROR) - val warnings = result.errors.getBySeverity(ValidationError.Severity.WARNING) - - val contextualErrors = errors.map { it.copy(message = "Item #$idx: ${it.message}") } - val contextualWarnings = warnings.map { it.copy(message = "Item #$idx: ${it.message}") } + val errors = result.errors.getByMinSeverity(Severity.ERROR) + val warnings = result.errors.getBySeverity(Severity.WARNING) + + val contextualErrors = errors.map { + newValidationError(it.field, "Item #$idx: ${it.message}", it.code, it.severity) + } + val contextualWarnings = warnings.map { + newValidationError(it.field, "Item #$idx: ${it.message}", it.code, it.severity) + } allErrors.addAll(contextualErrors) allWarnings.addAll(contextualWarnings) logValidationIssues(idx, contextualErrors, contextualWarnings) @@ -70,14 +76,14 @@ abstract class AbstractJsonParser : IParser { override val stats: ParsingStats get() = lastParsingStats - private fun logValidationIssues(itemIndex: Int, errors: List, warnings: List) { + private fun logValidationIssues(itemIndex: Int, errors: List, warnings: List) { if(errors.isNotEmpty()) { - Catalyx.LOGGER.error("❌ Failed to parse item $itemIndex from $filePath:") + Catalyx.LOGGER.error("❌ Failed to parse item $itemIndex from $input:") errors.forEach { Catalyx.LOGGER.error(" $it") } } if(warnings.isNotEmpty()) { - Catalyx.LOGGER.warn("⚠️ Warnings for item $itemIndex from $filePath:") + Catalyx.LOGGER.warn("⚠️ Warnings for item $itemIndex from $input:") warnings.forEach { Catalyx.LOGGER.warn(" $it") } } } @@ -86,7 +92,7 @@ abstract class AbstractJsonParser : IParser { val stats = lastParsingStats val successRate = stats.successRate * 100 - Catalyx.LOGGER.info("📊 Parsing Summary for $filePath:") + Catalyx.LOGGER.info("📊 Parsing Summary for $input:") Catalyx.LOGGER.info(" Total items: ${stats.totalItems}") Catalyx.LOGGER.info(" ✅ Successful: ${stats.successfulItems}") Catalyx.LOGGER.info(" ❌ Failed: ${stats.failedItems}") @@ -94,8 +100,8 @@ abstract class AbstractJsonParser : IParser { if(stats.hasErrors) { Catalyx.LOGGER.info(" 🔍 Validation errors: ${stats.errors.size}") - val criticalErrors = stats.errors.getBySeverity(ValidationError.Severity.CRITICAL) - val regularErrors = stats.errors.getBySeverity(ValidationError.Severity.ERROR) + val criticalErrors = stats.errors.getBySeverity(Severity.CRITICAL) + val regularErrors = stats.errors.getBySeverity(Severity.ERROR) if(criticalErrors.isNotEmpty()) Catalyx.LOGGER.info(" 🚨 Critical: ${criticalErrors.size}") diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/IParser.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/IParser.kt index 028e46f..2fd0a0c 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/IParser.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/IParser.kt @@ -2,6 +2,6 @@ package org.ender_development.catalyx.core.utils.parser interface IParser { fun parse(): List - val filePath: String + val input: String val stats: ParsingStats } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParserRegistryBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParserRegistryBuilder.kt index 01e25a0..a52eb3a 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParserRegistryBuilder.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParserRegistryBuilder.kt @@ -1,7 +1,7 @@ package org.ender_development.catalyx.core.utils.parser import com.google.gson.reflect.TypeToken -import org.ender_development.catalyx.core.utils.validation.ValidationResult +import org.ender_development.catalyx.core.validation.ValidationResult class ParserRegistryBuilder { private val registry = ParserRegistry() @@ -11,7 +11,7 @@ class ParserRegistryBuilder { fun jsonParser(key: String, filePath: String, defaultData: () -> List, sanitizer: (T) -> ValidationResult) { val parser = object : AbstractJsonParser() { - override val filePath = filePath + override val input = filePath override val defaultRawData: List get() = defaultData() diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParsingStats.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParsingStats.kt index 713644d..6fee0ef 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParsingStats.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/utils/parser/ParsingStats.kt @@ -1,19 +1,19 @@ package org.ender_development.catalyx.core.utils.parser -import org.ender_development.catalyx.core.utils.validation.ValidationError +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError data class ParsingStats( val totalItems: Int = 0, val successfulItems: Int = 0, val failedItems: Int = 0, - val errors: List = emptyList(), - val warnings: List = emptyList() + val errors: List = emptyList(), + val warnings: List = emptyList() ) { val hasErrors = errors.isNotEmpty() val hasWarnings = warnings.isNotEmpty() val successRate = if(totalItems == 0) .0 else successfulItems.toDouble() / totalItems - val errorMessages = errors.map(ValidationError::message) - val warningMessages = warnings.map(ValidationError::message) + val errorMessages = errors.map(IValidationError::message) + val warningMessages = warnings.map(IValidationError::message) } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/FieldValidationBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/FieldValidationBuilder.kt deleted file mode 100644 index 35b6e42..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/FieldValidationBuilder.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.ender_development.catalyx.core.utils.validation - -@Suppress("UNUSED") -class FieldValidationBuilder(value: V?, private val fieldName: String, private val parentBuilder: ValidationBuilder<*>) { - private var currentValue: V? = value - - fun validate(validator: IValidator): FieldValidationBuilder { - if (currentValue != null && !validator.validate(currentValue)) { - parentBuilder.addError(fieldName, "Validation failed for field '$fieldName'") - currentValue = null - } else if (currentValue == null && !validator.validate(null)) - parentBuilder.addError(fieldName, "Field '$fieldName' is required") - return this - } - - fun withMessage(message: String): FieldValidationBuilder { - // Remove the last error and replace with custom message - parentBuilder.getErrors().lastOrNull()?.let { - if(it.field == fieldName) { - parentBuilder.errors.removeLast() - parentBuilder.addError(fieldName, message) - } - } - return this - } - - fun orElse(defaultValue: V): V = - currentValue ?: defaultValue - - fun get(): V? = - currentValue -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/IValidator.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/IValidator.kt deleted file mode 100644 index 769dc6d..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/IValidator.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.ender_development.catalyx.core.utils.validation - -fun interface IValidator { - fun validate(value: T): Boolean -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationError.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationError.kt deleted file mode 100644 index 62e662e..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationError.kt +++ /dev/null @@ -1,26 +0,0 @@ -package org.ender_development.catalyx.core.utils.validation - -import org.apache.logging.log4j.Level -import org.apache.logging.log4j.Logger -import org.ender_development.catalyx.Catalyx - -@Suppress("UNUSED") -data class ValidationError(val field: String? = null, val message: String, val code: String? = null, val severity: Severity = Severity.ERROR) { - enum class Severity(val loggerLevel: Level) { - WARNING(Level.WARN), - ERROR(Level.ERROR), - CRITICAL(Level.FATAL) - } - - override fun toString(): String { - val prefix = when(severity) { - Severity.WARNING -> "⚠️" - Severity.ERROR -> "❌" - Severity.CRITICAL -> "🚨" - } - return field?.let { "$prefix [$field]: $message" } ?: "$prefix: $message" - } - - fun log(logger: Logger = Catalyx.LOGGER) = - logger.log(severity.loggerLevel, toString()) -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationResult.kt b/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationResult.kt deleted file mode 100644 index 42bbba5..0000000 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationResult.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.ender_development.catalyx.core.utils.validation - -@Suppress("UNUSED") -class ValidationResult private constructor( - val data: T?, - val errors: List -) { - val success: Boolean = errors.isEmpty() - val failure: Boolean = !success - val errorMessages: List = errors.map(ValidationError::message) - - companion object { - fun success(data: T): ValidationResult = - ValidationResult(data, emptyList()) - - fun failure(errors: List): ValidationResult = - ValidationResult(null, errors) - } -} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/validation/FieldValidationBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/core/validation/FieldValidationBuilder.kt new file mode 100644 index 0000000..e038d54 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/validation/FieldValidationBuilder.kt @@ -0,0 +1,34 @@ +package org.ender_development.catalyx.core.validation + +import org.ender_development.catalyx.api.v1.validation.interfaces.IFieldValidationBuilder +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidator + +class FieldValidationBuilder(value: V?, private val fieldName: String, private val parentBuilder: ValidationBuilder<*>) : IFieldValidationBuilder { + private var currentValue: V? = value + + override fun validate(validator: IValidator): FieldValidationBuilder { + if(currentValue != null && !validator.validate(currentValue)) { + parentBuilder.addError(fieldName, "Validation failed for field '$fieldName'") + currentValue = null + } else if(currentValue == null && !validator.validate(null)) + parentBuilder.addError(fieldName, "Field '$fieldName' is required") + return this + } + + override fun withMessage(message: String): FieldValidationBuilder { + // Remove the last error and replace with custom message + parentBuilder.errors.lastOrNull()?.let { + if(it.field == fieldName) { + parentBuilder.mutableErrors.removeLast() + parentBuilder.addError(fieldName, message) + } + } + return this + } + + override fun orElse(defaultValue: V): V = + currentValue ?: defaultValue + + override fun get(): V? = + currentValue +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationBuilder.kt b/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationBuilder.kt similarity index 57% rename from src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationBuilder.kt rename to src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationBuilder.kt index 0c00e79..ecdc48c 100644 --- a/src/main/kotlin/org/ender_development/catalyx/core/utils/validation/ValidationBuilder.kt +++ b/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationBuilder.kt @@ -1,10 +1,17 @@ -package org.ender_development.catalyx.core.utils.validation +package org.ender_development.catalyx.core.validation + +import org.ender_development.catalyx.api.v1.common.Severity +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationBuilder +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidator @Suppress("UNUSED") -class ValidationBuilder { - internal val errors = mutableListOf() +class ValidationBuilder : IValidationBuilder { + val errors: List + field = mutableListOf() private var target: T? = null + internal val mutableErrors: MutableList = errors + fun field(value: V?, fieldName: String, vararg validators: IValidator): FieldValidationBuilder = FieldValidationBuilder(value, fieldName, this).apply { validators.forEach(::validate) @@ -23,36 +30,32 @@ class ValidationBuilder { else -> value } - fun rule(condition: Boolean, message: String, severity: ValidationError.Severity = ValidationError.Severity.ERROR) { - if (!condition) + fun rule(condition: Boolean, message: String, severity: Severity = Severity.ERROR) { + if(!condition) errors.add(ValidationError(null, message, null, severity)) } - fun addError(field: String? = null, message: String, code: String? = null, severity: ValidationError.Severity = ValidationError.Severity.ERROR) = + fun addError(field: String? = null, message: String, code: String? = null, severity: Severity = Severity.ERROR) = errors.add(ValidationError(field, message, code, severity)) fun addWarning(field: String? = null, message: String, code: String? = null) = - addError(field, message, code, ValidationError.Severity.WARNING) + addError(field, message, code, Severity.WARNING) - @Suppress("UNCHECKED_CAST") fun build(data: T?): ValidationResult { - val onlyWarnings = errors.none { it.severity != ValidationError.Severity.WARNING } + val onlyWarnings = !errors.any { it.severity != Severity.WARNING } - return if (onlyWarnings && data != null) + return if(onlyWarnings && data != null) ValidationResult.success(data) else { - if (data == null && errors.isEmpty()) + if(data == null && errors.isEmpty()) errors.add(ValidationError(message = "Data construction failed")) ValidationResult.failure(errors) - } as ValidationResult + } } fun hasErrors(): Boolean = - errors.any { it.severity != ValidationError.Severity.WARNING } + errors.any { it.severity != Severity.WARNING } fun hasWarnings(): Boolean = - errors.any { it.severity == ValidationError.Severity.WARNING } - - fun getErrors(): List = - errors + errors.any { it.severity == Severity.WARNING } } diff --git a/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationError.kt b/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationError.kt new file mode 100644 index 0000000..36bc3b5 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationError.kt @@ -0,0 +1,23 @@ +package org.ender_development.catalyx.core.validation + +import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.Severity +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError + +data class ValidationError( + override val field: String? = null, + override val message: String, + override val code: String? = null, + override val severity: Severity = Severity.ERROR +) : IValidationError { + override fun toString() = buildString { + append(severity.emoji) + if(field != null) + append(" [$field]") + append(": $message") + } + + @Suppress("NOTHING_TO_INLINE") + internal inline fun log() = + log(Catalyx.LOGGER) +} diff --git a/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationResult.kt b/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationResult.kt new file mode 100644 index 0000000..a639a3d --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/core/validation/ValidationResult.kt @@ -0,0 +1,18 @@ +package org.ender_development.catalyx.core.validation + +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationError +import org.ender_development.catalyx.api.v1.validation.interfaces.IValidationResult + +class ValidationResult private constructor(override val data: T?, override val errors: List) : IValidationResult { + override val success = errors.isEmpty() + override val failure = !success + override val errorMessages = errors.map(IValidationError::message) + + companion object { + fun success(data: T) = + ValidationResult(data, emptyList()) + + fun failure(errors: List) = + ValidationResult(null, errors) + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxCoreModule.kt b/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxCoreModule.kt index 443adf2..11cf8e3 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxCoreModule.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxCoreModule.kt @@ -1,17 +1,19 @@ package org.ender_development.catalyx.modules import net.minecraftforge.client.event.RenderWorldLastEvent +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent import net.minecraftforge.fml.common.event.FMLServerStoppedEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule +import org.ender_development.catalyx.api.v1.modules.interfaces.ICatalyxModule import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.client.AreaHighlighter -import org.ender_development.catalyx.core.module.CatalyxModule -import org.ender_development.catalyx.core.module.ICatalyxModule -import org.ender_development.catalyx.core.utils.extensions.subLogger +import org.ender_development.catalyx.core.network.PacketHandler import org.ender_development.catalyx.core.utils.persistence.WorldPersistentData @CatalyxModule( @@ -26,6 +28,10 @@ internal class CatalyxCoreModule : ICatalyxModule { override val eventBusSubscribers = listOf(this) + override fun preInit(event: FMLPreInitializationEvent) { + PacketHandler.init() + } + override fun serverAboutToStart(event: FMLServerAboutToStartEvent) = WorldPersistentData.instances.forEach(WorldPersistentData::worldJoined) diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxInternalModuleContainer.kt b/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxInternalModuleContainer.kt index 0fd9ff7..f3ba436 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxInternalModuleContainer.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxInternalModuleContainer.kt @@ -1,16 +1,16 @@ package org.ender_development.catalyx.modules +import org.ender_development.catalyx.api.v1.common.Mods +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModuleContainer import org.ender_development.catalyx.core.Reference -import org.ender_development.catalyx.core.module.CatalyxModuleContainer -import org.ender_development.catalyx.core.utils.Mods /** - * Module Container for all internal Catalyx modules + * Module Container for all modules inside Catalyx */ @CatalyxModuleContainer(Reference.MODID, Reference.MODID) object CatalyxInternalModuleContainer { const val MODULE_CORE = "core" - const val MODULE_INTERNAL = "internal" + const val MODULE_COMMON = "common" const val MODULE_TEST = "test" const val MODULE_INTEGRATION = "integration" diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxModuleBase.kt b/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxModuleBase.kt index d20ac04..69fc0ab 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxModuleBase.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/CatalyxModuleBase.kt @@ -2,7 +2,7 @@ package org.ender_development.catalyx.modules import org.apache.logging.log4j.Logger import org.ender_development.catalyx.Catalyx -import org.ender_development.catalyx.core.module.ICatalyxModule +import org.ender_development.catalyx.api.v1.modules.interfaces.ICatalyxModule /** * Abstract base class for all builtin Catalyx modules diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/internal/InternalModule.kt b/src/main/kotlin/org/ender_development/catalyx/modules/common/CommonModule.kt similarity index 51% rename from src/main/kotlin/org/ender_development/catalyx/modules/internal/InternalModule.kt rename to src/main/kotlin/org/ender_development/catalyx/modules/common/CommonModule.kt index 2f39231..12af3e7 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/internal/InternalModule.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/common/CommonModule.kt @@ -1,21 +1,20 @@ -package org.ender_development.catalyx.modules.internal +package org.ender_development.catalyx.modules.common import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule +import org.ender_development.catalyx.api.v1.modules.interfaces.ICatalyxModule import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.items.CopyPasteTool -import org.ender_development.catalyx.core.module.CatalyxModule -import org.ender_development.catalyx.core.module.ICatalyxModule -import org.ender_development.catalyx.core.utils.extensions.subLogger import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer -// TODO rename, this name is silly, but couldn't come up with a better one right meow @CatalyxModule( - moduleId = CatalyxInternalModuleContainer.MODULE_INTERNAL, + moduleId = CatalyxInternalModuleContainer.MODULE_COMMON, containerId = Reference.MODID, - name = "Internal", - description = "An internal module for Catalyx, used for stuff that can can be used in all mods that use Catalyx." + name = "Common", + description = "The default module for Catalyx, used for stuff that can can be used in all mods that use Catalyx." ) -class InternalModule() : ICatalyxModule { +class CommonModule() : ICatalyxModule { override val logger = Catalyx.LOGGER.subLogger("Internal") val copyPasteTool = CopyPasteTool() diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/integration/IntegrationModule.kt b/src/main/kotlin/org/ender_development/catalyx/modules/integration/IntegrationModule.kt index 4f12e29..fbe6f8b 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/integration/IntegrationModule.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/integration/IntegrationModule.kt @@ -1,8 +1,8 @@ package org.ender_development.catalyx.modules.integration +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule import org.ender_development.catalyx.core.Reference -import org.ender_development.catalyx.core.module.CatalyxModule -import org.ender_development.catalyx.core.utils.extensions.subLogger import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer import org.ender_development.catalyx.modules.CatalyxModuleBase diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/integration/crafttweaker/CatalyxBlock.kt b/src/main/kotlin/org/ender_development/catalyx/modules/integration/crafttweaker/CatalyxBlock.kt new file mode 100644 index 0000000..15e2884 --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/modules/integration/crafttweaker/CatalyxBlock.kt @@ -0,0 +1,67 @@ +package org.ender_development.catalyx.modules.integration.crafttweaker + +import crafttweaker.annotations.ZenRegister +import crafttweaker.api.block.IMaterial +import crafttweaker.api.minecraft.CraftTweakerMC +import net.minecraft.block.Block +import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.core.Reference +import org.ender_development.catalyx.core.blocks.BaseBlock +import stanhebben.zenscript.annotations.ZenClass +import stanhebben.zenscript.annotations.ZenMethod + +@Suppress("UNUSED") +@ZenRegister +@ZenClass("${Reference.MODID}.content.Block") +class CatalyxBlock(private val block: Block) { + companion object { + private fun init(block: Block, name: String): CatalyxBlock = + CatalyxBlock(block.setRegistryName(Reference.MODID, name).setTranslationKey("tile.${Reference.MODID}:$name.name")) + + @ZenMethod + fun createBlock(name: String, material: IMaterial): CatalyxBlock = + init(BaseBlock(Catalyx, name, CraftTweakerMC.getMaterial(material)), name) + } + + @ZenMethod + fun setHardness(hardness: Float): CatalyxBlock { + block.setHardness(hardness) + return this + } + + @ZenMethod + fun setResistance(resistance: Float): CatalyxBlock { + block.setResistance(resistance) + return this + } + + @ZenMethod + fun setUnbreakable(): CatalyxBlock { + block.setBlockUnbreakable() + return this + } + + @ZenMethod + fun setLightOpacity(opacity: Int): CatalyxBlock { + block.setLightOpacity(opacity) + return this + } + + @ZenMethod + fun setLightLevel(light: Float): CatalyxBlock { + block.setLightLevel(light) + return this + } + + @ZenMethod + fun setSlipperiness(slipperiness: Float): CatalyxBlock { + block.setDefaultSlipperiness(slipperiness) + return this + } + + @ZenMethod + fun setHarvestLevel(tool: String, level: Int): CatalyxBlock { + block.setHarvestLevel(tool, level) + return this + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/integration/crafttweaker/ModuleCraftTweaker.kt b/src/main/kotlin/org/ender_development/catalyx/modules/integration/crafttweaker/ModuleCraftTweaker.kt new file mode 100644 index 0000000..70b756c --- /dev/null +++ b/src/main/kotlin/org/ender_development/catalyx/modules/integration/crafttweaker/ModuleCraftTweaker.kt @@ -0,0 +1,31 @@ +package org.ender_development.catalyx.modules.integration.crafttweaker + +import crafttweaker.CraftTweakerAPI +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent +import org.ender_development.catalyx.api.v1.common.Mods +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule +import org.ender_development.catalyx.core.Reference +import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer +import org.ender_development.catalyx.modules.integration.IntegrationModule +import kotlin.properties.Delegates + +@CatalyxModule( + moduleId = CatalyxInternalModuleContainer.MODULE_CT, + containerId = Reference.MODID, + modDependencies = [Mods.CRAFTTWEAKER], + name = "Catalyx CraftTweaker Integration Module", + description = "Adds CT bindings to content creation functions", + moduleDependencies = ["${Reference.MODID}:${CatalyxInternalModuleContainer.MODULE_INTEGRATION}"] +) +internal class ModuleCraftTweaker : IntegrationModule() { + override val logger = super.logger.subLogger("CraftTweaker") + + var scriptsSuccessful by Delegates.notNull() + + override fun preInit(event: FMLPreInitializationEvent) { + logger.info("CraftTweaker found. Loading scripts...") + CraftTweakerAPI.logInfo("${Reference.MOD_NAME} says meow :3") + scriptsSuccessful = CraftTweakerAPI.tweaker.loadScript(false, Reference.MODID); + } +} diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/integration/groovyscript/ModuleGroovyScript.kt b/src/main/kotlin/org/ender_development/catalyx/modules/integration/groovyscript/ModuleGroovyScript.kt index 6d4c309..39fa4a3 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/integration/groovyscript/ModuleGroovyScript.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/integration/groovyscript/ModuleGroovyScript.kt @@ -4,11 +4,11 @@ import com.cleanroommc.groovyscript.GroovyScript import com.cleanroommc.groovyscript.api.GroovyPlugin import com.cleanroommc.groovyscript.compat.mods.GroovyContainer import net.minecraftforge.fml.common.Optional +import org.ender_development.catalyx.api.v1.common.Mods +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule import org.ender_development.catalyx.core.Reference -import org.ender_development.catalyx.core.module.CatalyxModule import org.ender_development.catalyx.core.module.ModuleManager -import org.ender_development.catalyx.core.utils.Mods -import org.ender_development.catalyx.core.utils.extensions.subLogger import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer import org.ender_development.catalyx.modules.integration.IntegrationModule @@ -35,9 +35,11 @@ internal class ModuleGroovyScript : IntegrationModule(), GroovyPlugin { modSupportContainer = container!! } + @Optional.Method(modid = Mods.GROOVYSCRIPT) override fun getModId() = Reference.MODID + @Optional.Method(modid = Mods.GROOVYSCRIPT) override fun getContainerName() = Reference.MOD_NAME } diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/FluidTileProvider.kt b/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/FluidTileProvider.kt index 1c234d8..39642c8 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/FluidTileProvider.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/FluidTileProvider.kt @@ -5,13 +5,13 @@ import mcjty.theoneprobe.apiimpl.styles.ProgressStyle import net.minecraft.block.state.IBlockState import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.World +import org.ender_development.catalyx.api.v1.common.extensions.getRealColor import org.ender_development.catalyx.core.Reference import org.ender_development.catalyx.core.tiles.helper.IFluidTile -import org.ender_development.catalyx.core.utils.extensions.getRealColor import java.awt.Color internal class FluidTileProvider : IProbeInfoProvider { - override fun getID() = "${Reference.MODID}.auto.ifluidtile_provider" + override fun getID() = "${Reference.MODID}:auto.ifluidtile_provider" override fun addProbeInfo(mode: ProbeMode, info: IProbeInfo, player: EntityPlayer, world: World, state: IBlockState, data: IProbeHitData) { val tile = world.getTileEntity(data.pos) as? IFluidTile ?: return diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/ModuleTheOneProbe.kt b/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/ModuleTheOneProbe.kt index 5974f16..1decdd7 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/ModuleTheOneProbe.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/integration/top/ModuleTheOneProbe.kt @@ -2,10 +2,10 @@ package org.ender_development.catalyx.modules.integration.top import mcjty.theoneprobe.TheOneProbe import net.minecraftforge.fml.common.event.FMLInitializationEvent +import org.ender_development.catalyx.api.v1.common.Mods +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule import org.ender_development.catalyx.core.Reference -import org.ender_development.catalyx.core.module.CatalyxModule -import org.ender_development.catalyx.core.utils.Mods -import org.ender_development.catalyx.core.utils.extensions.subLogger import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer import org.ender_development.catalyx.modules.integration.IntegrationModule diff --git a/src/main/kotlin/org/ender_development/catalyx/modules/test/DevTestModule.kt b/src/main/kotlin/org/ender_development/catalyx/modules/test/DevTestModule.kt index 1d4f0b7..2ef534b 100644 --- a/src/main/kotlin/org/ender_development/catalyx/modules/test/DevTestModule.kt +++ b/src/main/kotlin/org/ender_development/catalyx/modules/test/DevTestModule.kt @@ -1,22 +1,32 @@ package org.ender_development.catalyx.modules.test +import net.minecraft.block.state.IBlockState import net.minecraft.client.Minecraft +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.ResourceLocation import net.minecraft.util.text.TextComponentString +import net.minecraft.world.World import net.minecraftforge.client.event.ClientChatEvent +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import org.ender_development.catalyx.Catalyx +import org.ender_development.catalyx.api.v1.common.extensions.subLogger +import org.ender_development.catalyx.api.v1.modules.annotations.CatalyxModule +import org.ender_development.catalyx.api.v1.utils.Utils import org.ender_development.catalyx.core.Reference +import org.ender_development.catalyx.core.blocks.BaseTileBlock import org.ender_development.catalyx.core.blocks.IOTileBlock import org.ender_development.catalyx.core.blocks.multiblock.CenterBlock import org.ender_development.catalyx.core.blocks.multiblock.parts.CornerBlock import org.ender_development.catalyx.core.blocks.multiblock.parts.SideBlock import org.ender_development.catalyx.core.client.AreaHighlighter -import org.ender_development.catalyx.core.module.CatalyxModule -import org.ender_development.catalyx.core.utils.SideUtils -import org.ender_development.catalyx.core.utils.extensions.subLogger +import org.ender_development.catalyx.core.tiles.BaseTile +import org.ender_development.catalyx.core.tiles.helper.ICopyPasteExtraDataTile import org.ender_development.catalyx.modules.CatalyxInternalModuleContainer import org.ender_development.catalyx.modules.CatalyxModuleBase +@Suppress("unused") @CatalyxModule( moduleId = CatalyxInternalModuleContainer.MODULE_TEST, containerId = Reference.MODID, @@ -33,10 +43,34 @@ internal class DevTestModule : CatalyxModuleBase() { val testMultiBlock = CenterBlock(Catalyx, "test_middle", DummyClass1::class.java, 1, testCorner, testSide) val testTesrBlock = IOTileBlock(Catalyx, "test_tesr", DummyClass2::class.java, 0) + // yes, this needs to be in preInit, otherwise a crash happens because CapabilityEnergy.ENERGY is still null lmao + override fun preInit(event: FMLPreInitializationEvent) { + class TestCopyPasteTile() : BaseTile(Catalyx), ICopyPasteExtraDataTile { + override fun copyData(tag: NBTTagCompound) { + repeat(10) { + tag.setInteger("Copy$it", it + Catalyx.RANDOM.nextInt(100, 1000)) + } + } + + override fun pasteData(tag: NBTTagCompound, player: EntityPlayer) { + logger.info("Received:") + logger.info(tag.toString()) + } + } + + val testCopyPasteBlock = object : BaseTileBlock(Catalyx, "test_copy_paste", TestCopyPasteTile::class.java, -1) { + override val textureLocation = ResourceLocation(Reference.MODID, "logo") + override val modelLocation = ResourceLocation("minecraft", "block/cobblestone") + + override fun createTileEntity(world: World, state: IBlockState) = + TestCopyPasteTile() + } + } + override fun load() = logger.info("Detected deobfuscated environment, adding some testing features") - override val eventBusSubscribers = if(SideUtils.isClient) listOf(TestEventHandler()) else emptyList() + override val eventBusSubscribers = if(Utils.environment.isClient) listOf(TestEventHandler()) else emptyList() class TestEventHandler { val areaHighlighter = AreaHighlighter() diff --git a/src/main/resources/assets/catalyx/blockstates/test_corner.json b/src/main/resources/assets/catalyx/blockstates/test_corner.json index 6708f14..0ec0110 100644 --- a/src/main/resources/assets/catalyx/blockstates/test_corner.json +++ b/src/main/resources/assets/catalyx/blockstates/test_corner.json @@ -1,15 +1,9 @@ { "forge_marker": 1, "defaults": { - "model": "catalyx:layered_cube_merged", + "model": "minecraft:cube_all", "textures": { - "particle": "catalyx:blocks/mb_inner", - "down": "", - "up": "", - "north": "", - "east": "", - "south": "", - "west": "" + "all": "catalyx:blocks/mb_inner" } }, "variants": { @@ -23,7 +17,7 @@ }, "position": { "0": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down_right_lower", "up": "catalyx:blocks/mb_top_right_upper", @@ -34,7 +28,7 @@ } }, "1": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down_right_upper", "up": "catalyx:blocks/mb_top_right_lower", @@ -45,7 +39,7 @@ } }, "2": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down_left_upper", "up": "catalyx:blocks/mb_top_left_lower", @@ -56,7 +50,7 @@ } }, "3": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down_left_lower", "up": "catalyx:blocks/mb_top_left_upper", diff --git a/src/main/resources/assets/catalyx/blockstates/test_middle.json b/src/main/resources/assets/catalyx/blockstates/test_middle.json index 602736f..352946d 100644 --- a/src/main/resources/assets/catalyx/blockstates/test_middle.json +++ b/src/main/resources/assets/catalyx/blockstates/test_middle.json @@ -1,10 +1,9 @@ { "forge_marker": 1, "defaults": { - "model": "catalyx:layered_cube_all", + "model": "minecraft:cube_all", "textures": { - "bot_all": "catalyx:blocks/mb_inner", - "top_all": "catalyx:blocks/mb_inner" + "all": "catalyx:blocks/mb_inner" } }, "variants": { diff --git a/src/main/resources/assets/catalyx/blockstates/test_side.json b/src/main/resources/assets/catalyx/blockstates/test_side.json index da46e69..e8fa47e 100644 --- a/src/main/resources/assets/catalyx/blockstates/test_side.json +++ b/src/main/resources/assets/catalyx/blockstates/test_side.json @@ -1,15 +1,9 @@ { "forge_marker": 1, "defaults": { - "model": "catalyx:layered_cube_merged", + "model": "minecraft:cube_all", "textures": { - "particle": "catalyx:blocks/mb_inner", - "down": "", - "up": "", - "north": "", - "east": "", - "south": "", - "west": "" + "all": "catalyx:blocks/mb_inner" } }, "variants": { @@ -23,7 +17,7 @@ }, "position": { "0": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down3", "up": "catalyx:blocks/mb_top1", @@ -34,7 +28,7 @@ } }, "1": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down2", "up": "catalyx:blocks/mb_top2", @@ -45,7 +39,7 @@ } }, "2": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down1", "up": "catalyx:blocks/mb_top3", @@ -56,7 +50,7 @@ } }, "3": { - "model": "catalyx:layered_cube_merged", + "model": "catalyx:cat_cube", "textures": { "down": "catalyx:blocks/mb_down4", "up": "catalyx:blocks/mb_top4", diff --git a/src/main/resources/assets/catalyx/blockstates/test_tesr.json b/src/main/resources/assets/catalyx/blockstates/test_tesr.json index 2d109f3..2d76299 100644 --- a/src/main/resources/assets/catalyx/blockstates/test_tesr.json +++ b/src/main/resources/assets/catalyx/blockstates/test_tesr.json @@ -1,10 +1,9 @@ { "forge_marker": 1, "defaults": { - "model": "catalyx:layered_cube_all", + "model": "minecraft:cube_all", "textures": { - "bot_all": "catalyx:blocks/mb_inner", - "top_all": "catalyx:blocks/mb_inner" + "all": "catalyx:blocks/mb_inner" } }, "variants": { diff --git a/src/main/resources/assets/catalyx/lang/en_us.lang b/src/main/resources/assets/catalyx/lang/en_us.lang index 1c02300..6228a03 100644 --- a/src/main/resources/assets/catalyx/lang/en_us.lang +++ b/src/main/resources/assets/catalyx/lang/en_us.lang @@ -1,3 +1,9 @@ +item.catalyx:copy_paste_tool.name=Copy-Paste Tool +item.catalyx:copy_paste_tool.desc.1=Allows you to copy-paste settings and other data between supported blocks +item.catalyx:copy_paste_tool.desc.2=Shift+right-click to copy, right-click to paste +item.catalyx:copy_paste_tool.desc.copying=Copying data from %s - shift to see data +item.catalyx:copy_paste_tool.desc.empty=Not copying any data + tooltip.catalyx:running=Click to pause tooltip.catalyx:paused=Click to resume tooltip.catalyx:redstone_high=Works with a redstone signal diff --git a/src/main/resources/assets/catalyx/models/block/cat_cube.json b/src/main/resources/assets/catalyx/models/block/cat_cube.json new file mode 100644 index 0000000..40d386d --- /dev/null +++ b/src/main/resources/assets/catalyx/models/block/cat_cube.json @@ -0,0 +1,12 @@ +{ + "parent": "block/cube", + "textures": { + "particle": "#up", + "down": "#down", + "up": "#up", + "north": "#north", + "east": "#east", + "south": "#south", + "west": "#west" + } +} diff --git a/src/main/resources/assets/catalyx/models/block/layered_cube_all.json b/src/main/resources/assets/catalyx/models/block/layered_cube_all.json deleted file mode 100644 index cc87f95..0000000 --- a/src/main/resources/assets/catalyx/models/block/layered_cube_all.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "parent": "catalyx:block/layered_cube_base", - "textures": { - "particle": "#bot_all", - "bot_down": "#bot_all", - "bot_up": "#bot_all", - "bot_north": "#bot_all", - "bot_east": "#bot_all", - "bot_south": "#bot_all", - "bot_west": "#bot_all", - "top_down": "#top_all", - "top_up": "#top_all", - "top_north": "#top_all", - "top_east": "#top_all", - "top_south": "#top_all", - "top_west": "#top_all" - } -} diff --git a/src/main/resources/assets/catalyx/models/block/layered_cube_base.json b/src/main/resources/assets/catalyx/models/block/layered_cube_base.json deleted file mode 100644 index d8b8f0a..0000000 --- a/src/main/resources/assets/catalyx/models/block/layered_cube_base.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "parent": "minecraft:block/cube", - "elements": [ - { - "from": [ 0, 0, 0 ], - "to": [ 16, 16, 16 ], - "faces": { - "down": { "texture": "#bot_down", "cullface": "down" }, - "up": { "texture": "#bot_up", "cullface": "up" }, - "north": { "texture": "#bot_north", "cullface": "north" }, - "south": { "texture": "#bot_south", "cullface": "south" }, - "west": { "texture": "#bot_west", "cullface": "west" }, - "east": { "texture": "#bot_east", "cullface": "east" } - } - }, - { - "from": [ 0, 0, 0 ], - "to": [ 16, 16, 16 ], - "shade": false, - "faces": { - "down": { "texture": "#top_down", "cullface": "down" }, - "up": { "texture": "#top_up", "cullface": "up" }, - "north": { "texture": "#top_north", "cullface": "north" }, - "south": { "texture": "#top_south", "cullface": "south" }, - "west": { "texture": "#top_west", "cullface": "west" }, - "east": { "texture": "#top_east", "cullface": "east" } - } - } - ] -} diff --git a/src/main/resources/assets/catalyx/models/block/layered_cube_merged.json b/src/main/resources/assets/catalyx/models/block/layered_cube_merged.json deleted file mode 100644 index 7449806..0000000 --- a/src/main/resources/assets/catalyx/models/block/layered_cube_merged.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "parent": "catalyx:block/layered_cube_base", - "textures": { - "particle": "#particle", - "bot_down": "#down", - "bot_up": "#up", - "bot_north": "#north", - "bot_east": "#east", - "bot_south": "#south", - "bot_west": "#west", - "top_down": "#down", - "top_up": "#up", - "top_north": "#north", - "top_east": "#east", - "top_south": "#south", - "top_west": "#west" - } -} diff --git a/src/main/resources/assets/catalyx/models/block/layered_orientable.json b/src/main/resources/assets/catalyx/models/block/layered_orientable.json deleted file mode 100644 index e27d305..0000000 --- a/src/main/resources/assets/catalyx/models/block/layered_orientable.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "parent": "catalyx:block/layered_cube_base", - "display": { - "firstperson_righthand": { - "rotation": [ 0, 135, 0 ], - "translation": [ 0, 0, 0 ], - "scale": [ 0.40, 0.40, 0.40 ] - } - }, - "textures": { - "particle": "#bot_front", - "bot_down": "#top_all", - "bot_up": "#top_all", - "bot_north": "#bot_front", - "bot_east": "#side_all", - "bot_south": "#side_all", - "bot_west": "#side_all", - "top_down": "#top_all", - "top_up": "#top_all", - "top_north": "#top_front", - "top_east": "#side_all", - "top_south": "#side_all", - "top_west": "#side_all" - } -} diff --git a/src/main/resources/assets/catalyx/models/item/copy_paste_tool.json b/src/main/resources/assets/catalyx/models/item/copy_paste_tool.json deleted file mode 100644 index 0f3bd15..0000000 --- a/src/main/resources/assets/catalyx/models/item/copy_paste_tool.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "catalyx:logo" - } -} diff --git a/src/main/resources/assets/catalyx/models/item/test_middle.json b/src/main/resources/assets/catalyx/models/item/test_middle.json new file mode 100644 index 0000000..6e8e19e --- /dev/null +++ b/src/main/resources/assets/catalyx/models/item/test_middle.json @@ -0,0 +1,3 @@ +{ + "parent": "block/cobblestone" +}