diff --git a/build.gradle b/build.gradle index 4a3bb03c..53d4e1be 100644 --- a/build.gradle +++ b/build.gradle @@ -1,41 +1,38 @@ +//file:noinspection GroovyAssignabilityCheck + buildscript { - ext.kotlin_version = '1.6.10' - repositories { - // These repositories are only for Gradle plugins, put any other repositories in the repository block further below - maven { url = 'https://maven.minecraftforge.net' } - maven { url = 'https://maven.parchmentmc.org' } - gradlePluginPortal() - mavenCentral() - } dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true - classpath 'org.parchmentmc:librarian:1.+' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - classpath "gradle.plugin.com.github.johnrengelman:shadow:7.1.1" + classpath 'org.spongepowered:mixingradle:0.7.+' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0" } } -apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'org.parchmentmc.librarian.forgegradle' -apply plugin: 'kotlin' -apply plugin: 'kotlinx-serialization' -apply plugin: "com.github.johnrengelman.shadow" -apply from: 'https://raw.githubusercontent.com/thedarkcolour/KotlinForForge/site/thedarkcolour/kotlinforforge/gradle/kff-3.3.2.gradle' -apply plugin: 'eclipse' -apply plugin: 'maven-publish' - +plugins { + id 'net.minecraftforge.gradle' version '5.1.+' + id 'org.jetbrains.kotlin.jvm' version '1.8.0' + id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' + id 'org.parchmentmc.librarian.forgegradle' version '1.+' + id 'com.github.johnrengelman.shadow' version '7.1.2' +} -version = '1.0.1' +version = '2.0.0' group = 'org.eln2.mc' archivesBaseName = 'eln2' -// Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) +tasks.build.dependsOn kotlinSourcesJar +tasks.build.dependsOn shadowJar + +println( + 'Grissess Status - Java: ' + System.getProperty('java.version') + + ' JVM: ' + System.getProperty('java.vm.version') + + '(' + System.getProperty('java.vendor') + ') ' + + 'Arch: ' + System.getProperty('os.arch') +) + minecraft { - mappings channel: 'parchment', version: "2022.05.22-1.18.2" + mappings channel: 'parchment', version: '2023.03.12-1.19.3' accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') @@ -43,12 +40,10 @@ minecraft { client { workingDirectory project.file('run') - // The markers can be added/remove as needed separated by commas. - // "SCAN": For mods scan. - // "REGISTRIES": For firing of registry events. - // "REGISTRYDUMP": For getting the contents of all registries. property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" mods { eln2 { @@ -59,6 +54,7 @@ minecraft { server { workingDirectory project.file('run') + property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' @@ -71,9 +67,10 @@ minecraft { data { workingDirectory project.file('run') + property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' - // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + args '--mod', 'eln2', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') mods { @@ -90,44 +87,85 @@ configurations { implementation.extendsFrom library } -minecraft.runs.all { - lazyToken('minecraft_classpath') { - configurations.library.copyRecursive().resolve().collect { it.absolutePath }.join(File.pathSeparator) +reobf { + shadowJar { + // empty } } +test { + useJUnitPlatform() +} + // Include resources generated by data generators. -sourceSets.main.resources { srcDir 'src/generated/resources' } +sourceSets.main.resources { + srcDir 'src/generated/resources' +} repositories { mavenCentral() - maven { url 'https://jitpack.io' } - maven { url "https://maven.bai.lol" } - // Put repositories for dependencies here - // ForgeGradle automatically adds the Forge maven and Maven Central for you - - // If you have mod jar dependencies in ./libs, you can declare them as a repository like so: - // flatDir { - // dir 'libs' - // } + maven { + name 'JitPack' + url 'https://jitpack.io' + } + maven { + name 'tterrag maven' + url 'https://maven.tterrag.com/' + } + maven { + name = 'Kotlin for Forge' + url = 'https://thedarkcolour.github.io/KotlinForForge/' + content { + includeGroup 'thedarkcolour' + } + } + maven { + url = 'https://maven2.bai.lol' + content { + includeGroup 'lol.bai' + includeGroup 'mcp.mobius.waila' + } + } } dependencies { - minecraft 'net.minecraftforge:forge:1.18.2-40.1.25' - compileOnly fg.deobf("mcp.mobius.waila:wthit-api:forge-4.7.2") - runtimeOnly fg.deobf("mcp.mobius.waila:wthit:forge-4.7.2") - library('com.github.age-series:libage:main-SNAPSHOT') - library("org.apache.commons:commons-math3:3.6.1") - library("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") - library('com.charleskorn.kaml:kaml:0.40.0') - - // Real mod deobf dependency examples - these get remapped to your current mappings - // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency - // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency - // implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency - - // Examples using mod jars from ./libs - // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") + minecraft 'net.minecraftforge:forge:1.19.3-44.1.23' + library ("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + exclude group: 'org.jetbrains', module: 'annotations' + } + library("org.jetbrains.kotlin:kotlin-reflect:1.8.0") + library("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + + compileOnly fg.deobf('mcp.mobius.waila:wthit-api:forge-6.4.2') + runtimeOnly fg.deobf('mcp.mobius.waila:wthit:forge-6.4.2') + runtimeOnly fg.deobf('lol.bai:badpackets:forge-0.3.4') + implementation fg.deobf('com.jozufozu.flywheel:flywheel-forge-1.19.3:0.6.8.a-1') + + library 'com.github.age-series:LibAge:8ed5950a0d' + library 'org.apache.commons:commons-math3:3.6.1' + library('com.charleskorn.kaml:kaml:0.50.0') + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +shadowJar { + archiveClassifier.set("") + configurations = [project.configurations.library] + + def rlTarget = "${project.group}.relocated" + + relocate 'kotlin', "${rlTarget}.kotlin" + relocate 'com.charleskorn', "${rlTarget}.charleskorn" + relocate 'org.snakeyaml', "${rlTarget}.snakeyaml" + relocate 'org.apache.commons', "${rlTarget}.apache.commons" + relocate 'org.ageseries', "${rlTarget}.ageseries" + relocate 'org.intellij', "${rlTarget}.intellij" + relocate 'jetbrains', "${rlTarget}.jetbrains" + + afterEvaluate { + finalizedBy reobfShadowJar + } } jar { @@ -135,63 +173,44 @@ jar { archiveClassifier = 'slim' manifest { attributes([ - "Specification-Title" : "eln2", - "Specification-Vendor" : "age-series-team", - "Specification-Version" : "1", - "Implementation-Title" : project.name, - "Implementation-Version" : project.jar.archiveVersion, - "Implementation-Vendor" : "age-series-team", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + "Specification-Title" : 'eln2', + "Specification-Vendor" : 'age-series-team', + "Specification-Version" : '2', + "Implementation-Title" : project.name, + "Implementation-Version" : project.jar.archiveVersion, + "Implementation-Vendor" : 'age-series-team', + "Implementation-Timestamp": new Date().format('yyyy-MM-dd\'T\'HH:mm:ssZ') ]) } } -// Do shadow relocations -// (I can't figure out how to do this in an automatic, sensible way, so--for -// now--you will have to hunt down these dependencies manually and iteratively. -// Let ./gradlew dependencies be your guide, and/or the printlns below. -// Sorry! - Grissess) -def shaded = [ - "com.charleskorn.kaml", - "org.snakeyaml", - "org.apache.commons", - "com.github.age-series" -].stream().collect() +final def classpathBlacklist = [ + 'annotations-23.0.0.jar' +] -shadowJar { - archiveClassifier = '' - dependencies { - exclude(dependency { - def res = !shaded.contains(it.moduleGroup) - if(!res) println("Include: $it") - else println("Exclude: $it") - res - }) - } - shaded.forEach { - relocate it, "org.ageseries.shadow." + it +minecraft.runs.configureEach { + lazyToken('minecraft_classpath') { + configurations.library.copyRecursive() + .resolve() + .stream() + .filter { + !classpathBlacklist.any { final blacklisted -> + it.path.endsWith(blacklisted) + } + } + .collect { it.absolutePath } + .join(File.pathSeparator) } - - finalizedBy 'reobfShadowJar' } -assemble.dependsOn shadowJar - reobf { - shadowJar { } + jar { classpath.from(sourceSets.main.compileClasspath) } + shadowJar {} } -// This is the preferred method to reobfuscate your jar file -jar.finalizedBy('reobfJar') -compileKotlin { - kotlinOptions { - jvmTarget = "17" - } +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' } -compileTestKotlin { - kotlinOptions { - jvmTarget = "17" - } -} -// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing -// publish.dependsOn('reobfJar') + +jar.finalizedBy('reobfJar') + diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index f95c9228..00000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -See https://eln2.org/contributing diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS deleted file mode 100644 index b19ba5bc..00000000 --- a/docs/CONTRIBUTORS +++ /dev/null @@ -1,5 +0,0 @@ -jrddunbr: Project Lead, various tasks, various parsers -Grissess: MNA, Falstad importer -Baughn: Gradle, testing suites, GitHub Actions, Minecraft integration, Google Protocol Buffers -Caeleron: MNA theory work, Node, Code cleanup -Alan F: Ore generation code, block and item registration diff --git a/docs/forge-license.txt b/docs/forge-license.txt deleted file mode 100644 index b0cbe2b3..00000000 --- a/docs/forge-license.txt +++ /dev/null @@ -1,520 +0,0 @@ -Unless noted below, Minecraft Forge, Forge Mod Loader, and all -parts herein are licensed under the terms of the LGPL 2.1 found -here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and -copied below. - -Homepage: http://minecraftforge.net/ - https://github.com/MinecraftForge/MinecraftForge - - -A note on authorship: -All source artifacts are property of their original author, with -the exclusion of the contents of the patches directory and others -copied from it from time to time. Authorship of the contents of -the patches directory is retained by the Minecraft Forge project. -This is because the patches are partially machine generated -artifacts, and are changed heavily due to the way forge works. -Individual attribution within them is impossible. - -Consent: -All contributions to Forge must consent to the release of any -patch content to the Forge project. - -A note on infectivity: -The LGPL is chosen specifically so that projects may depend on Forge -features without being infected with its license. That is the -purpose of the LGPL. Mods and others using this code via ordinary -Java mechanics for referencing libraries are specifically not bound -by Forge's license for the Mod code. - - -=== MCP Data === -This software includes data from the Minecraft Coder Pack (MCP), with kind permission -from them. The license to MCP data is not transitive - distribution of this data by -third parties requires independent licensing from the MCP team. This data is not -redistributable without permission from the MCP team. - -=== Sharing === -I grant permission for some parts of FML to be redistributed outside the terms of the LGPL, for the benefit of -the minecraft modding community. All contributions to these parts should be licensed under the same additional grant. - --- Runtime patcher -- -License is granted to redistribute the runtime patcher code (src/main/java/net/minecraftforge/fml/common/patcher -and subdirectories) under any alternative open source license as classified by the OSI (http://opensource.org/licenses) - --- ASM transformers -- -License is granted to redistribute the ASM transformer code (src/main/java/net/minecraftforge/common/asm/ and subdirectories) -under any alternative open source license as classified by the OSI (http://opensource.org/licenses) - -========================================================================= -This software includes portions from the Apache Maven project at -http://maven.apache.org/ specifically the ComparableVersion.java code. It is -included based on guidelines at -http://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html -with notices intact. The only change is a non-functional change of package name. - -This software contains a partial repackaging of javaxdelta, a BSD licensed program for generating -binary differences and applying them, sourced from the subversion at http://sourceforge.net/projects/javaxdelta/ -authored by genman, heikok, pivot. -The only changes are to replace some Trove collection types with standard Java collections, and repackaged. -========================================================================= - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/gradle.properties b/gradle.properties index 878bf1f7..04406333 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,3 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. +kotlin.code.style=official org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +org.gradle.daemon=false diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a..249e5832 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb879..ae04661e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c7873..a69d9cb6 100755 --- a/gradlew +++ b/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32..f127cfd4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/nix/sources.json b/nix/sources.json deleted file mode 100644 index d3a80c4c..00000000 --- a/nix/sources.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "niv": { - "branch": "master", - "description": "Easy dependency management for Nix projects", - "homepage": "https://github.com/nmattia/niv", - "owner": "nmattia", - "repo": "niv", - "rev": "febd3530f0c2f2fb74752ee4d9dd2518d302f618", - "sha256": "1gifi50k4h6wk9ix0yvp66p7jk8rrqgr39r5rf4lyha6pbs7dbk6", - "type": "tarball", - "url": "https://github.com/nmattia/niv/archive/febd3530f0c2f2fb74752ee4d9dd2518d302f618.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, - "nixpkgs": { - "branch": "nixos-20.03", - "description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to", - "homepage": "https://github.com/NixOS/nixpkgs", - "owner": "NixOS", - "repo": "nixpkgs-channels", - "rev": "e69cfc351befceecff01b21cea8eaa3cb3dd620a", - "sha256": "0i1djkh79yqzxzikvkayfghj0a2dzy2ycl0n3px4d6hixr53lhj6", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs-channels/archive/e69cfc351befceecff01b21cea8eaa3cb3dd620a.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - } -} diff --git a/nix/sources.nix b/nix/sources.nix deleted file mode 100644 index 8a725cb4..00000000 --- a/nix/sources.nix +++ /dev/null @@ -1,134 +0,0 @@ -# This file has been generated by Niv. - -let - - # - # The fetchers. fetch_ fetches specs of type . - # - - fetch_file = pkgs: spec: - if spec.builtin or true then - builtins_fetchurl { inherit (spec) url sha256; } - else - pkgs.fetchurl { inherit (spec) url sha256; }; - - fetch_tarball = pkgs: spec: - if spec.builtin or true then - builtins_fetchTarball { inherit (spec) url sha256; } - else - pkgs.fetchzip { inherit (spec) url sha256; }; - - fetch_git = spec: - builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; }; - - fetch_builtin-tarball = spec: - builtins.trace - '' - WARNING: - The niv type "builtin-tarball" will soon be deprecated. You should - instead use `builtin = true`. - - $ niv modify -a type=tarball -a builtin=true - '' - builtins_fetchTarball { inherit (spec) url sha256; }; - - fetch_builtin-url = spec: - builtins.trace - '' - WARNING: - The niv type "builtin-url" will soon be deprecated. You should - instead use `builtin = true`. - - $ niv modify -a type=file -a builtin=true - '' - (builtins_fetchurl { inherit (spec) url sha256; }); - - # - # Various helpers - # - - # The set of packages used when specs are fetched using non-builtins. - mkPkgs = sources: - let - sourcesNixpkgs = - import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {}; - hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; - hasThisAsNixpkgsPath = == ./.; - in - if builtins.hasAttr "nixpkgs" sources - then sourcesNixpkgs - else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then - import {} - else - abort - '' - Please specify either (through -I or NIX_PATH=nixpkgs=...) or - add a package called "nixpkgs" to your sources.json. - ''; - - # The actual fetching function. - fetch = pkgs: name: spec: - - if ! builtins.hasAttr "type" spec then - abort "ERROR: niv spec ${name} does not have a 'type' attribute" - else if spec.type == "file" then fetch_file pkgs spec - else if spec.type == "tarball" then fetch_tarball pkgs spec - else if spec.type == "git" then fetch_git spec - else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec - else if spec.type == "builtin-url" then fetch_builtin-url spec - else - abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; - - # Ports of functions for older nix versions - - # a Nix version of mapAttrs if the built-in doesn't exist - mapAttrs = builtins.mapAttrs or ( - f: set: with builtins; - listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) - ); - - # fetchTarball version that is compatible between all the versions of Nix - builtins_fetchTarball = { url, sha256 }@attrs: - let - inherit (builtins) lessThan nixVersion fetchTarball; - in - if lessThan nixVersion "1.12" then - fetchTarball { inherit url; } - else - fetchTarball attrs; - - # fetchurl version that is compatible between all the versions of Nix - builtins_fetchurl = { url, sha256 }@attrs: - let - inherit (builtins) lessThan nixVersion fetchurl; - in - if lessThan nixVersion "1.12" then - fetchurl { inherit url; } - else - fetchurl attrs; - - # Create the final "sources" from the config - mkSources = config: - mapAttrs ( - name: spec: - if builtins.hasAttr "outPath" spec - then abort - "The values in sources.json should not have an 'outPath' attribute" - else - spec // { outPath = fetch config.pkgs name spec; } - ) config.sources; - - # The "config" used by the fetchers - mkConfig = - { sourcesFile ? ./sources.json - , sources ? builtins.fromJSON (builtins.readFile sourcesFile) - , pkgs ? mkPkgs sources - }: rec { - # The sources, i.e. the attribute set of spec name to spec - inherit sources; - - # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers - inherit pkgs; - }; -in -mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..acd154d0 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url = 'https://maven.minecraftforge.net/' } + maven { url = 'https://maven.parchmentmc.org' } + } +} diff --git a/shell.nix b/shell.nix deleted file mode 100644 index 193e3bdb..00000000 --- a/shell.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ sources ? import ./nix/sources.nix -, nixpkgs ? import sources.nixpkgs {} -}: - -(nixpkgs.buildFHSUserEnv { - name = "eln2-env"; - targetPkgs = pkgs: with pkgs; [ gradle_5 ]; -}).env diff --git a/src/main/java/org/eln2/mc/Eln2.kt b/src/main/java/org/eln2/mc/Eln2.kt deleted file mode 100644 index 356182f1..00000000 --- a/src/main/java/org/eln2/mc/Eln2.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.eln2.mc - -import net.minecraftforge.api.distmarker.Dist -import net.minecraftforge.fml.common.Mod -import net.minecraftforge.fml.loading.FMLEnvironment -import org.apache.logging.log4j.LogManager -import org.apache.logging.log4j.Logger -import org.eln2.mc.client.events.ClientEvents -import org.eln2.mc.common.Configuration -import org.eln2.mc.common.ElectricalAgeConfiguration -import org.eln2.mc.common.blocks.BlockRegistry -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.common.containers.ContainerRegistry -import org.eln2.mc.common.items.ItemRegistry -import org.eln2.mc.common.network.ModStatistics -import org.eln2.mc.common.network.Networking -import thedarkcolour.kotlinforforge.forge.MOD_BUS - -@Mod(Eln2.MODID) -object Eln2 { - const val MODID = "eln2" - val LOGGER: Logger = LogManager.getLogger() - val config: ElectricalAgeConfiguration - - - init { - Configuration.loadConfig() - config = Configuration.config - - BlockRegistry.setup(MOD_BUS) - ItemRegistry.setup(MOD_BUS) - ContainerRegistry.setup(MOD_BUS) - - if (Dist.CLIENT == FMLEnvironment.dist) { - MOD_BUS.register(ClientEvents) //client-side setup - } - - Networking.setup() - - // custom registries - CellRegistry.setup(MOD_BUS) - - LOGGER.info("Prepared registries.") - - if (config.enableAnalytics) { - ModStatistics.sendAnalytics() - } - } - -} diff --git a/src/main/java/org/eln2/mc/Eln2WailaPlugin.kt b/src/main/java/org/eln2/mc/Eln2WailaPlugin.kt deleted file mode 100644 index d4c5f2ba..00000000 --- a/src/main/java/org/eln2/mc/Eln2WailaPlugin.kt +++ /dev/null @@ -1,48 +0,0 @@ -package org.eln2.mc - -import mcp.mobius.waila.api.* -import mcp.mobius.waila.api.component.PairComponent -import net.minecraft.nbt.CompoundTag -import net.minecraft.network.chat.TextComponent -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.level.Level -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.extensions.NbtExtensions.getStringMap -import org.eln2.mc.extensions.NbtExtensions.setStringMap - - -@WailaPlugin(id = "${Eln2.MODID}:waila_plugin") -class Eln2WailaPlugin: IWailaPlugin { - override fun register(registrar: IRegistrar?) { - if (registrar == null) return - - val clientProvider: IBlockComponentProvider = object: IBlockComponentProvider { - override fun appendBody(tooltip: ITooltip?, accessor: IBlockAccessor?, config: IPluginConfig?) { - super.appendBody(tooltip, accessor, config) - if (tooltip == null || accessor == null || config == null) return - val bodyList = accessor.serverData.getStringMap("body") - bodyList.forEach { (k, v) -> - tooltip.addLine(PairComponent(TranslatableComponent(k), TextComponent(v))) - } - } - } - - registrar.addComponent(clientProvider, TooltipPosition.BODY, CellTileEntity::class.java) - - val serverProvider: IServerDataProvider = object: IServerDataProvider { - override fun appendServerData( - sendData: CompoundTag?, - player: ServerPlayer?, - world: Level?, - cell: CellTileEntity? - ) { - if (sendData == null || player == null || world == null || cell == null) return - sendData.setStringMap("body", cell.getHudMap().mapKeys { "waila.eln2.${it.key}" }) - } - } - - registrar.addBlockData(serverProvider, CellTileEntity::class.java) - - } -} diff --git a/src/main/java/org/eln2/mc/client/events/ClientEvents.kt b/src/main/java/org/eln2/mc/client/events/ClientEvents.kt deleted file mode 100644 index c0205af6..00000000 --- a/src/main/java/org/eln2/mc/client/events/ClientEvents.kt +++ /dev/null @@ -1,35 +0,0 @@ -package org.eln2.mc.client.events - -import net.minecraft.client.gui.screens.MenuScreens -import net.minecraftforge.eventbus.api.SubscribeEvent -import net.minecraftforge.fml.common.Mod.EventBusSubscriber -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent -import org.eln2.mc.client.screens.CapacitorCellScreen -import org.eln2.mc.client.screens.InductorCellScreen -import org.eln2.mc.client.screens.ResistorCellScreen -import org.eln2.mc.client.screens.VoltageSourceCellScreen -import org.eln2.mc.common.containers.ContainerRegistry.CAPACITOR_CELL_CONTAINER -import org.eln2.mc.common.containers.ContainerRegistry.CONTAINER_REGISTRY -import org.eln2.mc.common.containers.ContainerRegistry.INDUCTOR_CELL_CONTAINER -import org.eln2.mc.common.containers.ContainerRegistry.RESISTOR_CELL_CONTAINER -import org.eln2.mc.common.containers.ContainerRegistry.VOLTAGE_SOURCE_CELL_CONTAINER - -@EventBusSubscriber -object ClientEvents { - - /** - * Register the client-side equivalents of the GUI containers. - * This must be done on the client during FMLClientSetupEvent - * Note: This is done in a different registry than [CONTAINER_REGISTRY] - */ - @SubscribeEvent - fun clientSetup(event: FMLClientSetupEvent) { - event.enqueueWork { - MenuScreens.register(VOLTAGE_SOURCE_CELL_CONTAINER.get(), ::VoltageSourceCellScreen) - MenuScreens.register(RESISTOR_CELL_CONTAINER.get(), ::ResistorCellScreen) - MenuScreens.register(CAPACITOR_CELL_CONTAINER.get(), ::CapacitorCellScreen) - MenuScreens.register(INDUCTOR_CELL_CONTAINER.get(), ::InductorCellScreen) - } - } - -} diff --git a/src/main/java/org/eln2/mc/client/gui/PlotterScreen.kt b/src/main/java/org/eln2/mc/client/gui/PlotterScreen.kt deleted file mode 100644 index bd7f061b..00000000 --- a/src/main/java/org/eln2/mc/client/gui/PlotterScreen.kt +++ /dev/null @@ -1,264 +0,0 @@ -package org.eln2.mc.client.gui - -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.gui.screens.Screen -import net.minecraft.client.renderer.GameRenderer -import net.minecraft.client.resources.language.I18n.get -import net.minecraft.core.BlockPos -import net.minecraft.network.chat.TextComponent -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.block.Block -import org.eln2.mc.Eln2 -import org.eln2.mc.common.blocks.BlockRegistry -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.common.network.CellInfo -import org.eln2.mc.extensions.MatrixStackExtensions.rect4 -import org.eln2.mc.utility.* -import org.eln2.mc.utility.ValueText.valueText -import kotlin.math.max - -class PlotterScreen(private val cells : List, val solveTime : Long) : Screen(TextComponent("Plotter")) { - private var scale = 1.0f - private var posX = 0.0 - private var posY = 0.0 - - override fun init() { - prepareCells() - } - - private fun renderGridBackground(poseStack: PoseStack){ - fill(poseStack, 0, 0, width, height, McColor(43u, 43u, 43u).value) - - val size = (texSize * scale).toInt() - - val color = McColor(60u, 60u, 60u).value - - val cornerX = ((posX * scale) % size).toInt() - val cornerY = ((posY * scale) % size).toInt() - - for(x in cornerX - size..width step size) vLine(poseStack, x, 0, height, color) - for(y in cornerY - size..width step size) hLine(poseStack, 0, width, y, color) - } - - // the size of the cell icon textures - private val texSize = 32 - - private val cellInfoCollection = ArrayList() - - private fun prepareCells() { - val minX = cells.minOf { it.pos.x } - val minY = cells.minOf { it.pos.z } - val offX = if(minX < 0) kotlin.math.abs(minX) else -minX - val offY = if(minY < 0) kotlin.math.abs(minY) else -minY - - cells.forEach{ cellInfo -> - - val baseX = cellInfo.pos.x + offX - val baseY = cellInfo.pos.z + offY - - val x = baseX * texSize + width / 100 - val y = baseY * texSize + width / 100 - - cellInfoCollection.add(CellInfo(cellInfo.type, cellInfo.info, BlockPos(x, y, 0))) - } - - // perf: less texture switches - cellInfoCollection.sortBy { it.type } - } - - private fun blockFor(id : String) : Block { - return try { - BlockRegistry.BLOCK_REGISTRY.entries.first { - it.id.path == id.split(':')[1] - }.get() - } catch (e: Exception) { - error("Fatal error! Mismatched block ID and cell ID!") - } - } - - override fun render(pPoseStack: PoseStack, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - renderGridBackground(pPoseStack) - - pPoseStack.pushPose() - - pPoseStack.scale(scale, scale, scale) - pPoseStack.translate(posX, posY, 1.0) - - var toolTipCell : CellInfo? = null - var latestTypeTex = "" - - cellInfoCollection.forEach { - val xMin = (it.pos.x + posX) * scale - val yMin = (it.pos.y + posY) * scale - val xMax = scale * texSize.toFloat() + xMin - val yMax = scale * texSize.toFloat() + yMin - - // perf: culling - if(xMax < 0 || yMax < 0 || xMin > width || yMin > height){ - return@forEach - } - - if(it.type != latestTypeTex){ - val texLocation = when(it.type){ - CellRegistry.GROUND_CELL.id!!.toString() -> ResourceLocation(Eln2.MODID, "textures/overlay/plotter/ground.png") - CellRegistry.RESISTOR_CELL.id!!.toString() -> ResourceLocation(Eln2.MODID, "textures/overlay/plotter/resistor.png") - CellRegistry.VOLTAGE_SOURCE_CELL.id!!.toString() -> ResourceLocation(Eln2.MODID, "textures/overlay/plotter/voltage_source.png") - else -> ResourceLocation(Eln2.MODID, "textures/overlay/plotter/wire.png") - } - - latestTypeTex = it.type - - RenderSystem.setShader { GameRenderer.getPositionTexShader() } - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) - RenderSystem.setShaderTexture(0, texLocation) - } - - blit(pPoseStack, it.pos.x, it.pos.y, blitOffset, 0f, 0f, texSize, texSize, texSize, texSize) - - // check if the mouse is hovering over the cell - if(pMouseY > yMin && pMouseY < yMax && pMouseX > xMin && pMouseX < xMax) { - toolTipCell = it - } - } - - if(toolTipCell != null){ - // draw the outline of the cell - - val pos = toolTipCell!!.pos - pPoseStack.rect4(pos.x, pos.y, texSize - 1, texSize - 1, McColorValues.white) - } - - pPoseStack.popPose() - - if(toolTipCell!=null) { - drawInfoCard(pPoseStack, pMouseX, pMouseY, toolTipCell!!) - } - - // finally, render the header and footer on top of everything - renderHeader(pPoseStack) - renderFooter(pPoseStack, toolTipCell) - } - - private fun keyColorMap(key: String): Int { - return when (key) { - "voltage" -> McColorValues.cyan - "current" -> McColorValues.red - "resistance" -> McColorValues.yellow - "energy" -> McColorValues.purple - "inductance" -> McColor(255u, 170u, 80u).value - "capacitance" -> McColorValues.blue - else -> McColorValues.white - } - } - - private fun drawInfoCard(poseStack: PoseStack, mouseX : Int, mouseY : Int, cell : CellInfo){ - val data = cell.info - - val boxOriginX = mouseX + 5 - val boxOriginY = mouseY + 5 - - val marginX = 2 - val marginY = 2 - - val typeString = "${get(TranslatableComponent("plotter.eln2.type").key)}: ${get("block.${cell.type.replace(":", ".")}")}" - - val width = max( - font.width(typeString), - data.entries.maxOf { - font.width("${it.key}: ${it.value}") - }) + 5 + marginX * 2 - - val height = data.entries.count() * font.lineHeight + marginY * 2 + 2 * font.lineHeight - - // generate background - fill(poseStack, boxOriginX, boxOriginY, boxOriginX + width, boxOriginY + height, McColor(70u, 72u, 74u).value) - - data.entries.forEachIndexed { index, entry -> - val vertical = index * font.lineHeight - - val color = keyColorMap(entry.key) - val label = get(TranslatableComponent("plotter.eln2.${entry.key}").key) - val value = entry.value - - // draw the label - drawString(poseStack, font, "${label}: ", boxOriginX + marginX, boxOriginY + vertical + marginY, color) - - // draw the value - drawString(poseStack, font, value, boxOriginX + marginX + font.width("${label}: "), boxOriginY + vertical + marginY, color) - } - - // draw separator - val outlineColor = McColor(86u, 86u, 86u).value - - // display the type of the cell - - drawString( - poseStack, - font, - typeString, - boxOriginX + marginX + 1, - boxOriginY + height - font.lineHeight - 1, - McColor(255u, 0u ,0u, 200u).value) - - // separator - - hLine(poseStack, boxOriginX, boxOriginX + width, boxOriginY + height - font.lineHeight - font.lineHeight / 2, outlineColor) - - // draw bounding box - poseStack.rect4(boxOriginX, boxOriginY, width, height, outlineColor) - } - - private fun renderHeader(poseStack: PoseStack){ - val h = 20 - fill(poseStack, 0, 0, width, h, McColor(60u, 63u, 65u, 150u).value) - drawString( - poseStack, font, - "${get(TranslatableComponent("plotter.eln2.solve_time").key)}: ${valueText(solveTime.toDouble().div(1000000000.0), UnitType.SECOND)}", - 2 , 6, McColor(255u, 255u, 200u, 200u).value - ) - poseStack.rect4(0, 0, width - 1, h, McColor(95u, 95u, 95u, 150u).value) - } - - private fun renderFooter(poseStack: PoseStack, toolTipCell : CellInfo?){ - val localizedName = - if (toolTipCell != null) get(blockFor(toolTipCell.type).descriptionId) - else toolTipCell?.type - - val sb = StringBuilder() - - sb.append("${get(TranslatableComponent("plotter.eln2.cell_count").key)}: ${cells.count()}") - - sb.append(" ") - - if (localizedName != null) { - sb.append("${get(TranslatableComponent("plotter.eln2.highlighted").key)}: $localizedName") - } - - val h = 20 - fill(poseStack, 0, height - h, width, height, McColor(60u, 63u, 65u, 100u).value) - poseStack.rect4(0, height - h, width - 1, height, McColor(95u, 95u, 95u, 150u).value) - drawString(poseStack, font, sb.toString(),2 , height - h + 6, McColor(255u, 255u, 200u, 100u).value) - } - - // zoom - override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pDelta: Double): Boolean { - if(pDelta < 0){ - scale = max(0.2f, scale + pDelta.toFloat() / 20f) - } - else { - scale += pDelta.toFloat() / 20f - } - - return super.mouseScrolled(pMouseX, pMouseY, pDelta) - } - - // pan - override fun mouseDragged(pMouseX: Double, pMouseY: Double, pButton: Int, pDragX: Double, pDragY: Double): Boolean { - posX += pDragX.toFloat() / scale - posY += pDragY.toFloat() / scale - - return super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY) - } -} diff --git a/src/main/java/org/eln2/mc/client/input/Input.kt b/src/main/java/org/eln2/mc/client/input/Input.kt deleted file mode 100644 index 1995c420..00000000 --- a/src/main/java/org/eln2/mc/client/input/Input.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.eln2.mc.client.input -import com.mojang.blaze3d.platform.InputConstants -import net.minecraft.client.KeyMapping -import net.minecraft.client.Minecraft -import net.minecraft.world.entity.LivingEntity -import net.minecraft.world.phys.BlockHitResult -import net.minecraft.world.phys.HitResult -import net.minecraftforge.api.distmarker.Dist -import net.minecraftforge.client.ClientRegistry -import net.minecraftforge.client.event.InputEvent -import net.minecraftforge.client.settings.KeyConflictContext -import net.minecraftforge.eventbus.api.SubscribeEvent -import net.minecraftforge.fml.common.Mod -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.network.clientToServer.CircuitExplorerOpenPacket -import org.lwjgl.glfw.GLFW - -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, value = [Dist.CLIENT]) -object Input { - private val OPEN_CIRCUIT_PLOTTER = KeyMapping( - "Open circuit plotter", - KeyConflictContext.IN_GAME, - InputConstants.Type.KEYSYM, - InputConstants.KEY_P, - "Electrical Age 2") - - init { - ClientRegistry.registerKeyBinding(OPEN_CIRCUIT_PLOTTER) - } - - @SubscribeEvent - fun inputEvent(event: InputEvent.KeyInputEvent){ - if(OPEN_CIRCUIT_PLOTTER.isDown && event.action == GLFW.GLFW_PRESS) - handleOpenCircuitPlotter() - } - - private fun handleOpenCircuitPlotter(){ - val player = Minecraft.getInstance().cameraEntity as LivingEntity - val pickResult = player.pick(100.0, 0f, false) - - if(pickResult.type != HitResult.Type.BLOCK) - return - - val blockHit = pickResult as BlockHitResult - if(player.level.getBlockState(blockHit.blockPos).block !is CellBlockBase) - return - - Networking.sendToServer(CircuitExplorerOpenPacket()) - } -} diff --git a/src/main/java/org/eln2/mc/client/screens/CapacitorCellScreen.kt b/src/main/java/org/eln2/mc/client/screens/CapacitorCellScreen.kt deleted file mode 100644 index 8248989e..00000000 --- a/src/main/java/org/eln2/mc/client/screens/CapacitorCellScreen.kt +++ /dev/null @@ -1,115 +0,0 @@ -package org.eln2.mc.client.screens - -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.gui.components.Button -import net.minecraft.client.gui.components.EditBox -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TextComponent -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.entity.player.Inventory -import net.minecraftforge.client.event.ContainerScreenEvent -import net.minecraftforge.common.MinecraftForge -import org.eln2.mc.Eln2 -import org.eln2.mc.common.containers.CapacitorCellContainer -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.clientToServer.SingleDoubleElementGuiUpdatePacket -import java.awt.Color - -class CapacitorCellScreen(private val container: CapacitorCellContainer, inv: Inventory, name: Component) : - AbstractContainerScreen(container, inv, name) { - - companion object { - private val guiTexture: ResourceLocation = ResourceLocation(Eln2.MODID, "textures/gui/capacitor_gui.png") - private const val textureWidth = 256 - private const val textureHeight = 128 - private const val guiWidth = 256 - private const val guiHeight = 128 - - private const val textboxW = 192 - private const val textboxH = 16 - private const val textboxX = 32 - private const val textboxY = 48 - - private const val buttonW = 60 - private const val buttonH = 18 - private const val buttonX = 96 - private const val buttonY = 128 - (buttonW / 2) - } - - private var relX: Int = 0 - private var relY: Int = 0 - lateinit var textbox: EditBox - lateinit var saveButton: Button - - private var capacitance = 0.0 - - override fun init() { - relX = (this.width - guiWidth) / 2 - relY = (this.height - guiHeight) / 2 - textbox = EditBox(this.font, relX + textboxX, relY + textboxY, textboxW, textboxH, TextComponent("unused")) - textbox.value = capacitance.toString() - saveButton = Button(relX + buttonX, relY + buttonY, buttonW, buttonH, TranslatableComponent("gui.eln2.save")) { - try { - val capcitance = textbox.value.toDouble() - this.container.value = capcitance - Networking.sendToServer(SingleDoubleElementGuiUpdatePacket(capcitance, container.pos)) - this.onClose() - } catch (ex: NumberFormatException) { - textbox.setTextColor(Color.RED.rgb) - } - } - - addRenderableWidget(textbox) - addRenderableWidget(saveButton) - } - - override fun renderBg(pPoseStack: PoseStack, pPartialTick: Float, pMouseX: Int, pMouseY: Int) { - RenderSystem.setShaderTexture(0, guiTexture) - blit( - pPoseStack, - relX, - relY, - this.blitOffset, - 0.0f, - 0.0f, - guiWidth, - guiHeight, - textureWidth, - textureHeight - ) - } - - override fun render(pPoseStack: PoseStack, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - this.renderBackground(pPoseStack) - this.renderBg(pPoseStack, pPartialTick, pMouseX, pMouseY) - MinecraftForge.EVENT_BUS.post(ContainerScreenEvent.DrawBackground(this, pPoseStack, pMouseX, pMouseY)) - - if (container.value != capacitance) { - capacitance = container.value - textbox.value = "%.6f".format(capacitance) - } - - //Render foreground - for (widget in renderables) { - widget.render(pPoseStack, pMouseX, pMouseY, pPartialTick) - } - - //Vanilla gets a posestack from the render system rather than re-using the pPoseStack - //So let's do the same to be safe - val posestack = RenderSystem.getModelViewStack() - posestack.pushPose() - posestack.translate(relX.toDouble(), relY.toDouble(), 0.0) - RenderSystem.applyModelViewMatrix() - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) - this.font.draw(pPoseStack, this.title, this.titleLabelX.toFloat(), this.titleLabelY.toFloat(), 4210752) - posestack.popPose() - RenderSystem.applyModelViewMatrix() - RenderSystem.enableDepthTest() - MinecraftForge.EVENT_BUS.post(ContainerScreenEvent.DrawForeground(this, pPoseStack, pMouseX, pMouseY)) - - this.renderTooltip(pPoseStack, pMouseX, pMouseY) - } -} diff --git a/src/main/java/org/eln2/mc/client/screens/InductorCellScreen.kt b/src/main/java/org/eln2/mc/client/screens/InductorCellScreen.kt deleted file mode 100644 index 2d9a009e..00000000 --- a/src/main/java/org/eln2/mc/client/screens/InductorCellScreen.kt +++ /dev/null @@ -1,116 +0,0 @@ -package org.eln2.mc.client.screens - -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.gui.components.Button -import net.minecraft.client.gui.components.EditBox -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TextComponent -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.entity.player.Inventory -import net.minecraftforge.client.event.ContainerScreenEvent -import net.minecraftforge.common.MinecraftForge -import org.eln2.mc.Eln2 -import org.eln2.mc.common.containers.InductorCellContainer -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.clientToServer.SingleDoubleElementGuiUpdatePacket -import java.awt.Color - -class InductorCellScreen(private val container: InductorCellContainer, inv: Inventory, name: Component) : - AbstractContainerScreen(container, inv, name) { - - companion object { - private val guiTexture: ResourceLocation = ResourceLocation(Eln2.MODID, "textures/gui/inductor_gui.png") - private const val textureWidth = 256 - private const val textureHeight = 128 - private const val guiWidth = 256 - private const val guiHeight = 128 - - private const val textboxW = 192 - private const val textboxH = 16 - private const val textboxX = 32 - private const val textboxY = 48 - - private const val buttonW = 60 - private const val buttonH = 18 - private const val buttonX = 96 - private const val buttonY = 128 - (buttonW / 2) - } - - - private var relX: Int = 0 - private var relY: Int = 0 - lateinit var textbox: EditBox - lateinit var saveButton: Button - - private var inductance = 0.0 - - override fun init() { - relX = (this.width - guiWidth) / 2 - relY = (this.height - guiHeight) / 2 - textbox = EditBox(this.font, relX + textboxX, relY + textboxY, textboxW, textboxH, TextComponent("unused")) - textbox.value = inductance.toString() - saveButton = Button(relX + buttonX, relY + buttonY, buttonW, buttonH, TranslatableComponent("gui.eln2.save")) { - try { - val inductance = textbox.value.toDouble() - this.container.value = inductance - Networking.sendToServer(SingleDoubleElementGuiUpdatePacket(inductance, container.pos)) - this.onClose() - } catch (ex: NumberFormatException) { - textbox.setTextColor(Color.RED.rgb) - } - } - - addRenderableWidget(textbox) - addRenderableWidget(saveButton) - } - - override fun renderBg(pPoseStack: PoseStack, pPartialTick: Float, pMouseX: Int, pMouseY: Int) { - RenderSystem.setShaderTexture(0, guiTexture) - blit( - pPoseStack, - relX, - relY, - this.blitOffset, - 0.0f, - 0.0f, - guiWidth, - guiHeight, - textureWidth, - textureHeight - ) - } - - override fun render(pPoseStack: PoseStack, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - this.renderBackground(pPoseStack) - this.renderBg(pPoseStack, pPartialTick, pMouseX, pMouseY) - MinecraftForge.EVENT_BUS.post(ContainerScreenEvent.DrawBackground(this, pPoseStack, pMouseX, pMouseY)) - - if (container.value != inductance) { - inductance = container.value - textbox.value = "%.6f".format(inductance) - } - - //Render foreground - for (widget in renderables) { - widget.render(pPoseStack, pMouseX, pMouseY, pPartialTick) - } - - //Vanilla gets a posestack from the render system rather than re-using the pPoseStack - //So let's do the same to be safe - val posestack = RenderSystem.getModelViewStack() - posestack.pushPose() - posestack.translate(relX.toDouble(), relY.toDouble(), 0.0) - RenderSystem.applyModelViewMatrix() - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) - this.font.draw(pPoseStack, this.title, this.titleLabelX.toFloat(), this.titleLabelY.toFloat(), 4210752) - posestack.popPose() - RenderSystem.applyModelViewMatrix() - RenderSystem.enableDepthTest() - MinecraftForge.EVENT_BUS.post(ContainerScreenEvent.DrawForeground(this, pPoseStack, pMouseX, pMouseY)) - - this.renderTooltip(pPoseStack, pMouseX, pMouseY) - } -} diff --git a/src/main/java/org/eln2/mc/client/screens/ResistorCellScreen.kt b/src/main/java/org/eln2/mc/client/screens/ResistorCellScreen.kt deleted file mode 100644 index 35a0be92..00000000 --- a/src/main/java/org/eln2/mc/client/screens/ResistorCellScreen.kt +++ /dev/null @@ -1,116 +0,0 @@ -package org.eln2.mc.client.screens - -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.gui.components.Button -import net.minecraft.client.gui.components.EditBox -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TextComponent -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.entity.player.Inventory -import net.minecraftforge.client.event.ContainerScreenEvent -import net.minecraftforge.common.MinecraftForge -import org.eln2.mc.Eln2 -import org.eln2.mc.common.containers.ResistorCellContainer -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.clientToServer.SingleDoubleElementGuiUpdatePacket -import java.awt.Color - -class ResistorCellScreen(private val container: ResistorCellContainer, inv: Inventory, name: Component) : - AbstractContainerScreen(container, inv, name) { - - companion object { - private val guiTexture: ResourceLocation = ResourceLocation(Eln2.MODID, "textures/gui/resistor_gui.png") - private const val textureWidth = 256 - private const val textureHeight = 128 - private const val guiWidth = 256 - private const val guiHeight = 128 - - private const val textboxW = 192 - private const val textboxH = 16 - private const val textboxX = 32 - private const val textboxY = 48 - - private const val buttonW = 60 - private const val buttonH = 18 - private const val buttonX = 96 - private const val buttonY = 128 - (buttonW / 2) - } - - private var relX: Int = 0 - private var relY: Int = 0 - - lateinit var textbox: EditBox - lateinit var saveButton: Button - - private var resistance = 0.0 - - override fun init() { - relX = (this.width - guiWidth) / 2 - relY = (this.height - guiHeight) / 2 - textbox = EditBox(this.font, relX + textboxX, relY + textboxY, textboxW, textboxH, TextComponent("unused")) - textbox.value = resistance.toString() - saveButton = Button(relX + buttonX, relY + buttonY, buttonW, buttonH, TranslatableComponent("gui.eln2.save")) { - try { - val resistance = textbox.value.toDouble() - this.container.value = resistance - Networking.sendToServer(SingleDoubleElementGuiUpdatePacket(resistance, container.pos)) - this.onClose() - } catch (ex: NumberFormatException) { - textbox.setTextColor(Color.RED.rgb) - } - } - - addRenderableWidget(textbox) - addRenderableWidget(saveButton) - } - - override fun renderBg(pPoseStack: PoseStack, pPartialTick: Float, pMouseX: Int, pMouseY: Int) { - RenderSystem.setShaderTexture(0, guiTexture) - blit( - pPoseStack, - relX, - relY, - this.blitOffset, - 0.0f, - 0.0f, - guiWidth, - guiHeight, - textureWidth, - textureHeight - ) - } - - override fun render(pPoseStack: PoseStack, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - this.renderBackground(pPoseStack) - this.renderBg(pPoseStack, pPartialTick, pMouseX, pMouseY) - MinecraftForge.EVENT_BUS.post(ContainerScreenEvent.DrawBackground(this, pPoseStack, pMouseX, pMouseY)) - - if (container.value != resistance) { - resistance = container.value - textbox.value = resistance.toString() - } - - //Render foreground - for (widget in renderables) { - widget.render(pPoseStack, pMouseX, pMouseY, pPartialTick) - } - - //Vanilla gets a posestack from the render system rather than re-using the pPoseStack - //So let's do the same to be safe - val posestack = RenderSystem.getModelViewStack() - posestack.pushPose() - posestack.translate(relX.toDouble(), relY.toDouble(), 0.0) - RenderSystem.applyModelViewMatrix() - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) - this.font.draw(pPoseStack, this.title, this.titleLabelX.toFloat(), this.titleLabelY.toFloat(), 4210752) - posestack.popPose() - RenderSystem.applyModelViewMatrix() - RenderSystem.enableDepthTest() - MinecraftForge.EVENT_BUS.post(ContainerScreenEvent.DrawForeground(this, pPoseStack, pMouseX, pMouseY)) - - this.renderTooltip(pPoseStack, pMouseX, pMouseY) - } -} diff --git a/src/main/java/org/eln2/mc/client/screens/VoltageSourceCellScreen.kt b/src/main/java/org/eln2/mc/client/screens/VoltageSourceCellScreen.kt deleted file mode 100644 index 77f1af4c..00000000 --- a/src/main/java/org/eln2/mc/client/screens/VoltageSourceCellScreen.kt +++ /dev/null @@ -1,118 +0,0 @@ -package org.eln2.mc.client.screens - -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.gui.GuiComponent -import net.minecraft.client.gui.components.Button -import net.minecraft.client.gui.components.EditBox -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TextComponent -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.entity.player.Inventory -import net.minecraftforge.client.event.ContainerScreenEvent.DrawBackground -import net.minecraftforge.client.event.ContainerScreenEvent.DrawForeground -import net.minecraftforge.common.MinecraftForge -import org.eln2.mc.Eln2.MODID -import org.eln2.mc.common.containers.VoltageSourceCellContainer -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.clientToServer.SingleDoubleElementGuiUpdatePacket -import java.awt.Color - -class VoltageSourceCellScreen(private val container: VoltageSourceCellContainer, inv: Inventory, name: Component) : - AbstractContainerScreen(container, inv, name) { - - companion object { - private val guiTexture: ResourceLocation = ResourceLocation(MODID, "textures/gui/voltage_source_gui.png") - private const val textureWidth = 320 - private const val textureHeight = 128 - private const val guiWidth = 256 - private const val guiHeight = 128 - - private const val textboxW = 192 - private const val textboxH = 16 - private const val textboxX = 32 - private const val textboxY = 48 - - private const val buttonW = 60 - private const val buttonH = 18 - private const val buttonX = 96 - private const val buttonY = 128 - (buttonW / 2) - } - - private var relX: Int = 0 - private var relY: Int = 0 - lateinit var textbox: EditBox - lateinit var saveButton: Button - - private var voltage = 0.0 - - override fun init() { - relX = (this.width - guiWidth) / 2 - relY = (this.height - guiHeight) / 2 - textbox = EditBox(this.font, relX + textboxX, relY + textboxY, textboxW, textboxH, TextComponent("unused")) - textbox.value = voltage.toString() - saveButton = Button(relX + buttonX, relY + buttonY, buttonW, buttonH, TranslatableComponent("gui.eln2.save")) { - try { - val voltage = textbox.value.toDouble() - this.container.value = voltage - Networking.sendToServer(SingleDoubleElementGuiUpdatePacket(voltage, container.pos)) - this.onClose() - } catch (ex: NumberFormatException) { - textbox.setTextColor(Color.RED.rgb) - } - } - - addRenderableWidget(textbox) - addRenderableWidget(saveButton) - } - - override fun renderBg(pPoseStack: PoseStack, pPartialTick: Float, pMouseX: Int, pMouseY: Int) { - RenderSystem.setShaderTexture(0, guiTexture) - GuiComponent.blit( - pPoseStack, - relX, - relY, - this.blitOffset, - 0.0f, - 0.0f, - guiWidth, - guiHeight, - textureWidth, - textureHeight - ) - } - - override fun render(pPoseStack: PoseStack, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - this.renderBackground(pPoseStack) - this.renderBg(pPoseStack, pPartialTick, pMouseX, pMouseY) - MinecraftForge.EVENT_BUS.post(DrawBackground(this, pPoseStack, pMouseX, pMouseY)) - - if (container.value != voltage) { - voltage = container.value - textbox.value = voltage.toString() - } - - //Render foreground - for (widget in renderables) { - widget.render(pPoseStack, pMouseX, pMouseY, pPartialTick) - } - - //Vanilla gets a posestack from the render system rather than re-using the pPoseStack - //So let's do the same to be safe - val posestack = RenderSystem.getModelViewStack() - posestack.pushPose() - posestack.translate(relX.toDouble(), relY.toDouble(), 0.0) - RenderSystem.applyModelViewMatrix() - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) - this.font.draw(pPoseStack, this.title, this.titleLabelX.toFloat(), this.titleLabelY.toFloat(), 4210752) - posestack.popPose() - RenderSystem.applyModelViewMatrix() - RenderSystem.enableDepthTest() - MinecraftForge.EVENT_BUS.post(DrawForeground(this, pPoseStack, pMouseX, pMouseY)) - - this.renderTooltip(pPoseStack, pMouseX, pMouseY) - } - -} diff --git a/src/main/java/org/eln2/mc/common/CommonEvents.kt b/src/main/java/org/eln2/mc/common/CommonEvents.kt deleted file mode 100644 index 47445390..00000000 --- a/src/main/java/org/eln2/mc/common/CommonEvents.kt +++ /dev/null @@ -1,102 +0,0 @@ -package org.eln2.mc.common - -import com.charleskorn.kaml.Yaml -import net.minecraft.ChatFormatting -import net.minecraft.Util -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.server.level.ServerLevel -import net.minecraft.world.entity.player.Player -import net.minecraftforge.event.ServerChatEvent -import net.minecraftforge.event.TickEvent -import net.minecraftforge.event.entity.EntityJoinWorldEvent -import net.minecraftforge.eventbus.api.SubscribeEvent -import net.minecraftforge.fml.common.Mod -import net.minecraftforge.fml.loading.FMLPaths -import net.minecraftforge.server.ServerLifecycleHooks -import org.eln2.mc.Eln2 -import org.eln2.mc.common.cell.CellGraphManager -import org.eln2.mc.utility.AnalyticsAcknowledgementsData -import java.io.IOException - -@Mod.EventBusSubscriber -object CommonEvents { - - private const val THIRTY_DAYS_AS_MILLISECONDS: Long = 2_592_000_000L - - @SubscribeEvent - fun onServerTick(event : TickEvent.ServerTickEvent){ - if(event.phase == TickEvent.Phase.END){ - ServerLifecycleHooks.getCurrentServer().allLevels.forEach{ - CellGraphManager.getFor(it).tickAll() - } - } - } - - @SubscribeEvent - fun onChat(event : ServerChatEvent){ - when (event.message) { - "build" -> { - CellGraphManager.getFor(event.player.level as ServerLevel).graphs.values.forEach{ it.build() } - } - "circuits" -> { - CellGraphManager.getFor(event.player.level as ServerLevel).graphs.values.forEach { - Eln2.LOGGER.info("Circuit:") - Eln2.LOGGER.info( - it.circuit.components.map{ - comp -> "\n ${comp.detail()}${comp.pins.map { pin -> pin.node?.index}}" - } - ) - } - } - } - } - - @SubscribeEvent - fun onEntityJoinedWorld(event: EntityJoinWorldEvent) { - //Warn new users that we collect analytics - if (event.world.isClientSide && event.entity is Player) { - if (Eln2.config.enableAnalytics) { - val acknowledgementFile = FMLPaths.CONFIGDIR.get().resolve("ElectricalAge/acknowledgements.yml").toFile() - if (!acknowledgementFile.exists()) { - try { - acknowledgementFile.parentFile.mkdirs() - acknowledgementFile.createNewFile() - acknowledgementFile.writeText(Yaml.default.encodeToString(AnalyticsAcknowledgementsData.serializer(), AnalyticsAcknowledgementsData(mutableMapOf()))) - } catch (ex: Exception) { - when (ex) { - is IOException, is SecurityException -> { - Eln2.LOGGER.warn("Unable to write default analytics acknowledgements config") - Eln2.LOGGER.warn(ex.localizedMessage) - } - else -> throw ex - } - } - } - val uuid: String = event.entity.uuid.toString() - val acknowledgements: AnalyticsAcknowledgementsData = try { - Yaml.default.decodeFromStream(AnalyticsAcknowledgementsData.serializer(), acknowledgementFile.inputStream()) - } catch (ex: IOException) { - AnalyticsAcknowledgementsData(mutableMapOf()) - } - if (acknowledgements.entries.none { (k, _) -> k == uuid } || acknowledgements.entries[uuid]!! < (System.currentTimeMillis()) - THIRTY_DAYS_AS_MILLISECONDS) { - event.entity.sendMessage(TranslatableComponent("misc.eln2.acknowledge_analytics").withStyle(ChatFormatting.RED), Util.NIL_UUID) - acknowledgements.entries[uuid] = System.currentTimeMillis() - } - - try { - acknowledgementFile.writeText(Yaml.default.encodeToString(AnalyticsAcknowledgementsData.serializer(), acknowledgements)) - } catch (ex: Exception) { - when (ex) { - is IOException, is SecurityException -> { - Eln2.LOGGER.warn("Unable to save analytics acknowledgements") - Eln2.LOGGER.warn(ex.localizedMessage) - - event.entity.sendMessage(TranslatableComponent("misc.eln2.analytics_save_failure").withStyle(ChatFormatting.ITALIC), Util.NIL_UUID) - } - else -> throw ex - } - } - } - } - } -} diff --git a/src/main/java/org/eln2/mc/common/Configuration.kt b/src/main/java/org/eln2/mc/common/Configuration.kt deleted file mode 100644 index f96a0fb6..00000000 --- a/src/main/java/org/eln2/mc/common/Configuration.kt +++ /dev/null @@ -1,54 +0,0 @@ -package org.eln2.mc.common - -import com.charleskorn.kaml.Yaml -import kotlinx.serialization.Serializable -import org.eln2.mc.Eln2.LOGGER -import java.io.File -import java.util.* - -object Configuration { - private val CONFIG_FILE: File = File("config/electrical_age.yaml") - var config: ElectricalAgeConfiguration = ElectricalAgeConfiguration() - - fun loadConfig(configFile: File = CONFIG_FILE) { - try { - if (configFile.isFile) { - LOGGER.info("[Electrical Age] Reading config from ${configFile.absoluteFile}") - config = Yaml.default.decodeFromStream(ElectricalAgeConfiguration.serializer(), configFile.inputStream()) - } else { - config = ElectricalAgeConfiguration() - saveConfig() - } - } catch (e: Exception) { - LOGGER.error("Electrical Age had an issue with loading the configuration file, please check the file for errors.") - LOGGER.error("Check that 1) You have valid YAML 2) the config directives are spelled correctly (see documentation)") - } - } - - private fun saveConfig(configFile: File = CONFIG_FILE) { - try { - LOGGER.info("[Electrical Age] Writing config to ${configFile.absoluteFile}") - val configText = Yaml.default.encodeToString(ElectricalAgeConfiguration.serializer(), config) - if (!configFile.exists()) { - configFile.createNewFile() - } - configFile.writeText(configText) - } catch (e: Exception) { - LOGGER.error("Electrical Age was unable to write the config file, please check filesystem permissions: $e") - } - } -} - -/** - * ElectricalAgeConfiguration - * - * NOTE: ALL FIELDS _MUST_ have default values when called, since the user will likely want a sane default! - * They may be blank, but MUST be present. Thanks! - */ -@Serializable -data class ElectricalAgeConfiguration ( - var enableAnalytics: Boolean = true, - // TODO: Replace with stats.age-series.org (but needs CAA certificates) - var analyticsEndpoint: String = "https://ingz5drycg.execute-api.us-east-1.amazonaws.com/", - var analyticsUuid: String = UUID.randomUUID().toString() -) diff --git a/src/main/java/org/eln2/mc/common/Eln2CreativeTabs.kt b/src/main/java/org/eln2/mc/common/Eln2CreativeTabs.kt deleted file mode 100644 index 693e7a4c..00000000 --- a/src/main/java/org/eln2/mc/common/Eln2CreativeTabs.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.eln2.mc.common - -import net.minecraft.world.item.CreativeModeTab -import net.minecraft.world.item.ItemStack -import org.eln2.mc.common.blocks.BlockRegistry - -val eln2Tab: CreativeModeTab = object: CreativeModeTab("Electrical_Age") { - override fun makeIcon(): ItemStack { - return ItemStack(BlockRegistry.VOLTAGE_SOURCE_CELL.item.get().asItem()) - } -} diff --git a/src/main/java/org/eln2/mc/common/Mathematics.kt b/src/main/java/org/eln2/mc/common/Mathematics.kt deleted file mode 100644 index eaf85849..00000000 --- a/src/main/java/org/eln2/mc/common/Mathematics.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.eln2.mc.common - -import net.minecraft.core.Direction - -object Mathematics { - fun angleBetweenPoints2(x0: Double, y0: Double, x1: Double, y1: Double): Double { - return kotlin.math.atan2(y1 - y0, x1 - x0) * 180.0 / Math.PI - } - - fun angleToDirection(angle : Double) : Direction{ - return Direction.fromYRot(angle) - } -} diff --git a/src/main/java/org/eln2/mc/common/PlacementRotation.kt b/src/main/java/org/eln2/mc/common/PlacementRotation.kt deleted file mode 100644 index 7e744f73..00000000 --- a/src/main/java/org/eln2/mc/common/PlacementRotation.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.eln2.mc.common - -import net.minecraft.core.Direction - -enum class RelativeRotationDirection { - Front, - Back, - Left, - Right, -} - -class PlacementRotation(val placementDirection : Direction) { - fun getAbsoluteFromRelative(rotation : RelativeRotationDirection) : Direction { - return when(rotation){ - RelativeRotationDirection.Front -> placementDirection - RelativeRotationDirection.Back -> placementDirection.opposite - RelativeRotationDirection.Right -> placementDirection.clockWise - RelativeRotationDirection.Left -> placementDirection.counterClockWise - } - } - - fun getRelativeFromAbsolute(direction: Direction) : RelativeRotationDirection { - return when(direction){ - placementDirection -> RelativeRotationDirection.Front - placementDirection.opposite -> RelativeRotationDirection.Back - placementDirection.clockWise -> RelativeRotationDirection.Right - placementDirection.counterClockWise -> RelativeRotationDirection.Left - else -> error("Direction not implemented: $direction") - } - } -} - diff --git a/src/main/java/org/eln2/mc/common/blocks/BlockRegistry.kt b/src/main/java/org/eln2/mc/common/blocks/BlockRegistry.kt deleted file mode 100644 index cc25d0e9..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/BlockRegistry.kt +++ /dev/null @@ -1,72 +0,0 @@ -@file:Suppress("unused") // Because block variables here would be suggested for deletion. - -package org.eln2.mc.common.blocks - -import net.minecraft.world.item.* -import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.entity.BlockEntityType -import net.minecraftforge.eventbus.api.IEventBus -import net.minecraftforge.registries.DeferredRegister -import net.minecraftforge.registries.ForgeRegistries -import net.minecraftforge.registries.RegistryObject -import org.eln2.mc.Eln2 -import org.eln2.mc.common.blocks.block.DcDcConverterBlock -import org.eln2.mc.common.blocks.cell.* -import org.eln2.mc.common.eln2Tab - -object BlockRegistry { - @Suppress("MemberVisibilityCanBePrivate") // Used for block registration and fetching - val BLOCK_REGISTRY = DeferredRegister.create(ForgeRegistries.BLOCKS, Eln2.MODID)!! // Yeah, if this fails blow up the game - @Suppress("MemberVisibilityCanBePrivate") // Used for block registration and fetching - val BLOCK_ITEM_REGISTRY = DeferredRegister.create(ForgeRegistries.ITEMS, Eln2.MODID)!! // Yeah, if this fails blow up the game - @Suppress("MemberVisibilityCanBePrivate") // Used for block registration and fetching - val BLOCK_ENTITY_REGISTRY = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITIES, Eln2.MODID)!! // Yeah, if this fails blow up the game - - fun setup(bus : IEventBus) { - BLOCK_REGISTRY.register(bus) - BLOCK_ITEM_REGISTRY.register(bus) - BLOCK_ENTITY_REGISTRY.register(bus) - } - - val CELL_BLOCK_ENTITY: RegistryObject> = BLOCK_ENTITY_REGISTRY.register("cell"){ - @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // Thanks, Minecraft for the high quality code. - BlockEntityType.Builder.of(::CellTileEntity).build(null) - } - - class CellBlockRegistryItem( - val name : String, - val block : RegistryObject, - val item : RegistryObject - ) - - data class BlockRegistryItem( - val name: String, - val block: RegistryObject, - val item: RegistryObject - ) - - private fun registerCellBlock(name : String, tab: CreativeModeTab? = null, supplier : () -> CellBlockBase) : CellBlockRegistryItem{ - val block = BLOCK_REGISTRY.register(name) { supplier() } - val item = BLOCK_ITEM_REGISTRY.register(name) { BlockItem(block.get(), Item.Properties().also {if (tab != null) it.tab(tab)}) } - return CellBlockRegistryItem(name, block, item) - } - - private fun registerBasicBlock(name: String, tab: CreativeModeTab? = null, supplier: () -> Block): BlockRegistryItem { - val block = BLOCK_REGISTRY.register(name) {supplier()} - val item = BLOCK_ITEM_REGISTRY.register(name) {BlockItem(block.get(), Item.Properties().also {if(tab != null) it.tab(tab)})} - return BlockRegistryItem(name, block, item) - } - - val RESISTOR_CELL = registerCellBlock("resistor", eln2Tab) { ResistorCellBlock() } - val WIRE_CELL = registerCellBlock("wire", eln2Tab) { WireCellBlock() } - val VOLTAGE_SOURCE_CELL = registerCellBlock("voltage_source", eln2Tab) { VoltageSourceCellBlock() } - val GROUND_CELL = registerCellBlock("ground", eln2Tab) { GroundCellBlock() } - val CAPACITOR_CELL = registerCellBlock("capacitor", eln2Tab) { CapacitorCellBlock() } - val INDUCTOR_CELL = registerCellBlock("inductor", eln2Tab) { InductorCellBlock() } - val DIODE_CELL = registerCellBlock("diode", eln2Tab) { DiodeCellBlock() } - val DC_DC_CONVERTER_BLOCK = registerBasicBlock("dcdc_converter") { DcDcConverterBlock() } - val `12V_BATTERY_CELL` = registerCellBlock("12v_battery", eln2Tab) { `12vBatteryCellBlock`()} - val LIGHT_CELL = registerCellBlock("light") {LightCellBlock()} - val SOLAR_LIGHT_CELL = registerCellBlock("solar_light") {SolarLightCellBlock()} - val SOLAR_PANEL_CELL = registerCellBlock("solar_panel", eln2Tab) {SolarPanelCellBlock()} -} diff --git a/src/main/java/org/eln2/mc/common/blocks/CellBlockBase.kt b/src/main/java/org/eln2/mc/common/blocks/CellBlockBase.kt deleted file mode 100644 index 6fc94333..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/CellBlockBase.kt +++ /dev/null @@ -1,87 +0,0 @@ -package org.eln2.mc.common.blocks - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.entity.LivingEntity -import net.minecraft.world.entity.player.Player -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.context.BlockPlaceContext -import net.minecraft.world.level.Explosion -import net.minecraft.world.level.Level -import net.minecraft.world.level.LevelReader -import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.EntityBlock -import net.minecraft.world.level.block.HorizontalDirectionalBlock -import net.minecraft.world.level.block.entity.BlockEntity -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.block.state.StateDefinition -import net.minecraft.world.level.material.FluidState -import net.minecraft.world.level.material.Material -import org.eln2.mc.common.cell.CellRegistry - -abstract class CellBlockBase : HorizontalDirectionalBlock(Properties.of(Material.STONE).noOcclusion()), EntityBlock { - init { - @Suppress("LeakingThis") - registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.NORTH)) - } - - override fun getStateForPlacement(pContext: BlockPlaceContext): BlockState? { - return super.defaultBlockState().setValue(FACING, pContext.horizontalDirection.opposite.counterClockWise) - } - - override fun createBlockStateDefinition(pBuilder: StateDefinition.Builder) { - super.createBlockStateDefinition(pBuilder) - pBuilder.add(FACING) - } - - override fun setPlacedBy( - level : Level, - pos : BlockPos, - blockState : BlockState, - entity : LivingEntity?, - itemStack : ItemStack - ) { - val cellEntity = level.getBlockEntity(pos)!! as CellTileEntity - cellEntity.setPlacedBy(level, pos, blockState, entity, itemStack, CellRegistry.registry.getValue(getCellProvider())?: error("Unable to get cell provider")) - } - - - override fun onBlockExploded(blState: BlockState?, lvl: Level?, pos: BlockPos?, exp: Explosion?) { - destroy(lvl?: error("Level was null"), pos?: error("Position was null")) - super.onBlockExploded(blState, lvl, pos, exp) - } - - override fun onDestroyedByPlayer( - blState: BlockState?, - lvl: Level?, - pos: BlockPos?, - pl: Player?, - wh: Boolean, - flState: FluidState? - ): Boolean { - destroy(lvl?: error("Level was null"), pos?: error("Position was null")) - return super.onDestroyedByPlayer(blState, lvl, pos, pl, wh, flState) - } - - private fun destroy(level: Level, pos: BlockPos){ - if (!level.isClientSide) { - val cellEntity = level.getBlockEntity(pos)!! as CellTileEntity - cellEntity.setDestroyed() - } - } - - override fun newBlockEntity(pPos: BlockPos, pState: BlockState): BlockEntity? { - return CellTileEntity(pPos, pState) - } - - override fun onNeighborChange(blockState: BlockState?, world: LevelReader?, pos: BlockPos?, neighbor: BlockPos?) { - if (!(world?.isClientSide?: error("World was null"))) { - val cellEntity = world.getBlockEntity(pos?: error("Position was null")) as CellTileEntity - cellEntity.neighbourUpdated(neighbor?: error("Neighbor location is null")) - } - } - - // override this: - abstract fun getCellProvider() : ResourceLocation -} diff --git a/src/main/java/org/eln2/mc/common/blocks/CellTileEntity.kt b/src/main/java/org/eln2/mc/common/blocks/CellTileEntity.kt deleted file mode 100644 index c413eb79..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/CellTileEntity.kt +++ /dev/null @@ -1,483 +0,0 @@ -package org.eln2.mc.common.blocks - -import mcp.mobius.waila.api.IServerDataProvider -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.nbt.CompoundTag -import net.minecraft.server.level.ServerLevel -import net.minecraft.world.entity.LivingEntity -import net.minecraft.world.item.ItemStack -import net.minecraft.world.level.Level -import net.minecraft.world.level.block.HorizontalDirectionalBlock -import net.minecraft.world.level.block.entity.BlockEntity -import net.minecraft.world.level.block.state.BlockState -import org.eln2.mc.Eln2 -import org.eln2.mc.common.PlacementRotation -import org.eln2.mc.common.cell.* -import java.util.* -import kotlin.system.measureNanoTime - -class CellTileEntity(var pos : BlockPos, var state: BlockState): BlockEntity(BlockRegistry.CELL_BLOCK_ENTITY.get(), pos, state) { - private lateinit var manager : CellGraphManager - // Cell is not available on the client. - var cell : CellBase? = null - - private val serverLevel get() = level as ServerLevel - private var adjacentUpdateRequired = true - private var neighbourCache : ArrayList? = null - private lateinit var connectPredicate : ((dir : Direction) -> Boolean) - - /** - * Called by the block when one of our neighbours is updated. - * We use this to invalidate the adjacency cache. Next time we use it, we will query the world for the changes. - * @see adjacentUpdateRequired - */ - @Suppress("UNUSED_PARAMETER") // Will very likely be needed later and helps to know the name of the args. - fun neighbourUpdated(pos : BlockPos) { - adjacentUpdateRequired = true - } - - /** - * Called by the block when it is placed. - * For now, we are only processing this for the server. - * It will add our cell to an existing circuit, or join multiple existing circuits, or create a new one - * with ourselves. - */ - @Suppress("UNUSED_PARAMETER") // Will very likely be needed later and helps to know the name of the args. - fun setPlacedBy( - level : Level, - position : BlockPos, - blockState : BlockState, - entity : LivingEntity?, - itemStack : ItemStack, - cellProvider: CellProvider - ) { - if(level.isClientSide){ - return - } - - println("Cell is created at $position") - cell = cellProvider.create(position) - cell!!.tile = this - cell!!.id = cellProvider.registryName!! - - val placeDir = PlacementRotation (state.getValue(HorizontalDirectionalBlock.FACING)) - - Eln2.LOGGER.info("north <-> ${placeDir.getRelativeFromAbsolute(Direction.NORTH)}") - Eln2.LOGGER.info("south <-> ${placeDir.getRelativeFromAbsolute(Direction.SOUTH)}") - Eln2.LOGGER.info("east <-> ${placeDir.getRelativeFromAbsolute(Direction.EAST)}") - Eln2.LOGGER.info("west <-> ${placeDir.getRelativeFromAbsolute(Direction.WEST)}") - - connectPredicate = { - connectionPredicate(placeDir, it, cellProvider) - } - - manager = CellGraphManager.getFor(level as ServerLevel) - - registerIntoCircuit() - cell!!.setPlaced() - - setChanged() - - cell!!.graph.build() - } - - private fun connectionPredicate(place : PlacementRotation, dir : Direction, provider: CellProvider) : Boolean{ - val relative = place.getRelativeFromAbsolute(dir) - if(!provider.connectableDirections.contains(relative)){ - return false - } - - return provider.connectionPredicate(relative) - } - - /** - * Called by the block when it is broken. - * For now, we are only doing processing for the server. - */ - fun setDestroyed() { - if (cell == null) - return - cell!!.destroy() - - val adjacentTiles = HashSet(getAdjacentCellTilesFast()) - - if(adjacentTiles.isEmpty()){ - // we are alone - cell!!.graph.destroyAndRemove() - return - } - - if(adjacentTiles.count() == 1){ - adjacentTiles.first().cell!!.connections.remove(cell) - adjacentTiles.first().cell!!.update(connectionsChanged = true, graphChanged = false) - return - } - - fun isVisited(c : CellBase) : Boolean{ - return c.graph != cell!!.graph - } - - val queue = LinkedList() - val nanoTime = measureNanoTime { - - adjacentTiles.forEach{ - it.cell!!.connections.remove(cell) - } - - adjacentTiles.forEach { neighbour -> - if(isVisited(neighbour.cell!!)){ - return@forEach - } - - val results = CellGraph(UUID.randomUUID(), manager) - - queue.add(neighbour.cell!!) - - while(queue.isNotEmpty()){ - val element = queue.remove() - - if(isVisited(element)) { - continue - } - - element.graph = results - element.update(connectionsChanged = adjacentTiles.contains(element.tile), graphChanged = true) - results.addCell(element) - - element.connections.forEach{ child -> - queue.add(child) - } - } - - manager.addGraph(results) - results.build() - } - } - - Eln2.LOGGER.info("Remove nanoseconds: $nanoTime") - - cell!!.graph.destroyAndRemove() - } - - /** - * Called when the entity was placed into the world. - * we search all adjacent tile entities. If they have the same circuit, we will add our cell to their circuit. - * Else, we will delete their circuits and copy them over to the new one, that also includes us (we join the circuits together) - * If there are no adjacent, compatible cells, we create a new circuit with only ourselves - */ - fun registerIntoCircuit() { - val adjacent = getAdjacentCellTilesFast() - - if (adjacent.isNotEmpty()) { - // there are compatible adjacent cells. - val firstRemote = adjacent[0] - - if(adjacent.count() == 1) { - // we do not need to join multiple circuits. We can just add ourselves to that circuit. - addUsTo(firstRemote) - firstRemote.cell!!.connections.add(cell!!) - firstRemote.cell!!.update(connectionsChanged = true, graphChanged = false) - cell!!.connections = ArrayList(adjacent.map { it.cell }) - cell!!.update(connectionsChanged = true, graphChanged = true) - return - } - - // perf: if adjacent tiles are from the same circuit, we do not actually need to create a new circuit. - // we can just add ourselves to their circuit. - val areAllIdentical = areAllPartOfSameCircuit(adjacent) - - if(!areAllIdentical){ - concatenateCircuitAndAddUs(adjacent) - } else { - // all adjacent tiles are of the same circuit. we can join their circuit. - addUsTo(firstRemote) - - adjacent.forEach { - it.cell!!.connections.add(cell!!) - it.cell!!.update(connectionsChanged = true, graphChanged = false) - } - - cell!!.connections = ArrayList(adjacent.map { it.cell }) - cell!!.update(connectionsChanged = true, graphChanged = true) - } - - return - } - - // we are not adjacent to any components. - // we will build a circuit containing ourselves - - val graph = CellGraph(UUID.randomUUID(), manager) - graph.addCell(cell!!) - cell!!.graph = graph - manager.addGraph(graph) - cell!!.connections = ArrayList() - cell!!.update(connectionsChanged = true, graphChanged = true) - setChanged() - } - - /** - * Will set our cell's connections to the neighbours but exclude the provided cell. - * @param exclude The cell to exclude. - */ - // TODO: Do we want this still? - private fun setCellConnectionsToAdjacentButExclude(exclude : CellBase){ - val adjacent = getAdjacentCellsFast() - adjacent.remove(exclude) - cell!!.connections = adjacent - } - - /** - * Will check if the tiles provided all share the same circuit. - * @param tiles The tiles to check. - * @return True if the tiles are part of the same circuit. Otherwise, false. - */ - private fun areAllPartOfSameCircuit(tiles : List) : Boolean { - if (tiles.count() != 1) { - val first = tiles[0] - var result = true - - tiles.drop(1).forEach { - if(first.cell!!.graph.id != it.cell!!.graph.id){ - result = false - return@forEach - } - } - - return result - } - return true - } - - /** - * Called when we are not joining different graphs together. It will add us to adjacent entity's graph. - * @param adjacent The adjacent entity whose circuit we will add our cell to. - */ - private fun addUsTo(adjacent: CellTileEntity) { - val remoteGraph = adjacent.cell!!.graph - - // add ourselves to it - remoteGraph.addCell(cell!!) - - cell!!.graph = remoteGraph - - setChanged() - } - - /** - * Called when we are placed adjacently to 2 or more cells that are port of different graphs. - * @param adjacent The adjacent tiles to us. - */ - private fun concatenateCircuitAndAddUs(adjacent : ArrayList){ - // create a new circuit that contains all cells - - val newCircuit = CellGraph(UUID.randomUUID(), manager) - - val visitedGraphs = HashSet() - - val adjacentFast = HashSet(adjacent.map { it.cell }) - - adjacent.forEach{ - it.cell!!.connections.add(cell!!) - } - - adjacent.forEach { - // join cells from all circuits - val oldCircuit = it.cell!!.graph - - if(visitedGraphs.contains(oldCircuit)){ - // it shares a circuit with a tile we processed earlier - return@forEach - } - - visitedGraphs.add(oldCircuit) - - // copy all cells to new circuit - oldCircuit.copyTo(newCircuit) - oldCircuit.destroyAndRemove() - } - - newCircuit.addCell(cell!!) - - // so that connectionsChanged becomes true - adjacentFast.add(cell) - cell!!.connections = getAdjacentCellsFast() - cell!!.graph = newCircuit - - newCircuit.cells.forEach{ targetCell -> - targetCell.graph = newCircuit - targetCell.update(connectionsChanged = adjacentFast.contains(targetCell), graphChanged = true) - } - - manager.addGraph(newCircuit) - } - - /** - * Will get the direction of adjacent cells to us. Warning! this does not use a caching mechanism, it will query the world. - * @return The directions where adjacent cells are located. - */ - // TODO: Do we want this still? - fun getAdjacentSides() : LinkedList { - val result = LinkedList() - - fun getAndAdd(dir : Direction){ - if(getAdjacentTile(dir) != null && connectPredicate(dir)) result.add(dir) - } - - getAndAdd(Direction.NORTH) - getAndAdd(Direction.SOUTH) - getAndAdd(Direction.EAST) - getAndAdd(Direction.WEST) - - return result - } - - /** - * Will prepare a list of adjacent cells using the connection predicate. This uses a caching mechanism - * @see getAdjacentCellsFast - * @see neighbourCache - * in order to prevent querying the world when not necessary. - * @return A new array, containing the adjacent cells. - */ - private fun getAdjacentCellsFast() : ArrayList { - val adjacent = getAdjacentCellTilesFast() - - val result = ArrayList(adjacent.count()) - - adjacent.forEach { - result.add(it.cell!!) - } - - return result - } - - /** - * Will return the adjacent tile cache or query the world, apply the connection predicate, update the cache, and return it. - * @return The list of adjacent tiles. - * @see neighbourCache - * @see adjacentUpdateRequired - */ - private fun getAdjacentCellTilesFast() : ArrayList{ - return if (adjacentUpdateRequired || neighbourCache == null) { - adjacentUpdateRequired = false - - val nodes = ArrayList() - - fun getAndAdd(dir : Direction) { - val node = getAdjacentTile(dir) - if(node != null && node.canConnectFrom(this, dir)){ - nodes.add(node) - } - } - - getAndAdd(Direction.NORTH) - getAndAdd(Direction.SOUTH) - getAndAdd(Direction.EAST) - getAndAdd(Direction.WEST) - - nodes - } else neighbourCache!! - } - - /** - * Queries the world for the tile present in the specified direction. - * @param dir The direction to search in. - * @return The tile if found, or null if there is no tile at that position. - */ - private fun getAdjacentTile(dir : Direction) : CellTileEntity?{ - val level = getLevel()!! - val remotePos = pos.relative(dir) - val remoteEnt = level.getBlockEntity(remotePos) - - return remoteEnt as CellTileEntity? - } - - /** - * Applies the connection predicate for that direction. - * @param entity The entity we are checking. - * @param dir The direction towards entity. - * @return True if the connection is accepted. - */ - @Suppress("UNUSED_PARAMETER") // Will very likely be needed later and helps to know the name of the args. - private fun canConnectFrom(entity : CellTileEntity, dir : Direction) : Boolean { - return connectPredicate(dir.opposite) - - } - - override fun saveAdditional(pTag: CompoundTag) { - if (cell!!.hasGraph()) { - pTag.putString("GraphID", cell!!.graph.id.toString()) - } else { - Eln2.LOGGER.info("save additional: graph null") - } - } - - // remark: when the load method is called, the level is null. - // we need the level in order to get the cell manager. - // thus, we store the graph ID in this variable. - // the level becomes available when setLevel is called, - // so we load all our data there. - private lateinit var loadGraphId : UUID - - // attention: the level is null here - override fun load(pTag: CompoundTag) { - super.load(pTag) - - if (pTag.contains("GraphID")) { - loadGraphId = UUID.fromString(pTag.getString("GraphID"))!! - Eln2.LOGGER.info("tile load $pos") - // warning! level is not available at this stage! - // we override setLevel in order to load the rest of the data. - } - } - - override fun onChunkUnloaded() { - super.onChunkUnloaded() - - if (!level!!.isClientSide) { - cell!!.tileUnloaded() - - // GC reference tracking - cell!!.tile = null - } - } - - override fun setLevel(pLevel: Level) { - super.setLevel(pLevel) - - if (!level!!.isClientSide) { - manager = CellGraphManager.getFor(serverLevel) - - if (this::loadGraphId.isInitialized && manager.containsGraphWithId(loadGraphId)) { - // fetch graph with ID - val graph = manager.getGraphWithId(loadGraphId) - - // fetch cell instance - println("Loading cell at location $pos") - cell = graph.getCellAt(pos) - cell!!.tile = this - cell!!.tileLoaded() - - // fetch provider - val provider = CellRegistry.registry.getValue(cell!!.id)!! - - val absolute = blockState.getValue(HorizontalDirectionalBlock.FACING) - val placeDir = PlacementRotation(absolute) - - connectPredicate = { - connectionPredicate(placeDir, absolute, provider) - } - } - } - } - - fun getHudMap(): Map { - return if (cell == null) { - Eln2.LOGGER.warn("You're trying to reference cell in getHudMap from the client side, where cell is always null!") - mapOf() - } else { - cell!!.getHudMap() - } - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/ConduitBlock.kt b/src/main/java/org/eln2/mc/common/blocks/ConduitBlock.kt deleted file mode 100644 index ca27bca0..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/ConduitBlock.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.eln2.mc.common.blocks - -import net.minecraft.core.Direction -import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.RenderShape -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.block.state.properties.BlockStateProperties.* -import net.minecraft.world.level.material.Material -import net.minecraft.world.phys.shapes.BooleanOp -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape - - -class ConduitBlock(val predicate : ((dir : Direction) -> Boolean)) : Block(Properties.of(Material.STONE)) { - init { - registerDefaultState(stateDefinition.any() - .setValue(NORTH, false) - .setValue(SOUTH, false) - .setValue(EAST, false) - .setValue(WEST, false) - .setValue(UP, false) - .setValue(DOWN, false)) - } - - private val top = 16.0 - private val bottom = 0.0 - private val c = 8.0 - private val w = 2.0 - private val smallest = c - w - private val largest = c + w - - private val AABB = box(smallest, smallest, smallest, largest, largest, largest) - private val AABB_UP = box(smallest, smallest, smallest, largest, top, largest) - private val AABB_DOWN = box(smallest, bottom, smallest, largest, largest, largest) - private val AABB_NORTH = box(smallest, smallest, bottom, largest, largest, largest) - private val AABB_SOUTH = box(smallest, smallest, smallest, largest, largest, top) - private val AABB_WEST = box(bottom, smallest, smallest, largest, largest, largest) - private val AABB_EAST = box(smallest, smallest, smallest, top, largest, largest) - - - private fun createShape(state: BlockState): VoxelShape { - var shape = AABB - - if (predicate(Direction.NORTH)) shape = Shapes.joinUnoptimized(shape, AABB_NORTH, BooleanOp.OR) - if (predicate(Direction.SOUTH)) shape = Shapes.joinUnoptimized(shape, AABB_SOUTH, BooleanOp.OR) - if (predicate(Direction.WEST)) shape = Shapes.joinUnoptimized(shape, AABB_WEST, BooleanOp.OR) - if (predicate(Direction.EAST)) shape = Shapes.joinUnoptimized(shape, AABB_EAST, BooleanOp.OR) - if (predicate(Direction.UP)) shape = Shapes.joinUnoptimized(shape, AABB_UP, BooleanOp.OR) - if (predicate(Direction.DOWN)) shape = Shapes.joinUnoptimized(shape, AABB_DOWN, BooleanOp.OR) - - return shape - } - - override fun getRenderShape(pState: BlockState): RenderShape { - return RenderShape.MODEL - } - - - - -} diff --git a/src/main/java/org/eln2/mc/common/blocks/block/DcDcConverterBlock.kt b/src/main/java/org/eln2/mc/common/blocks/block/DcDcConverterBlock.kt deleted file mode 100644 index 46e428c5..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/block/DcDcConverterBlock.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.eln2.mc.common.blocks.block - -import net.minecraft.core.Direction -import net.minecraft.world.item.context.BlockPlaceContext -import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.HorizontalDirectionalBlock -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.block.state.StateDefinition -import net.minecraft.world.level.material.Material - -class DcDcConverterBlock: HorizontalDirectionalBlock(Properties.of(Material.STONE).noOcclusion()) { - init { - @Suppress("LeakingThis") - registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.NORTH)) - } - - override fun getStateForPlacement(pContext: BlockPlaceContext): BlockState? { - return super.defaultBlockState().setValue(FACING, pContext.horizontalDirection.opposite.counterClockWise) - } - - override fun createBlockStateDefinition(pBuilder: StateDefinition.Builder) { - super.createBlockStateDefinition(pBuilder) - pBuilder.add(FACING) - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/12vBatteryCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/12vBatteryCellBlock.kt deleted file mode 100644 index a694bb68..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/12vBatteryCellBlock.kt +++ /dev/null @@ -1,65 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.shapes.BooleanOp -import net.minecraft.world.phys.shapes.CollisionContext -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.extensions.VoxelShapeExtensions.align - -class `12vBatteryCellBlock`: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.`12V_BATTERY_CELL`.id - } - - override fun getCollisionShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - // TODO: This is deprecated - override fun getShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - companion object { - private val batteryBody = box(3.0, 0.0, 2.0, 13.0, 9.0, 14.0) - private val batteryRedLead = box(7.0, 0.0, 0.0, 9.0, 9.0, 2.0) - private val batteryBlackLead = box(7.0, 0.0, 14.0, 9.0, 9.0, 16.0) - - private val shape = Shapes.joinUnoptimized( - Shapes.joinUnoptimized(batteryRedLead, batteryBlackLead, BooleanOp.OR), batteryBody, BooleanOp.OR - ) - - private val cache = HashMap() - - fun getFor(state : BlockState) : VoxelShape { - return cache.computeIfAbsent(state){ - when(val facing = state.getValue(FACING)){ - Direction.NORTH -> shape - Direction.SOUTH -> shape - Direction.EAST -> shape.align(Direction.NORTH, Direction.EAST) - Direction.WEST -> shape.align(Direction.NORTH, Direction.WEST) - - else -> error("Unhandled dir: $facing") - } - } - } - } -} - diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/CapacitorCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/CapacitorCellBlock.kt deleted file mode 100644 index b0b94b41..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/CapacitorCellBlock.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.InteractionHand -import net.minecraft.world.InteractionResult -import net.minecraft.world.MenuProvider -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.level.Level -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.BlockHitResult -import net.minecraftforge.network.NetworkHooks -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.common.containers.CapacitorCellContainer - -class CapacitorCellBlock: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.CAPACITOR_CELL.id - } - - override fun use( - pState: BlockState, - pLevel: Level, - pPos: BlockPos, - pPlayer: Player, - pHand: InteractionHand, - pHit: BlockHitResult - ): InteractionResult { - if (!pLevel.isClientSide) { - val te = pLevel.getBlockEntity(pPos) - if (te is CellTileEntity) { - val containerProvider = object : MenuProvider { - override fun getDisplayName(): Component { - return TranslatableComponent("block.eln2.capacitor") - } - - override fun createMenu( - pContainerId: Int, - pInventory: Inventory, - pPlayer: Player - ): AbstractContainerMenu { - return CapacitorCellContainer(pContainerId, pInventory, pPlayer, te) - } - } - - NetworkHooks.openGui(pPlayer as ServerPlayer, containerProvider, te.pos) - return InteractionResult.SUCCESS - } - } - - return InteractionResult.SUCCESS - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/DiodeCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/DiodeCellBlock.kt deleted file mode 100644 index e9d3ecad..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/DiodeCellBlock.kt +++ /dev/null @@ -1,64 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.shapes.BooleanOp -import net.minecraft.world.phys.shapes.CollisionContext -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.extensions.VoxelShapeExtensions.align - -class DiodeCellBlock: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.DIODE_CELL.id - } - - override fun getCollisionShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - // TODO: This is deprecated - override fun getShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - companion object { - private val resistorBody = box(7.0, 0.0, 0.0, 9.0, 2.0, 4.0) - private val resistorLeadLeft = box(6.0, 0.0, 4.0, 10.0, 3.0, 12.0) - private val resistorLeadRight = box(7.0, 0.0, 12.0, 9.0, 2.0, 16.0) - - private val shape = Shapes.joinUnoptimized( - Shapes.joinUnoptimized(resistorLeadLeft, resistorLeadRight, BooleanOp.OR), resistorBody, BooleanOp.OR - ) - - private val cache = HashMap() - - fun getFor(state : BlockState) : VoxelShape{ - return cache.computeIfAbsent(state){ - when(val facing = state.getValue(FACING)){ - Direction.NORTH -> shape - Direction.SOUTH -> shape - Direction.EAST -> shape.align(Direction.NORTH, Direction.EAST) - Direction.WEST -> shape.align(Direction.NORTH, Direction.WEST) - - else -> error("Unhandled dir: $facing") - } - } - } - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/GroundCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/GroundCellBlock.kt deleted file mode 100644 index a0839f57..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/GroundCellBlock.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.resources.ResourceLocation -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.cell.CellRegistry - -class GroundCellBlock : CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.GROUND_CELL.id - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/InductorCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/InductorCellBlock.kt deleted file mode 100644 index 5349e61c..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/InductorCellBlock.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.InteractionHand -import net.minecraft.world.InteractionResult -import net.minecraft.world.MenuProvider -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.level.Level -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.BlockHitResult -import net.minecraftforge.network.NetworkHooks -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.common.containers.InductorCellContainer - -class InductorCellBlock: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.INDUCTOR_CELL.id - } - - override fun use( - pState: BlockState, - pLevel: Level, - pPos: BlockPos, - pPlayer: Player, - pHand: InteractionHand, - pHit: BlockHitResult - ): InteractionResult { - if (!pLevel.isClientSide) { - val te = pLevel.getBlockEntity(pPos) - if (te is CellTileEntity) { - val containerProvider = object : MenuProvider { - override fun getDisplayName(): Component { - return TranslatableComponent("block.eln2.inductor") - } - - override fun createMenu( - pContainerId: Int, - pInventory: Inventory, - pPlayer: Player - ): AbstractContainerMenu { - return InductorCellContainer(pContainerId, pInventory, pPlayer, te) - } - } - - NetworkHooks.openGui(pPlayer as ServerPlayer, containerProvider, te.pos) - return InteractionResult.SUCCESS - } - } - - return InteractionResult.SUCCESS - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/LightCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/LightCellBlock.kt deleted file mode 100644 index 8c9ce37f..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/LightCellBlock.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.shapes.BooleanOp -import net.minecraft.world.phys.shapes.CollisionContext -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.extensions.VoxelShapeExtensions.align - -class LightCellBlock: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.LIGHT_CELL.id - } - - override fun getCollisionShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - // TODO: This is deprecated - override fun getShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - companion object { - private val lightBody = box(5.0, 0.0, 5.0, 11.0, 4.0, 11.0) - private val lightLead = box(7.0, 0.0, 11.0, 9.0, 2.0, 16.0) - - private val shape = Shapes.joinUnoptimized(lightBody, lightLead, BooleanOp.OR) - - private val cache = HashMap() - - fun getFor(state : BlockState) : VoxelShape { - return cache.computeIfAbsent(state){ - when(val facing = state.getValue(FACING)){ - Direction.NORTH -> shape - Direction.SOUTH -> shape - Direction.EAST -> shape.align(Direction.NORTH, Direction.EAST) - Direction.WEST -> shape.align(Direction.NORTH, Direction.WEST) - - else -> error("Unhandled dir: $facing") - } - } - } - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/ResistorCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/ResistorCellBlock.kt deleted file mode 100644 index d13b7c5e..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/ResistorCellBlock.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.InteractionHand -import net.minecraft.world.InteractionResult -import net.minecraft.world.MenuProvider -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.level.Level -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.BlockHitResult -import net.minecraftforge.network.NetworkHooks -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.common.containers.ResistorCellContainer - -class ResistorCellBlock : CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.RESISTOR_CELL.id - } - - override fun use( - pState: BlockState, - pLevel: Level, - pPos: BlockPos, - pPlayer: Player, - pHand: InteractionHand, - pHit: BlockHitResult - ): InteractionResult { - if (!pLevel.isClientSide) { - val te = pLevel.getBlockEntity(pPos) - if (te is CellTileEntity) { - val containerProvider = object : MenuProvider { - override fun getDisplayName(): Component { - return TranslatableComponent("block.eln2.resistor") - } - - override fun createMenu( - pContainerId: Int, - pInventory: Inventory, - pPlayer: Player - ): AbstractContainerMenu { - return ResistorCellContainer(pContainerId, pInventory, pPlayer, te) - } - } - - NetworkHooks.openGui(pPlayer as ServerPlayer, containerProvider, te.pos) - return InteractionResult.SUCCESS - } - } - - return InteractionResult.SUCCESS - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/SolarLightCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/SolarLightCellBlock.kt deleted file mode 100644 index 12be882d..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/SolarLightCellBlock.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.shapes.BooleanOp -import net.minecraft.world.phys.shapes.CollisionContext -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.extensions.VoxelShapeExtensions.align - -class SolarLightCellBlock: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.SOLAR_LIGHT_CELL.id - } - - override fun getCollisionShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - // TODO: This is deprecated - override fun getShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - companion object { - private val lightPillar = box(7.0, 0.0, 7.0, 9.0, 8.0, 9.0) - private val lightHead = box(5.0, 8.0, 5.0, 11.0, 11.0, 11.0) - - private val shape = Shapes.joinUnoptimized(lightPillar, lightHead, BooleanOp.OR) - - private val cache = HashMap() - - fun getFor(state : BlockState) : VoxelShape { - return cache.computeIfAbsent(state){ - when(val facing = state.getValue(FACING)){ - Direction.NORTH -> shape - Direction.SOUTH -> shape - Direction.EAST -> shape.align(Direction.NORTH, Direction.EAST) - Direction.WEST -> shape.align(Direction.NORTH, Direction.WEST) - - else -> error("Unhandled dir: $facing") - } - } - } - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/SolarPanelCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/SolarPanelCellBlock.kt deleted file mode 100644 index 928110a1..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/SolarPanelCellBlock.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.shapes.BooleanOp -import net.minecraft.world.phys.shapes.CollisionContext -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.extensions.VoxelShapeExtensions.align - -class SolarPanelCellBlock: CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.SOLAR_PANEL_CELL.id - } - - override fun getCollisionShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - // TODO: This is deprecated - override fun getShape( - pState: BlockState, - pLevel: BlockGetter, - pPos: BlockPos, - pContext: CollisionContext - ): VoxelShape { - return getFor(pState) - } - - companion object { - private val solar_panel = box(0.0, 0.0, 0.0, 16.0, 2.0, 16.0) - private val shape = solar_panel - - private val cache = HashMap() - - fun getFor(state : BlockState) : VoxelShape { - return cache.computeIfAbsent(state){ - when(val facing = state.getValue(FACING)){ - Direction.NORTH -> shape - Direction.SOUTH -> shape - Direction.EAST -> shape.align(Direction.NORTH, Direction.EAST) - Direction.WEST -> shape.align(Direction.NORTH, Direction.WEST) - - else -> error("Unhandled dir: $facing") - } - } - } - } -} - diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/VoltageSourceCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/VoltageSourceCellBlock.kt deleted file mode 100644 index 703cd4c9..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/VoltageSourceCellBlock.kt +++ /dev/null @@ -1,62 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import com.google.common.collect.ImmutableMap -import net.minecraft.core.BlockPos -import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TranslatableComponent -import net.minecraft.resources.ResourceLocation -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.InteractionHand -import net.minecraft.world.InteractionResult -import net.minecraft.world.MenuProvider -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.level.Level -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.BlockHitResult -import net.minecraftforge.network.NetworkHooks -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.CellRegistry -import org.eln2.mc.common.containers.VoltageSourceCellContainer - - -class VoltageSourceCellBlock : CellBlockBase() { - override fun getCellProvider(): ResourceLocation { - return CellRegistry.VOLTAGE_SOURCE_CELL.id - } - - override fun use( - pState: BlockState, - pLevel: Level, - pPos: BlockPos, - pPlayer: Player, - pHand: InteractionHand, - pHit: BlockHitResult - ): InteractionResult { - if (!pLevel.isClientSide) { - val te = pLevel.getBlockEntity(pPos) - if (te is CellTileEntity) { - val containerProvider = object : MenuProvider { - override fun getDisplayName(): Component { - return TranslatableComponent("block.eln2.voltage_source") - } - - override fun createMenu( - pContainerId: Int, - pInventory: Inventory, - pPlayer: Player - ): AbstractContainerMenu { - return VoltageSourceCellContainer(pContainerId, pInventory, pPlayer, te) - } - } - - NetworkHooks.openGui(pPlayer as ServerPlayer, containerProvider, te.pos) - return InteractionResult.SUCCESS - } - } - - return InteractionResult.SUCCESS - } -} diff --git a/src/main/java/org/eln2/mc/common/blocks/cell/WireCellBlock.kt b/src/main/java/org/eln2/mc/common/blocks/cell/WireCellBlock.kt deleted file mode 100644 index 6f1ea4b7..00000000 --- a/src/main/java/org/eln2/mc/common/blocks/cell/WireCellBlock.kt +++ /dev/null @@ -1,142 +0,0 @@ -package org.eln2.mc.common.blocks.cell - -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.Level -import net.minecraft.world.level.LevelReader -import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.HorizontalDirectionalBlock -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.block.state.StateDefinition -import net.minecraft.world.level.block.state.properties.DirectionProperty -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.phys.shapes.CollisionContext -import net.minecraft.world.phys.shapes.VoxelShape -import org.eln2.mc.common.blocks.CellBlockBase -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.CellRegistry - -class WireCellBlock : CellBlockBase() { - - lateinit var connect_east: BooleanProperty - lateinit var connect_west: BooleanProperty - lateinit var connect_north: BooleanProperty - lateinit var connect_south: BooleanProperty - - - init { - registerDefaultState(stateDefinition.any().setValue(connect_east, false).setValue(connect_north, false).setValue(connect_south, false).setValue(connect_west, false)) - } - - - override fun getCellProvider(): ResourceLocation { - return CellRegistry.WIRE_CELL.id - } - - override fun getCollisionShape(pState: BlockState, pLevel: BlockGetter, pPos: BlockPos, pContext: CollisionContext): VoxelShape { - return Block.box(0.0, 0.0, 0.0, 16.0, 1.0, 16.0) - } - - override fun getShape(pState: BlockState, pLevel: BlockGetter, pPos: BlockPos, pContext: CollisionContext): VoxelShape { - return Block.box(0.0, 0.0, 0.0, 16.0, 2.0, 16.0) - } - - override fun onPlace(pState: BlockState, pLevel: Level, pPos: BlockPos, pOldState: BlockState, pIsMoving: Boolean) { - super.onPlace(pState, pLevel, pPos, pOldState, pIsMoving) - - // get blocks around and call nechang - for (x in -1..1) { - for (z in -1..1) { - if (x == 0 && z == 0) continue - neChang(pLevel, pPos, BlockPos(pPos.x + x, pPos.y, pPos.z + z)) - } - } - } - - override fun createBlockStateDefinition(pBuilder: StateDefinition.Builder) { - super.createBlockStateDefinition(pBuilder) - - connect_east = BooleanProperty.create("connect_east") - connect_north = BooleanProperty.create("connect_north") - connect_south = BooleanProperty.create("connect_south") - connect_west = BooleanProperty.create("connect_west") - - pBuilder.add(connect_east, connect_north, connect_south, connect_west) - } - - - - fun neChang(level: Level, pos: BlockPos, neighbor: BlockPos) { - val blockEntity = level.getBlockEntity(neighbor ?: error("Neighbor position was null")) - if(blockEntity != null) { - - // check if the blockentity is from this mod - if(blockEntity is CellTileEntity) { - // get the direction of the neighbor from us - val direction = Direction.fromNormal(neighbor.subtract(pos)) - - if(direction?.equals(Direction.EAST) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_east, true)) - } - if(direction?.equals(Direction.NORTH) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_north, true)) - } - if(direction?.equals(Direction.SOUTH) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_south, true)) - } - if(direction?.equals(Direction.WEST) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_west, true)) - } - } else { - // not a cell tile entity - val direction = Direction.fromNormal(neighbor.subtract(pos)) - - if(direction?.equals(Direction.EAST) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_east, false)) - } - if(direction?.equals(Direction.NORTH) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_north, false)) - } - if(direction?.equals(Direction.SOUTH) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_south, false)) - } - if(direction?.equals(Direction.WEST) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_west, false)) - } - } - } else { - // not a cell tile entity - - val direction = Direction.fromNormal(neighbor.subtract(pos)) - - if(direction?.equals(Direction.EAST) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_east, false)) - } - if(direction?.equals(Direction.NORTH) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_north, false)) - } - if(direction?.equals(Direction.SOUTH) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_south, false)) - } - if(direction?.equals(Direction.WEST) == true) { - level.setBlockAndUpdate(pos, level.getBlockState(pos).setValue(connect_west, false)) - } - } - } - override fun onNeighborChange(blockState: BlockState?, world: LevelReader?, pos: BlockPos?, neighbor: BlockPos?) { - - var level = world as Level - - if (world != null && pos != null) { - if (!(world?.isClientSide?: error("World was null"))) { - if (neighbor != null && neighbor != pos) { - neChang(level, pos, neighbor) - } - } - } - - super.onNeighborChange(blockState, world, pos, neighbor) - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/CellBase.kt b/src/main/java/org/eln2/mc/common/cell/CellBase.kt deleted file mode 100644 index 5d9277f9..00000000 --- a/src/main/java/org/eln2/mc/common/cell/CellBase.kt +++ /dev/null @@ -1,75 +0,0 @@ -package org.eln2.mc.common.cell - -import net.minecraft.core.BlockPos -import net.minecraft.resources.ResourceLocation -import org.ageseries.libage.sim.electrical.mna.component.Component -import org.eln2.mc.common.blocks.CellTileEntity - -class ComponentInfo(val component: Component, val index : Int) - -abstract class CellBase(val pos : BlockPos) { - lateinit var id : ResourceLocation - lateinit var graph: CellGraph - lateinit var connections : ArrayList - var tile : CellTileEntity? = null - - /** - * Called when the tile entity is being unloaded. - * After this method is called, the field will be null. - */ - open fun tileUnloaded(){} - - /** - * Called when the tile entity is being loaded. - * The field is assigned before this is called. - */ - open fun tileLoaded(){} - - fun hasGraph() : Boolean { return this::graph.isInitialized } - - /** - * Called when the graph manager completed loading this cell from the disk. - */ - open fun completeDiskLoad(){} - - /** - * Called when the tile entity placing is complete. - */ - open fun setPlaced(){} - - /** - * Called when the tile entity is destroyed. - */ - open fun destroy() { - graph.removeCell(this) - } - - /** - * Called when the graph and/or neighbouring cells are updated. This method is called after completeDiskLoad and setPlaced - * @param connectionsChanged True if the neighbouring cells changed. - * @param graphChanged True if the graph that owns this cell has been updated. - */ - open fun update(connectionsChanged : Boolean, graphChanged : Boolean){} - - /** - * Called to get a map of key value pairs of circuit properties for the WAILA clone and the plotter. - * @return Map of circuit property (eg, "voltage") and value (eg, "5.0V") - */ - abstract fun getHudMap(): Map - - /** - * This method is called before the Circuit is being rebuilt. - */ - abstract fun clearForRebuild() - - /** - * This method is used to return the component and the pin for a remote cell to connect to. - */ - abstract fun componentForNeighbour(neighbour : CellBase) : ComponentInfo - - /** - * This method is called after each cell's clearForRebuild method has been called. - * It must be used to create the circuit's connections. - */ - abstract fun buildConnections() -} diff --git a/src/main/java/org/eln2/mc/common/cell/CellGraph.kt b/src/main/java/org/eln2/mc/common/cell/CellGraph.kt deleted file mode 100644 index 4a99d055..00000000 --- a/src/main/java/org/eln2/mc/common/cell/CellGraph.kt +++ /dev/null @@ -1,151 +0,0 @@ -package org.eln2.mc.common.cell - -import net.minecraft.core.BlockPos -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.resources.ResourceLocation -import org.ageseries.libage.sim.electrical.mna.Circuit -import org.eln2.mc.Eln2 -import org.eln2.mc.extensions.NbtExtensions.getBlockPos -import org.eln2.mc.extensions.NbtExtensions.putBlockPos -import java.util.* -import kotlin.system.measureNanoTime - -class CellGraph(val id : UUID, val manager : CellGraphManager) { - val cells = ArrayList() - private val posCells = HashMap() - - lateinit var circuit : Circuit - val hasCircuit get() = this::circuit.isInitialized - var successful = false - private set - - var latestSolveTime = 0L - - fun serverTick(){ - if(hasCircuit){ - latestSolveTime = measureNanoTime { - successful = circuit.step(0.05) - } - } - } - - fun build() { - circuit = Circuit() - - cells.forEach{ cell -> - cell.clearForRebuild() - } - - cells.forEach { cell -> - cell.buildConnections() - } - - Eln2.LOGGER.info("Built circuit! component count: ${circuit.components.count()}, graph cell count: ${cells.count()}") - } - - fun getCellAt(pos: BlockPos): CellBase { - return posCells[pos] ?: error("Could not find cell at $pos!") - } - - fun removeCell(cell : CellBase) { - cells.remove(cell) - posCells.remove(cell.pos) - manager.setDirty() - } - - fun addCell(cell : CellBase) { - cells.add(cell) - posCells[cell.pos] = cell - manager.setDirty() - } - - fun copyTo(graph : CellGraph){ - graph.cells.addAll(cells) - manager.setDirty() - } - - fun destroyAndRemove() { - manager.removeGraph(this) - manager.setDirty() - } - - fun toNbt() : CompoundTag { - val circuitCompound = CompoundTag() - circuitCompound.putUUID("ID", id) - - val cellListTag = ListTag() - - cells.forEach{ cell -> - val cellTag = CompoundTag() - val connectionsTag = ListTag() - - cell.connections.forEach { conn-> - val connCompound = CompoundTag() - connCompound.putBlockPos("Position", conn.pos) - connectionsTag.add(connCompound) - } - - cellTag.putBlockPos("Position", cell.pos) - cellTag.putString("ID", cell.id.toString()) - cellTag.put("Connections", connectionsTag) - - cellListTag.add(cellTag) - } - - circuitCompound.put("Cells", cellListTag) - - return circuitCompound - } - - companion object { - fun fromNbt(graphCompound : CompoundTag, manager : CellGraphManager) : CellGraph { - val id = graphCompound.getUUID("ID") - val result = CellGraph(id, manager) - val cellListTag = graphCompound.get("Cells") as ListTag? - ?: // no cells are to be loaded - return result - - // used to assign the connections after all cells have been loaded - val cellConnections = HashMap>() - - cellListTag.forEach{ cellNbt -> - val cellCompound = cellNbt as CompoundTag - val pos = cellCompound.getBlockPos("Position") - val cellId = ResourceLocation.tryParse(cellCompound.getString("ID"))!! - - val connectionPositions = ArrayList() - val connectionsTag = cellCompound.get("Connections") as ListTag - - connectionsTag.forEach { - val connectionCompound = it as CompoundTag - val connectionPos = connectionCompound.getBlockPos("Position") - connectionPositions.add(connectionPos) - } - - val cell = CellRegistry.registry.getValue(cellId)!!.create(pos) - - cellConnections[cell] = connectionPositions - - cell.id = cellId - result.addCell(cell) - } - - // now assign all connections and the graph - - cellConnections.forEach{ - val cell = it.component1() - val connectionPositions = it.component2() - val connections = ArrayList(connectionPositions.map { pos -> result.getCellAt(pos) }) - - // now set graph and connection - cell.graph = result - cell.connections = connections - cell.update(connectionsChanged = true, graphChanged = true) - cell.completeDiskLoad() - } - - return result - } - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/CellGraphManager.kt b/src/main/java/org/eln2/mc/common/cell/CellGraphManager.kt deleted file mode 100644 index f5c4885b..00000000 --- a/src/main/java/org/eln2/mc/common/cell/CellGraphManager.kt +++ /dev/null @@ -1,81 +0,0 @@ -package org.eln2.mc.common.cell - -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.server.level.ServerLevel -import net.minecraft.world.level.Level -import net.minecraft.world.level.saveddata.SavedData -import org.eln2.mc.Eln2 -import java.lang.IndexOutOfBoundsException -import java.util.* - -class CellGraphManager(val level : Level) : SavedData() { - val graphs = HashMap() - - fun tickAll(){ - graphs.values.forEach{ it.serverTick() } - } - - fun containsGraphWithId(id : UUID) : Boolean{ - return graphs.containsKey(id) - } - - fun addGraph(graph : CellGraph) { - graphs[graph.id] = graph - setDirty() - } - - fun removeGraph(graph : CellGraph) { - graphs.remove(graph.id) - Eln2.LOGGER.info("Removed graph ${graph.id}!") - setDirty() - } - - override fun save(tag: CompoundTag): CompoundTag { - val graphListTag = ListTag() - - graphs.values.forEach { graph-> - graphListTag.add(graph.toNbt()) - } - - tag.put("Graphs", graphListTag) - Eln2.LOGGER.info("Wrote ${graphs.count()} graphs to disk.") - return tag - } - - fun getGraphWithId(id : UUID) : CellGraph{ - return graphs[id]?: throw IndexOutOfBoundsException("Graph ID was not found in the cell graph ${graphs}: $id") - } - - companion object { - private fun load(tag : CompoundTag, level : ServerLevel) : CellGraphManager { - val manager = CellGraphManager(level) - - val graphListTag = tag.get("Graphs") as ListTag? - - if(graphListTag == null){ - Eln2.LOGGER.info("No nodes to be loaded!") - return manager - } - - graphListTag.forEach { circuitNbt -> - val graphCompound = circuitNbt as CompoundTag - val graph = CellGraph.fromNbt(graphCompound, manager) - if(graph.cells.isEmpty()){ - Eln2.LOGGER.error("Loaded circuit with no cells!") - return@forEach - } - - manager.addGraph(graph) - Eln2.LOGGER.info("Loaded ${graph.cells.count()} cells for ${graph.id}!") - graph.build() - } - - return manager - } - - fun getFor(level : ServerLevel) : CellGraphManager { - return level.dataStorage.computeIfAbsent({ load(it, level) }, { CellGraphManager(level) }, "CellManager") - } - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/CellProvider.kt b/src/main/java/org/eln2/mc/common/cell/CellProvider.kt deleted file mode 100644 index bd1eb684..00000000 --- a/src/main/java/org/eln2/mc/common/cell/CellProvider.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.eln2.mc.common.cell - -import net.minecraft.core.BlockPos -import net.minecraftforge.registries.ForgeRegistryEntry -import org.eln2.mc.common.RelativeRotationDirection - -abstract class CellProvider : ForgeRegistryEntry() { - val connectableDirections = HashSet() - - /** - * Used to create a new instance of the cell. Called when the cell block is placed - * or when the cell manager is loading cells from the disk. - * @return Unique instance of the cell. If the cell is being created by the block, the setPlaced method will be called. - * @see CellBase.setPlaced - */ - abstract fun create(pos : BlockPos) : CellBase - - /** - * Used to check if a cell is valid for connection. - * @return True if the connection is accepted. Otherwise, false. - */ - abstract fun connectionPredicate(dir : RelativeRotationDirection) : Boolean -} diff --git a/src/main/java/org/eln2/mc/common/cell/CellRegistry.kt b/src/main/java/org/eln2/mc/common/cell/CellRegistry.kt deleted file mode 100644 index d8eeba2d..00000000 --- a/src/main/java/org/eln2/mc/common/cell/CellRegistry.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.eln2.mc.common.cell - -import net.minecraft.resources.ResourceLocation -import net.minecraftforge.eventbus.api.IEventBus -import net.minecraftforge.eventbus.api.SubscribeEvent -import net.minecraftforge.fml.common.Mod -import net.minecraftforge.registries.* -import org.eln2.mc.Eln2 -import org.eln2.mc.Eln2.LOGGER -import org.eln2.mc.common.cell.providers.FourPinCellProvider -import org.eln2.mc.common.cell.providers.NoPinCellProvider -import org.eln2.mc.common.cell.providers.TwoPinCellProvider -import org.eln2.mc.common.cell.types.* -import java.util.function.Supplier - -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -object CellRegistry { - private val CELLS = DeferredRegister.create(CellProvider::class.java, Eln2.MODID) - private var REGISTRY : Supplier?>? = null - val registry get() = REGISTRY!!.get()!! - - val RESISTOR_CELL = register("resistor", TwoPinCellProvider { ResistorCell(it) }) - val WIRE_CELL = register("wire", FourPinCellProvider { WireCell(it) }) - val VOLTAGE_SOURCE_CELL = register("voltage_source", FourPinCellProvider { VoltageSourceCell(it) }) - val GROUND_CELL = register("ground", FourPinCellProvider { GroundCell(it) }) - val CAPACITOR_CELL = register("capacitor", TwoPinCellProvider { CapacitorCell(it) }) - val INDUCTOR_CELL = register("inductor", TwoPinCellProvider { InductorCell(it) }) - val DIODE_CELL = register("diode", TwoPinCellProvider { DiodeCell(it) }) - val `12V_BATTERY_CELL` = register("12v_battery", TwoPinCellProvider { `12VBatteryCell`(it) }) - val LIGHT_CELL = register("light", FourPinCellProvider { LightCell(it) }) - val SOLAR_LIGHT_CELL = register("solar_light", NoPinCellProvider { SolarLightCell(it) }) - val SOLAR_PANEL_CELL = register("solar_panel", TwoPinCellProvider {SolarPanelCell(it)}) - - fun setup(bus : IEventBus) { - CELLS.register(bus) - LOGGER.info("Prepared cell registry.") - } - - @SubscribeEvent - fun createRegistry(event : NewRegistryEvent) { - val reg = RegistryBuilder() - reg.setName(ResourceLocation(Eln2.MODID, "cells")) - reg.type = CellProvider::class.java - REGISTRY = event.create(reg) - LOGGER.info("Created cell registry!") - } - - private fun register(id : String, provider: CellProvider) : RegistryObject { - return CELLS.register(id) { provider } - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/ISingleElementGuiCell.kt b/src/main/java/org/eln2/mc/common/cell/ISingleElementGuiCell.kt deleted file mode 100644 index 10e48a3c..00000000 --- a/src/main/java/org/eln2/mc/common/cell/ISingleElementGuiCell.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.eln2.mc.common.cell - -/** - * ISingleElementGuiCell is a Cell with a single numerical value that will be synced to the client for GUI use - */ -interface ISingleElementGuiCell { - - /** - * Get the current value from the electrical component for sending to the client - */ - fun getGuiValue(): N - - /** - * Set the current value to a number provided by the client - */ - fun setGuiValue(value: N) - -} diff --git a/src/main/java/org/eln2/mc/common/cell/providers/FourPinCellProvider.kt b/src/main/java/org/eln2/mc/common/cell/providers/FourPinCellProvider.kt deleted file mode 100644 index 42db3bb0..00000000 --- a/src/main/java/org/eln2/mc/common/cell/providers/FourPinCellProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.eln2.mc.common.cell.providers - -import net.minecraft.core.BlockPos -import org.eln2.mc.common.RelativeRotationDirection -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.CellProvider - -class FourPinCellProvider(val factory : ((pos : BlockPos) -> CellBase)) : CellProvider() { - init { - connectableDirections.addAll(listOf( - RelativeRotationDirection.Front, - RelativeRotationDirection.Back, - RelativeRotationDirection.Left, - RelativeRotationDirection.Right - )) - } - - override fun create(pos: BlockPos): CellBase { - return factory(pos) - } - - override fun connectionPredicate(dir: RelativeRotationDirection): Boolean { - return true - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/providers/NoPinCellProvider.kt b/src/main/java/org/eln2/mc/common/cell/providers/NoPinCellProvider.kt deleted file mode 100644 index 201cc73b..00000000 --- a/src/main/java/org/eln2/mc/common/cell/providers/NoPinCellProvider.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.eln2.mc.common.cell.providers - -import net.minecraft.core.BlockPos -import org.eln2.mc.common.RelativeRotationDirection -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.CellProvider - -class NoPinCellProvider(val factory : ((pos : BlockPos) -> CellBase)) : CellProvider() { - override fun create(pos: BlockPos): CellBase { - return factory(pos) - } - - override fun connectionPredicate(dir: RelativeRotationDirection): Boolean { - return true - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/providers/TwoPinCellProvider.kt b/src/main/java/org/eln2/mc/common/cell/providers/TwoPinCellProvider.kt deleted file mode 100644 index 3a3a932a..00000000 --- a/src/main/java/org/eln2/mc/common/cell/providers/TwoPinCellProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.eln2.mc.common.cell.providers - -import net.minecraft.core.BlockPos -import org.eln2.mc.Eln2 -import org.eln2.mc.common.RelativeRotationDirection -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.CellProvider - -class TwoPinCellProvider(val factory : ((pos : BlockPos) -> CellBase)) : CellProvider() { - init { - connectableDirections.addAll(listOf( - RelativeRotationDirection.Front, - RelativeRotationDirection.Back - )) - } - - override fun create(pos: BlockPos): CellBase { - return factory(pos) - } - - override fun connectionPredicate(dir: RelativeRotationDirection): Boolean { - Eln2.LOGGER.info("DIR: $dir") - return true - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/12VBatteryCell.kt b/src/main/java/org/eln2/mc/common/cell/types/12VBatteryCell.kt deleted file mode 100644 index 813098e5..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/12VBatteryCell.kt +++ /dev/null @@ -1,75 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.ageseries.libage.sim.electrical.mna.component.VoltageSource -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText - -class `12VBatteryCell`(pos : BlockPos) : CellBase(pos) { - - /* - * V -> local voltage source. - * C -> remote components. - * - * C V C - */ - - private lateinit var source : VoltageSource - - override fun clearForRebuild() { - source = VoltageSource() - source.potential = 12.5 - neighbourToResistorLookup.clear() - } - - // TODO: Battery needs a + and - terminal. Currently, it's just implicitly grounded because I can't get that to work. - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - - return ComponentInfo(neighbourToResistorLookup.computeIfAbsent(neighbour) { - val resistor = Resistor() - resistor.resistance = 0.001 - circuit.add(resistor) - resistor - }, 1) // pin 1 will be connected to the remote cell - } - - override fun buildConnections() { - val circuit = graph.circuit - circuit.add(source) - source.ground(0) - - connections.forEach { remoteCell -> - val localResistor = componentForNeighbour(remoteCell).component // get local resistor - localResistor.connectToPinOf(1, remoteCell.componentForNeighbour(this)) // connect local resistor to remote component - localResistor.connect(0, source, 1) // connect local resistor to our voltage source - } - } - - private val neighbourToResistorLookup = HashMap() - - override fun getHudMap(): Map { - val voltage: String = ValueText.valueText(source.potential, UnitType.VOLT) - var current: String = ValueText.valueText(0.0, UnitType.AMPERE) - var power: String = ValueText.valueText(0.0, UnitType.WATT) - val map = mutableMapOf() - - try { - current = ValueText.valueText(source.current, UnitType.AMPERE) - power = ValueText.valueText(source.potential * source.current, UnitType.WATT) - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["power"] = power - - return map - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/CapacitorCell.kt b/src/main/java/org/eln2/mc/common/cell/types/CapacitorCell.kt deleted file mode 100644 index f3066102..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/CapacitorCell.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Capacitor -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.common.cell.ISingleElementGuiCell -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText.valueText - -class CapacitorCell(pos: BlockPos) : CellBase(pos), ISingleElementGuiCell { - lateinit var capacitor: Capacitor - var added = false - - override fun clearForRebuild() { - capacitor = Capacitor() - capacitor.capacitance = 1.0E-6 - added = false - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - if(!added) { - circuit.add(capacitor) - added = true - } - return ComponentInfo(capacitor, connections.indexOf(neighbour)) - } - - override fun buildConnections() { - connections.forEach{remoteCell -> - val localInfo = componentForNeighbour(remoteCell) - localInfo.component.connectToPinOf(localInfo.index, remoteCell.componentForNeighbour(this)) - } - } - - override fun getHudMap(): Map { - var voltage: String = valueText(0.0, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - val capacitance: String = valueText(capacitor.capacitance, UnitType.FARAD) - var joules: String = valueText(0.0, UnitType.JOULE) - val map = mutableMapOf() - - try { - current = valueText(capacitor.current, UnitType.AMPERE) - joules = valueText(capacitor.energy, UnitType.JOULE) - voltage = capacitor.pins.joinToString(", ") { valueText(it.node?.potential ?: 0.0, UnitType.VOLT) } - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["capacitance"] = capacitance - map["energy"] = joules - - return map - } - - override fun getGuiValue(): Double { - return capacitor.capacitance - } - - override fun setGuiValue(value: Double) { - capacitor.capacitance = value - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/DiodeCell.kt b/src/main/java/org/eln2/mc/common/cell/types/DiodeCell.kt deleted file mode 100644 index f006e4e2..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/DiodeCell.kt +++ /dev/null @@ -1,59 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.IdealDiode -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText -import org.eln2.mc.utility.ValueText.valueText - -class DiodeCell(pos : BlockPos): CellBase(pos) { - lateinit var diode : IdealDiode - var added = false - - override fun clearForRebuild() { - diode = IdealDiode() - added = false - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - if(!added) { - circuit.add(diode) - added = true - } - return ComponentInfo(diode, connections.indexOf(neighbour)) - } - - override fun buildConnections() { - connections.forEach{remoteCell -> - val localInfo = componentForNeighbour(remoteCell) - localInfo.component.connectToPinOf(localInfo.index, remoteCell.componentForNeighbour(this)) - } - } - - override fun getHudMap(): Map { - var voltage: String = valueText(0.0, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - var mode: String? = null - val map = mutableMapOf() - - try { - // TODO: This feature (mode) should be exposed in libage as an enum. It also needs to be translated on the client. - mode = if (diode.resistance == diode.minimumResistance) "Forward Bias Mode (conducting)" else "Reverse Bias Mode (blocking)" - current = valueText(diode.current, UnitType.AMPERE) - voltage = diode.pins.joinToString(", ") { valueText(it.node?.potential ?: 0.0, UnitType.VOLT) } - - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - if (mode != null)map["mode"] = mode - - return map - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/GroundCell.kt b/src/main/java/org/eln2/mc/common/cell/types/GroundCell.kt deleted file mode 100644 index 6c5afb64..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/GroundCell.kt +++ /dev/null @@ -1,69 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText -import org.eln2.mc.utility.ValueText.valueText - -class GroundCell(pos : BlockPos) : CellBase(pos) { - - /* R -> local resistors. Their first pin is grounded. - * C -> remote components. The second pin of the local resistors is used for them. - * - * C - * R - * C R G R C - * R - * C - */ - - override fun clearForRebuild() { - neighbourToResistorLookup.clear() - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - - return ComponentInfo(neighbourToResistorLookup.computeIfAbsent(neighbour) { - val resistor = Resistor() - resistor.resistance = 0.001 - circuit.add(resistor) - resistor - }, 1) // pin 1 will be connected to the remote components - } - - override fun buildConnections() { - connections.forEach{ adjacentCell -> - val resistor = componentForNeighbour(adjacentCell).component - resistor.ground(0) // ground one pin of our resistor - // then connect the other pin to them - resistor.connectToPinOf(1, adjacentCell.componentForNeighbour(this)) - } - } - - private val neighbourToResistorLookup = HashMap() - - override fun getHudMap(): Map { - val voltage: String = valueText(0.0, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - val map = mutableMapOf() - - try { - val currents = connections.map { (componentForNeighbour(it).component as Resistor).current } - val currentString = currents.joinToString(", ") { valueText(it, UnitType.AMPERE) } - if (currentString.isNotEmpty()) - current = currentString - } catch (_: Exception) { - // don't care, sim is in a bad/unready state - } - - map["voltage"] = voltage - map["current"] = current - - return map - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/InductorCell.kt b/src/main/java/org/eln2/mc/common/cell/types/InductorCell.kt deleted file mode 100644 index a1d22619..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/InductorCell.kt +++ /dev/null @@ -1,73 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Inductor -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.common.cell.ISingleElementGuiCell -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText.valueText - -class InductorCell(pos: BlockPos) : CellBase(pos), ISingleElementGuiCell { - lateinit var inductor: Inductor - var added = false - - override fun clearForRebuild() { - inductor = Inductor() - inductor.inductance = 0.1 - added = false - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - if(!added) { - circuit.add(inductor) - added = true - } - return ComponentInfo(inductor, connections.indexOf(neighbour)) - } - - override fun buildConnections() { - connections.forEach{remoteCell -> - val localInfo = componentForNeighbour(remoteCell) - localInfo.component.connectToPinOf(localInfo.index, remoteCell.componentForNeighbour(this)) - } - } - - override fun getHudMap(): Map { - var voltage: String = valueText(0.0, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - val inductance: String = valueText(inductor.inductance, UnitType.HENRY) - var joules: String = valueText(0.0, UnitType.JOULE) - val map = mutableMapOf() - - try { - current = valueText(inductor.current, UnitType.AMPERE) - joules = valueText(inductor.energy, UnitType.JOULE) - voltage = inductor.pins.joinToString(", ") { - valueText( - it.node?.potential ?: 0.0, - UnitType.VOLT - ) - } - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["inductance"] = inductance - map["energy"] = joules - - return map - } - - override fun getGuiValue(): Double { - return inductor.inductance - } - - override fun setGuiValue(value: Double) { - inductor.inductance = value - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/LightCell.kt b/src/main/java/org/eln2/mc/common/cell/types/LightCell.kt deleted file mode 100644 index b75347ae..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/LightCell.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText - -class LightCell(pos : BlockPos): CellBase(pos) { - - /* R -> local resistors. Their first pin is grounded. - * C -> remote components. The second pin of the local resistors is used for them. - * - * C - * R - * C R G R C - * R - * C - */ - - override fun clearForRebuild() { - neighbourToResistorLookup.clear() - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - - return ComponentInfo(neighbourToResistorLookup.computeIfAbsent(neighbour) { - val resistor = Resistor() - resistor.resistance = 75.0 - circuit.add(resistor) - resistor - }, 1) // pin 1 will be connected to the remote components - } - - override fun buildConnections() { - connections.forEach{ adjacentCell -> - val resistor = componentForNeighbour(adjacentCell).component - resistor.ground(0) // ground one pin of our resistor - // then connect the other pin to them - resistor.connectToPinOf(1, adjacentCell.componentForNeighbour(this)) - } - } - - private val neighbourToResistorLookup = HashMap() - - override fun getHudMap(): Map { - val voltage: String = ValueText.valueText(0.0, UnitType.VOLT) - var current: String = ValueText.valueText(0.0, UnitType.AMPERE) - val map = mutableMapOf() - - try { - val currents = connections.map { (componentForNeighbour(it).component as Resistor).current } - val currentString = currents.joinToString(", ") { ValueText.valueText(it, UnitType.AMPERE) } - if (currentString.isNotEmpty()) - current = currentString - } catch (_: Exception) { - // don't care, sim is in a bad/unready state - } - - map["voltage"] = voltage - map["current"] = current - - return map - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/ResistorCell.kt b/src/main/java/org/eln2/mc/common/cell/types/ResistorCell.kt deleted file mode 100644 index 82ad419d..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/ResistorCell.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.common.cell.ISingleElementGuiCell -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText.valueText - -class ResistorCell(pos: BlockPos) : CellBase(pos), ISingleElementGuiCell { - lateinit var resistor: Resistor - var added = false - - override fun clearForRebuild() { - resistor = Resistor() - resistor.resistance = 100.0 - added = false - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - if(!added) { - circuit.add(resistor) - added = true - } - return ComponentInfo(resistor, connections.indexOf(neighbour)) - } - - override fun buildConnections() { - connections.forEach{remoteCell -> - val localInfo = componentForNeighbour(remoteCell) - localInfo.component.connectToPinOf(localInfo.index, remoteCell.componentForNeighbour(this)) - } - } - - override fun getHudMap(): Map { - var voltage: String = valueText(0.0, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - val resistance: String = valueText(resistor.resistance, UnitType.OHM) - var power: String = valueText(0.0, UnitType.WATT) - val map = mutableMapOf() - - try { - current = valueText(resistor.current, UnitType.AMPERE) - voltage = resistor.pins.joinToString(", ") { valueText(it.node?.potential ?: 0.0, UnitType.VOLT) } - power = valueText(resistor.power, UnitType.WATT) - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["resistance"] = resistance - map["power"] = power - - return map - } - - override fun getGuiValue(): Double { - return resistor.resistance - } - - override fun setGuiValue(value: Double) { - resistor.resistance = value - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/SolarLightCell.kt b/src/main/java/org/eln2/mc/common/cell/types/SolarLightCell.kt deleted file mode 100644 index 773d870a..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/SolarLightCell.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo - -class SolarLightCell(pos : BlockPos) : CellBase(pos) { - - override fun clearForRebuild() {} - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { error("Lol, this doesn't do anything here") } - - override fun buildConnections() {} - - override fun getHudMap(): Map { - return mapOf() - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/SolarPanelCell.kt b/src/main/java/org/eln2/mc/common/cell/types/SolarPanelCell.kt deleted file mode 100644 index ff0de7f9..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/SolarPanelCell.kt +++ /dev/null @@ -1,75 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.ageseries.libage.sim.electrical.mna.component.VoltageSource -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText - -class SolarPanelCell(pos : BlockPos) : CellBase(pos) { - - /* - * V -> local voltage source. - * C -> remote components. - * - * C V C - */ - - private lateinit var source : VoltageSource - - override fun clearForRebuild() { - source = VoltageSource() - source.potential = 12.5 - neighbourToResistorLookup.clear() - } - - // TODO: Battery needs a + and - terminal. Currently, it's just implicitly grounded because I can't get that to work. - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - - return ComponentInfo(neighbourToResistorLookup.computeIfAbsent(neighbour) { - val resistor = Resistor() - resistor.resistance = 0.001 - circuit.add(resistor) - resistor - }, 1) // pin 1 will be connected to the remote cell - } - - override fun buildConnections() { - val circuit = graph.circuit - circuit.add(source) - source.ground(0) - - connections.forEach { remoteCell -> - val localResistor = componentForNeighbour(remoteCell).component // get local resistor - localResistor.connectToPinOf(1, remoteCell.componentForNeighbour(this)) // connect local resistor to remote component - localResistor.connect(0, source, 1) // connect local resistor to our voltage source - } - } - - private val neighbourToResistorLookup = HashMap() - - override fun getHudMap(): Map { - val voltage: String = ValueText.valueText(source.potential, UnitType.VOLT) - var current: String = ValueText.valueText(0.0, UnitType.AMPERE) - var power: String = ValueText.valueText(0.0, UnitType.WATT) - val map = mutableMapOf() - - try { - current = ValueText.valueText(source.current, UnitType.AMPERE) - power = ValueText.valueText(source.potential * source.current, UnitType.WATT) - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["power"] = power - - return map - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/VoltageSourceCell.kt b/src/main/java/org/eln2/mc/common/cell/types/VoltageSourceCell.kt deleted file mode 100644 index 8d626aa6..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/VoltageSourceCell.kt +++ /dev/null @@ -1,83 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.ageseries.libage.sim.electrical.mna.component.VoltageSource -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.common.cell.ISingleElementGuiCell -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText.valueText - -class VoltageSourceCell(pos: BlockPos) : CellBase(pos), ISingleElementGuiCell { - - /* R -> local resistors. Their first pin is connected to the voltage source. - * C -> remote components. The second pin of the local resistors is used for them. - * - * C - * R - * C R V R C - * R - * C - */ - - private lateinit var source: VoltageSource - - override fun clearForRebuild() { - source = VoltageSource() - source.potential = 5.0 - neighbourToResistorLookup.clear() - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - - return ComponentInfo(neighbourToResistorLookup.computeIfAbsent(neighbour) { - val resistor = Resistor() - resistor.resistance = 0.001 - circuit.add(resistor) - resistor - }, 1) // pin 1 will be connected to the remote cell - } - - override fun buildConnections() { - val circuit = graph.circuit - circuit.add(source) - source.ground(0) - - connections.forEach { remoteCell -> - val localResistor = componentForNeighbour(remoteCell).component // get local resistor - localResistor.connectToPinOf(1, remoteCell.componentForNeighbour(this)) // connect local resistor to remote component - localResistor.connect(0, source, 1) // connect local resistor to our voltage source - } - } - - private val neighbourToResistorLookup = HashMap() - - override fun getHudMap(): Map { - val voltage: String = valueText(source.potential, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - var power: String = valueText(0.0, UnitType.WATT) - val map = mutableMapOf() - - try { - current = valueText(source.current, UnitType.AMPERE) - power = valueText(source.potential * source.current, UnitType.WATT) - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["power"] = power - - return map - } - - override fun getGuiValue(): Double = source.potential - - override fun setGuiValue(value: Double) { - source.potential = value - } -} diff --git a/src/main/java/org/eln2/mc/common/cell/types/WireCell.kt b/src/main/java/org/eln2/mc/common/cell/types/WireCell.kt deleted file mode 100644 index 213df77e..00000000 --- a/src/main/java/org/eln2/mc/common/cell/types/WireCell.kt +++ /dev/null @@ -1,82 +0,0 @@ -package org.eln2.mc.common.cell.types - -import net.minecraft.core.BlockPos -import org.ageseries.libage.sim.electrical.mna.component.Resistor -import org.eln2.mc.common.cell.CellBase -import org.eln2.mc.common.cell.ComponentInfo -import org.eln2.mc.extensions.ComponentExtensions.connectToPinOf -import org.eln2.mc.utility.UnitType -import org.eln2.mc.utility.ValueText -import org.eln2.mc.utility.ValueText.valueText -import kotlin.math.abs - -class WireCell(pos : BlockPos) : CellBase(pos) { - /* R -> local resistors. Their first pins are interconnected. - * C -> remote components. The second pin of the local resistors is used for them. - * - * C - * R - * C R ┼ R C - * R - * C - */ - - override fun clearForRebuild() { - neighbourToResistorLookup.clear() - } - - override fun componentForNeighbour(neighbour: CellBase): ComponentInfo { - val circuit = graph.circuit - - return ComponentInfo(neighbourToResistorLookup.computeIfAbsent(neighbour) { - val resistor = Resistor() - resistor.resistance = 0.001 - circuit.add(resistor) - if(neighbourToResistorLookup.isNotEmpty()){ - neighbourToResistorLookup.values.first().connect(0, resistor, 0) - } - resistor - }, 1) - } - - override fun buildConnections() { - connections.forEach{ adjacentCell -> - val resistor = componentForNeighbour(adjacentCell).component - resistor.connectToPinOf(1, adjacentCell.componentForNeighbour(this)) - } - } - - private val neighbourToResistorLookup = HashMap() - - /* - * The most meaningful current is the branch currents at the central points. - */ - override fun getHudMap(): Map { - var voltage: String = valueText(0.0, UnitType.VOLT) - var current: String = valueText(0.0, UnitType.AMPERE) - val resistance: String = valueText(0.001, UnitType.OHM) - val map = mutableMapOf() - - try { - val currentString = if (connections.size == 2) { - // Straight through wire. Just give absolute value I guess since directionality is ~ meaningless for wires. - valueText(abs((componentForNeighbour(connections[0]).component as Resistor).current), UnitType.AMPERE) - } else { - // Branch currents. Print them all. - val currents = connections.map { (componentForNeighbour(it).component as Resistor).current } - currents.joinToString(", ") { ValueText.valueText(it, UnitType.AMPERE) } - } - if (currentString.isNotEmpty()) - current = currentString - voltage = valueText((componentForNeighbour(connections[0]).component as Resistor).pins[0].node?.potential ?: 0.0, UnitType.VOLT) - } catch (_: Exception) { - // No results from simulator - } - - map["voltage"] = voltage - map["current"] = current - map["resistance"] = resistance - - return map - } -} diff --git a/src/main/java/org/eln2/mc/common/containers/CapacitorCellContainer.kt b/src/main/java/org/eln2/mc/common/containers/CapacitorCellContainer.kt deleted file mode 100644 index 333d7f33..00000000 --- a/src/main/java/org/eln2/mc/common/containers/CapacitorCellContainer.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.eln2.mc.common.containers - -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.types.CapacitorCell -import org.eln2.mc.common.containers.ContainerRegistry.CAPACITOR_CELL_CONTAINER -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.serverToClient.SingleDoubleElementGuiOpenPacket - -class CapacitorCellContainer(id: Int, plyInv: Inventory, ply: Player) : - SingleValueCellContainer(id, plyInv, ply, CAPACITOR_CELL_CONTAINER.get()) { - - override var value: Double = 0.0 - - constructor(id: Int, plyInv: Inventory, ply: Player, te: CellTileEntity) : this(id, plyInv, ply) { - this.te = te - - this.value = (te.cell as CapacitorCell).getGuiValue() - this.pos = te.pos - } - - override fun sendDataToClient(ply: ServerPlayer) { - Networking.sendTo(SingleDoubleElementGuiOpenPacket(value, pos), ply) - } - - override fun stillValid(pPlayer: Player): Boolean { - return true - } -} diff --git a/src/main/java/org/eln2/mc/common/containers/ContainerRegistry.kt b/src/main/java/org/eln2/mc/common/containers/ContainerRegistry.kt deleted file mode 100644 index 63b75d49..00000000 --- a/src/main/java/org/eln2/mc/common/containers/ContainerRegistry.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.eln2.mc.common.containers - -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.inventory.MenuType -import net.minecraftforge.eventbus.api.IEventBus -import net.minecraftforge.registries.DeferredRegister -import net.minecraftforge.registries.ForgeRegistries -import net.minecraftforge.registries.RegistryObject -import org.eln2.mc.Eln2 -import org.eln2.mc.common.blocks.BlockRegistry - -object ContainerRegistry { - /** - * Remember to also register your GUI's Screens on the client in [org.eln2.mc.client.events.ClientEvents.clientSetup] - */ - @JvmStatic - val CONTAINER_REGISTRY: DeferredRegister> = DeferredRegister.create( - ForgeRegistries.CONTAINERS, - Eln2.MODID - ) - - fun setup(bus: IEventBus) = CONTAINER_REGISTRY.register(bus) - - /** - * This really only exists so that I don't have to specify the type on every GUI to - * avoid unchecked nullability issues - */ - private fun registerGuiContainer( - name: String, - supplier: () -> MenuType - ): RegistryObject> = CONTAINER_REGISTRY.register(name) { supplier() } - - val VOLTAGE_SOURCE_CELL_CONTAINER = registerGuiContainer(BlockRegistry.VOLTAGE_SOURCE_CELL.name) { - MenuType {id, inv -> - VoltageSourceCellContainer(id, inv, inv.player) - } - } - - val RESISTOR_CELL_CONTAINER = registerGuiContainer(BlockRegistry.RESISTOR_CELL.name) { - MenuType { id, inv -> - ResistorCellContainer(id, inv, inv.player) - } - } - - val CAPACITOR_CELL_CONTAINER = registerGuiContainer(BlockRegistry.CAPACITOR_CELL.name) { - MenuType { id, inv -> - CapacitorCellContainer(id, inv, inv.player) - } - } - - val INDUCTOR_CELL_CONTAINER = registerGuiContainer(BlockRegistry.INDUCTOR_CELL.name) { - MenuType { id, inv -> - InductorCellContainer(id, inv, inv.player) - } - } -} diff --git a/src/main/java/org/eln2/mc/common/containers/InductorCellContainer.kt b/src/main/java/org/eln2/mc/common/containers/InductorCellContainer.kt deleted file mode 100644 index 5d322172..00000000 --- a/src/main/java/org/eln2/mc/common/containers/InductorCellContainer.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.eln2.mc.common.containers - -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.types.InductorCell -import org.eln2.mc.common.containers.ContainerRegistry.INDUCTOR_CELL_CONTAINER -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.serverToClient.SingleDoubleElementGuiOpenPacket - -class InductorCellContainer(id: Int, plyInv: Inventory, ply: Player) : - SingleValueCellContainer(id, plyInv, ply, INDUCTOR_CELL_CONTAINER.get()) { - - override var value: Double = 0.0 - - constructor(id: Int, plyInv: Inventory, ply: Player, te: CellTileEntity) : this(id, plyInv, ply) { - this.te = te - - this.value = (te.cell as InductorCell).getGuiValue() - this.pos = te.pos - } - - override fun getSyncedValue(): Double { - return value - } - - override fun sendDataToClient(ply: ServerPlayer) { - Networking.sendTo(SingleDoubleElementGuiOpenPacket(value, pos), ply) - } - - override fun stillValid(pPlayer: Player): Boolean { - return true - } - -} diff --git a/src/main/java/org/eln2/mc/common/containers/ResistorCellContainer.kt b/src/main/java/org/eln2/mc/common/containers/ResistorCellContainer.kt deleted file mode 100644 index e9ecebdc..00000000 --- a/src/main/java/org/eln2/mc/common/containers/ResistorCellContainer.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.eln2.mc.common.containers - -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.types.ResistorCell -import org.eln2.mc.common.containers.ContainerRegistry.RESISTOR_CELL_CONTAINER -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.serverToClient.SingleDoubleElementGuiOpenPacket - -@Suppress("UNCHECKED_CAST") -class ResistorCellContainer(id: Int, plyInv: Inventory, ply: Player) : - SingleValueCellContainer(id, plyInv, ply, RESISTOR_CELL_CONTAINER.get()) { - override fun stillValid(pPlayer: Player): Boolean { - return true - } - - override var value: Double = 0.0 - - constructor(id: Int, plyInv: Inventory, ply: Player, te: CellTileEntity) : this(id, plyInv, ply) { - this.te = te - - value = (te.cell as ResistorCell).getGuiValue() - pos = te.pos - } - - override fun sendDataToClient(ply: ServerPlayer) { - Networking.sendTo(SingleDoubleElementGuiOpenPacket(value, pos), ply) - } - -} diff --git a/src/main/java/org/eln2/mc/common/containers/SingleValueCellContainer.kt b/src/main/java/org/eln2/mc/common/containers/SingleValueCellContainer.kt deleted file mode 100644 index 18834773..00000000 --- a/src/main/java/org/eln2/mc/common/containers/SingleValueCellContainer.kt +++ /dev/null @@ -1,64 +0,0 @@ -package org.eln2.mc.common.containers - -import net.minecraft.core.BlockPos -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.inventory.ContainerListener -import net.minecraft.world.inventory.MenuType -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.ISingleElementGuiCell - -abstract class SingleValueCellContainer, N : Number>( - id: Int, - plyInv: Inventory, - private val ply: Player, - type: MenuType<*> -) : - AbstractContainerMenu(type, id) { - - abstract var value: N - var pos: BlockPos = BlockPos.ZERO - var te: CellTileEntity? = null - - open fun getSyncedValue(): N { - return this.value - } - - open fun setSyncedValue(value: N, pos: BlockPos): Boolean { - this.value = value - this.pos = pos - - return true - } - - abstract fun sendDataToClient(ply: ServerPlayer) - - open fun sendDataToAllClients() { - containerListeners.forEach { listener -> - if (listener is ServerPlayer) { - sendDataToClient(listener) - } - } - } - - override fun addSlotListener(pListener: ContainerListener) { - super.addSlotListener(pListener) - - //Ideally this would be a cast of pListener to ServerPlayer, but pListener is a ServerPlayer$2, - //which is some sort of uncastable wrapper around ServerPlayer - sendDataToClient(ply as ServerPlayer) - } - - @Suppress("UNCHECKED_CAST") - override fun broadcastChanges() { - if (this.value != (te?.cell as? C)?.getGuiValue() || this.pos != te?.pos) { - this.sendDataToAllClients() - } - } - - override fun broadcastFullState() { - this.sendDataToAllClients() - } -} diff --git a/src/main/java/org/eln2/mc/common/containers/VoltageSourceCellContainer.kt b/src/main/java/org/eln2/mc/common/containers/VoltageSourceCellContainer.kt deleted file mode 100644 index 618161ca..00000000 --- a/src/main/java/org/eln2/mc/common/containers/VoltageSourceCellContainer.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.eln2.mc.common.containers - -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.entity.player.Player -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.types.VoltageSourceCell -import org.eln2.mc.common.containers.ContainerRegistry.VOLTAGE_SOURCE_CELL_CONTAINER -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.network.serverToClient.SingleDoubleElementGuiOpenPacket - -class VoltageSourceCellContainer(id: Int, plyInv: Inventory, ply: Player) : - SingleValueCellContainer(id, plyInv, ply, VOLTAGE_SOURCE_CELL_CONTAINER.get()) { - override fun stillValid(pPlayer: Player): Boolean { - return true - } - - override var value: Double = 0.0 - - constructor(id: Int, plyInv: Inventory, ply: Player, te: CellTileEntity) : this(id, plyInv, ply) { - this.te = te - - value = (te.cell as VoltageSourceCell).getGuiValue() - pos = te.pos - } - - override fun sendDataToClient(ply: ServerPlayer) { - Networking.sendTo(SingleDoubleElementGuiOpenPacket(value, pos), ply) - } - -} diff --git a/src/main/java/org/eln2/mc/common/items/ItemRegistry.kt b/src/main/java/org/eln2/mc/common/items/ItemRegistry.kt deleted file mode 100644 index c31da21c..00000000 --- a/src/main/java/org/eln2/mc/common/items/ItemRegistry.kt +++ /dev/null @@ -1,34 +0,0 @@ -@file:Suppress("unused") // Because block variables here would be suggested for deletion. - -package org.eln2.mc.common.items - -import net.minecraft.world.item.Item -import net.minecraftforge.eventbus.api.IEventBus -import net.minecraftforge.registries.DeferredRegister -import net.minecraftforge.registries.ForgeRegistries -import net.minecraftforge.registries.RegistryObject -import org.eln2.mc.Eln2 -import org.eln2.mc.Eln2.LOGGER -import org.eln2.mc.common.eln2Tab - -object ItemRegistry { - @Suppress("MemberVisibilityCanBePrivate") // Used for item registration and fetching - val REGISTRY = DeferredRegister.create(ForgeRegistries.ITEMS, Eln2.MODID)!! // Yeah, if this fails blow up the game - - fun setup(bus : IEventBus){ - REGISTRY.register(bus) - LOGGER.info("Prepared item registry.") - } - - data class ItemRegistryItem( - val name: String, - val item: RegistryObject - ) - - private fun registerBasicItem(name: String, supplier: () -> Item): ItemRegistryItem { - val item = REGISTRY.register(name) {supplier()} - return ItemRegistryItem(name, item) - } - - val VOLTMETER_ITEM = registerBasicItem("voltmeter") {VoltmeterItem(eln2Tab)} -} diff --git a/src/main/java/org/eln2/mc/common/items/VoltmeterItem.kt b/src/main/java/org/eln2/mc/common/items/VoltmeterItem.kt deleted file mode 100644 index 0f52f2e6..00000000 --- a/src/main/java/org/eln2/mc/common/items/VoltmeterItem.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.eln2.mc.common.items - -import net.minecraft.Util -import net.minecraft.network.chat.TextComponent -import net.minecraft.world.InteractionResult -import net.minecraft.world.item.CreativeModeTab -import net.minecraft.world.item.Item -import net.minecraft.world.item.context.UseOnContext -import org.eln2.mc.common.blocks.CellTileEntity - -class VoltmeterItem(tab: CreativeModeTab?): Item(Item.Properties().also {if(tab != null) it.tab(tab)}) { - override fun useOn(context: UseOnContext): InteractionResult { - // If you try to dereference Cell on the client... lol it explodes violently. - if (!context.level.isClientSide) { - val clicked = context.level.getBlockEntity(context.clickedPos) - if (clicked is CellTileEntity) { - val voltage = clicked.getHudMap()["voltage"] - val power = clicked.getHudMap()["power"] - val current = clicked.getHudMap()["current"] - - var text = "" - - if (voltage != null) { - text += "Voltage: "+voltage+" " - } - if (power != null) { - text += "Power: "+power+" " - } - if (current != null) { - text += "Current: "+current+" " - } - - context.player?.sendMessage(TextComponent(text), Util.NIL_UUID) - return InteractionResult.SUCCESS - } - return InteractionResult.PASS - } - return InteractionResult.PASS - } -} diff --git a/src/main/java/org/eln2/mc/common/network/CellInfo.kt b/src/main/java/org/eln2/mc/common/network/CellInfo.kt deleted file mode 100644 index 815cca76..00000000 --- a/src/main/java/org/eln2/mc/common/network/CellInfo.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.eln2.mc.common.network - -import net.minecraft.core.BlockPos -import net.minecraft.network.FriendlyByteBuf -import org.eln2.mc.extensions.ByteBufferExtensions.readString -import org.eln2.mc.extensions.ByteBufferExtensions.readStringMap -import org.eln2.mc.extensions.ByteBufferExtensions.writeString -import org.eln2.mc.extensions.ByteBufferExtensions.writeStringMap - -class CellInfo(val type : String, val info : Map, val pos : BlockPos){ - - constructor(buffer : FriendlyByteBuf) : this(buffer.readString(), buffer.readStringMap(), buffer.readBlockPos()) - - fun serialize(buffer : FriendlyByteBuf) { - buffer.writeString(type) - buffer.writeStringMap(info) - buffer.writeBlockPos(pos) - } -} diff --git a/src/main/java/org/eln2/mc/common/network/ModStatistics.kt b/src/main/java/org/eln2/mc/common/network/ModStatistics.kt deleted file mode 100644 index db34fd1f..00000000 --- a/src/main/java/org/eln2/mc/common/network/ModStatistics.kt +++ /dev/null @@ -1,70 +0,0 @@ -package org.eln2.mc.common.network - -import kotlinx.serialization.Serializable -import org.apache.http.client.methods.HttpPost -import org.apache.http.entity.StringEntity -import org.apache.http.impl.client.HttpClientBuilder -import org.eln2.mc.Eln2 -import org.eln2.mc.Eln2.LOGGER -import java.util.* -import kotlin.concurrent.thread - -object ModStatistics { - var sent = false - - private fun collectData(): AnalyticsData { - try { - return AnalyticsData( - "", - "electrical_age", - "", - "", - Locale.getDefault().toLanguageTag() - ) - } catch (e: Exception) { - LOGGER.warn("Tried to get analytics and failed :/") - error("Tried to get analytics and failed :/") - } - } - - fun sendAnalytics() { - if (sent) { return } - thread (start = true, isDaemon = true, name = "Electrical Age Analytics") { - try { - val data = collectData() - val serialized = """ - { - "uuid": "${data.uuid}", - "mod_id": "${data.mod_id}", - "avg_sim_performance": "${data.avg_sim_performance}", - "game_lang": "${data.game_lang}", - "os_lang": "${data.os_lang}" - } - """.trimIndent() - LOGGER.debug("Sending HTTPS Post request to :\n$") - val httpClient = HttpClientBuilder.create().build() - val request = HttpPost(Eln2.config.analyticsEndpoint) - val params = StringEntity(serialized) - request.addHeader("content-type", "application/json") - request.entity = params - val resp = httpClient.execute(request) - if (resp.statusLine.statusCode != 200) { - LOGGER.warn(resp) - } - } catch (e: Exception) { - e.printStackTrace() - LOGGER.warn("Failed to send analytics information to server") - } - } - sent = true - } -} - -@Serializable -data class AnalyticsData( - var uuid: String = "", - var mod_id: String = "electrical_age", - var avg_sim_performance: String = "", - var game_lang: String = "", - var os_lang: String = Locale.getDefault().toLanguageTag() -) diff --git a/src/main/java/org/eln2/mc/common/network/Networking.kt b/src/main/java/org/eln2/mc/common/network/Networking.kt deleted file mode 100644 index 28ca2c91..00000000 --- a/src/main/java/org/eln2/mc/common/network/Networking.kt +++ /dev/null @@ -1,79 +0,0 @@ -@file:Suppress("INACCESSIBLE_TYPE") - -package org.eln2.mc.common.network - -import net.minecraft.resources.ResourceLocation -import net.minecraft.server.level.ServerPlayer -import net.minecraftforge.network.NetworkDirection -import net.minecraftforge.network.NetworkRegistry -import org.eln2.mc.Eln2 -import org.eln2.mc.common.network.clientToServer.CircuitExplorerOpenPacket -import org.eln2.mc.common.network.clientToServer.SingleDoubleElementGuiUpdatePacket -import org.eln2.mc.common.network.serverToClient.CircuitExplorerContextPacket -import org.eln2.mc.common.network.serverToClient.SingleDoubleElementGuiOpenPacket - -enum class PacketType(val id: Int) { - CIRCUIT_EXPLORER_OPEN_PACKET(0), - CIRCUIT_EXPLORER_CONTEXT_PACKET(1), - SINGLE_DOUBLE_ELEMENT_GUI_UPDATE_PACKET(2), - SINGLE_DOUBLE_ELEMENT_GUI_OPEN_PACKET(3), -} - -object Networking { - private const val protocolVersion = "1" - private const val channelName = "main" - private val channel = NetworkRegistry.newSimpleChannel( - ResourceLocation(Eln2.MODID, channelName), - { protocolVersion }, - { it == protocolVersion }, - { it == protocolVersion }) - - - fun setup() { - Eln2.LOGGER.info("Registering network packets") - channel.registerMessage( - PacketType.CIRCUIT_EXPLORER_OPEN_PACKET.id, - CircuitExplorerOpenPacket::class.java, - CircuitExplorerOpenPacket::encode, - ::CircuitExplorerOpenPacket, - CircuitExplorerOpenPacket::handle - ) - channel.registerMessage( - PacketType.CIRCUIT_EXPLORER_CONTEXT_PACKET.id, - CircuitExplorerContextPacket::class.java, - CircuitExplorerContextPacket::encode, - ::CircuitExplorerContextPacket, - CircuitExplorerContextPacket::handle - ) - channel.registerMessage( - PacketType.SINGLE_DOUBLE_ELEMENT_GUI_UPDATE_PACKET.id, - SingleDoubleElementGuiUpdatePacket::class.java, - SingleDoubleElementGuiUpdatePacket::encode, - SingleDoubleElementGuiUpdatePacket::decode, - SingleDoubleElementGuiUpdatePacket::handle - ) - channel.registerMessage( - PacketType.SINGLE_DOUBLE_ELEMENT_GUI_OPEN_PACKET.id, - SingleDoubleElementGuiOpenPacket::class.java, - SingleDoubleElementGuiOpenPacket::encode, - SingleDoubleElementGuiOpenPacket::decode, - SingleDoubleElementGuiOpenPacket::handle - ) - Eln2.LOGGER.info("Network packets registered") - } - - /** - * Sends a message from the server to the client. - * @param player The player to send the message to. - */ - fun sendTo(message: Any?, player: ServerPlayer) { - channel.sendTo(message, player.connection.getConnection(), NetworkDirection.PLAY_TO_CLIENT) - } - - /** - * Sends the message from the client to the server. - */ - fun sendToServer(message: Any?) { - channel.sendToServer(message) - } -} diff --git a/src/main/java/org/eln2/mc/common/network/clientToServer/CircuitExplorerOpenPacket.kt b/src/main/java/org/eln2/mc/common/network/clientToServer/CircuitExplorerOpenPacket.kt deleted file mode 100644 index fb3725b5..00000000 --- a/src/main/java/org/eln2/mc/common/network/clientToServer/CircuitExplorerOpenPacket.kt +++ /dev/null @@ -1,52 +0,0 @@ -package org.eln2.mc.common.network.clientToServer - -import net.minecraft.network.FriendlyByteBuf -import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.phys.BlockHitResult -import net.minecraft.world.phys.HitResult -import net.minecraftforge.network.NetworkEvent -import org.eln2.mc.Eln2 -import org.eln2.mc.common.network.CellInfo -import org.eln2.mc.common.network.Networking -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.network.serverToClient.CircuitExplorerContextPacket -import java.util.function.Supplier - -class CircuitExplorerOpenPacket() { - constructor(buffer : FriendlyByteBuf) : this() { } - - companion object{ - @Suppress("UNUSED_PARAMETER") // This will be useful later - fun encode(packet : CircuitExplorerOpenPacket, buffer : FriendlyByteBuf){ } - @Suppress("UNUSED_PARAMETER") // This will be useful later - fun handle(packet : CircuitExplorerOpenPacket, supplier : Supplier){ - val context = supplier.get() - - context.enqueueWork { - handleServer(context.sender!!) - } - } - - private fun handleServer(player : ServerPlayer){ - val pickResult = player.pick(100.0, 0f, false) - - if(pickResult.type != HitResult.Type.BLOCK){ - Eln2.LOGGER.info("server did not hit") - return - } - - val blockHit = pickResult as BlockHitResult - val tile = player.level.getBlockEntity(blockHit.blockPos) as CellTileEntity? - - if(tile !is CellTileEntity){ - Eln2.LOGGER.info("it is not the tile, it is ${player.level.getBlockEntity(blockHit.blockPos)}") - return - } - - - - val cells = tile.cell!!.graph.cells.map { CellInfo(it.id.toString(), it.getHudMap(), it.pos) } - Networking.sendTo(CircuitExplorerContextPacket(cells.toList(), tile.cell!!.graph.latestSolveTime), player) - } - } -} diff --git a/src/main/java/org/eln2/mc/common/network/clientToServer/SingleDoubleElementGuiUpdatePacket.kt b/src/main/java/org/eln2/mc/common/network/clientToServer/SingleDoubleElementGuiUpdatePacket.kt deleted file mode 100644 index 73098913..00000000 --- a/src/main/java/org/eln2/mc/common/network/clientToServer/SingleDoubleElementGuiUpdatePacket.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.eln2.mc.common.network.clientToServer - -import net.minecraft.core.BlockPos -import net.minecraft.network.FriendlyByteBuf -import net.minecraft.server.level.ServerPlayer -import net.minecraftforge.network.NetworkEvent -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.ISingleElementGuiCell -import java.util.function.Supplier - -/** - * SingleDoubleElementGuiUpdatePacket represents an update to an [ISingleElementGuiCell] - * where its stored value is a [Double] - * @see [org.eln2.mc.common.network.serverToClient.SingleDoubleElementGuiOpenPacket] - */ -class SingleDoubleElementGuiUpdatePacket(val value: Double, val pos: BlockPos) { - - companion object { - fun encode(packet: SingleDoubleElementGuiUpdatePacket, buffer: FriendlyByteBuf) { - buffer.writeDouble(packet.value) - buffer.writeBlockPos(packet.pos) - } - - fun decode(buffer: FriendlyByteBuf): SingleDoubleElementGuiUpdatePacket { - return SingleDoubleElementGuiUpdatePacket(buffer.readDouble(), buffer.readBlockPos()) - } - - fun handle(packet: SingleDoubleElementGuiUpdatePacket, supplier: Supplier) { - val ctx = supplier.get() - - ctx.enqueueWork { - handleServer(ctx.sender!!, packet) - } - ctx.packetHandled = true - } - - private fun handleServer(sender: ServerPlayer, packet: SingleDoubleElementGuiUpdatePacket) { - val te = sender.level.getBlockEntity(packet.pos) - - if (te is CellTileEntity) { - if (te.cell is ISingleElementGuiCell<*>) { - @Suppress("UNCHECKED_CAST") - (te.cell as? ISingleElementGuiCell)?.setGuiValue(packet.value) - ?: error("Attempted to set double value from GUI for non-double-holding TE") - } - } - } - } - -} diff --git a/src/main/java/org/eln2/mc/common/network/serverToClient/CircuitExplorerContextPacket.kt b/src/main/java/org/eln2/mc/common/network/serverToClient/CircuitExplorerContextPacket.kt deleted file mode 100644 index 33b92f35..00000000 --- a/src/main/java/org/eln2/mc/common/network/serverToClient/CircuitExplorerContextPacket.kt +++ /dev/null @@ -1,59 +0,0 @@ -package org.eln2.mc.common.network.serverToClient - -import net.minecraft.client.Minecraft -import net.minecraft.network.FriendlyByteBuf -import net.minecraftforge.api.distmarker.Dist -import net.minecraftforge.fml.loading.FMLEnvironment -import net.minecraftforge.network.NetworkEvent -import org.eln2.mc.Eln2 -import org.eln2.mc.common.network.CellInfo -import org.eln2.mc.client.gui.PlotterScreen -import java.util.function.Supplier - -class CircuitExplorerContextPacket() { - lateinit var cells : List - var nanoTime : Long = 0L - private set - - constructor(buffer : FriendlyByteBuf) : this(){ - val count = buffer.readInt() - - if(count == 0){ - Eln2.LOGGER.error("ERROR! Received 0 cells for the circuit explorer!") - return - } - - cells = ArrayList(buffer.readCollection({ArrayList(count)}, ::CellInfo)) - nanoTime = buffer.readLong() - } - - constructor(cells : List, nanoTime : Long) : this(){ - this.cells = cells - this.nanoTime = nanoTime - } - - companion object { - fun encode(packet : CircuitExplorerContextPacket, buffer : FriendlyByteBuf){ - buffer.writeInt(packet.cells.count()) - buffer.writeCollection(packet.cells) { pBuffer, info -> info.serialize(pBuffer)} - buffer.writeLong(packet.nanoTime) - } - - fun handle(packet : CircuitExplorerContextPacket, supplier : Supplier){ - supplier.get().enqueueWork { - if(Dist.CLIENT == FMLEnvironment.dist){ - handleClient(packet, Minecraft.getInstance()) - } - } - } - - private fun handleClient(packet : CircuitExplorerContextPacket, mc : Minecraft){ - if(mc.screen is PlotterScreen){ - Eln2.LOGGER.error("Screen already set!") - return - } - - mc.setScreen(PlotterScreen(packet.cells, packet.nanoTime)) - } - } -} diff --git a/src/main/java/org/eln2/mc/common/network/serverToClient/SingleDoubleElementGuiOpenPacket.kt b/src/main/java/org/eln2/mc/common/network/serverToClient/SingleDoubleElementGuiOpenPacket.kt deleted file mode 100644 index e093d67e..00000000 --- a/src/main/java/org/eln2/mc/common/network/serverToClient/SingleDoubleElementGuiOpenPacket.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.eln2.mc.common.network.serverToClient - -import net.minecraft.client.Minecraft -import net.minecraft.core.BlockPos -import net.minecraft.network.FriendlyByteBuf -import net.minecraftforge.api.distmarker.Dist -import net.minecraftforge.fml.loading.FMLEnvironment -import net.minecraftforge.network.NetworkEvent -import org.eln2.mc.common.cell.ISingleElementGuiCell -import org.eln2.mc.common.containers.SingleValueCellContainer -import java.util.function.Supplier - -/** - * SingleDoubleElementGuiOpenPacket is sent when the GUI of a [ISingleElementGuiCell] with a Double value - * is opened by a client. This populates the client container with values from the Block Entity - * @see [org.eln2.mc.common.network.clientToServer.SingleDoubleElementGuiUpdatePacket] - */ -class SingleDoubleElementGuiOpenPacket(val value: Double, val pos: BlockPos) { - - companion object { - fun encode(packet: SingleDoubleElementGuiOpenPacket, buffer: FriendlyByteBuf) { - buffer.writeDouble(packet.value) - buffer.writeBlockPos(packet.pos) - } - - fun decode(buffer: FriendlyByteBuf): SingleDoubleElementGuiOpenPacket { - return SingleDoubleElementGuiOpenPacket(buffer.readDouble(), buffer.readBlockPos()) - } - - fun handle(packet: SingleDoubleElementGuiOpenPacket, supplier: Supplier) { - val ctx = supplier.get() - - ctx.enqueueWork { - if (Dist.CLIENT == FMLEnvironment.dist) { - handleClient(packet, Minecraft.getInstance()) - } - } - ctx.packetHandled = true - } - - private fun handleClient(packet: SingleDoubleElementGuiOpenPacket, mc: Minecraft) { - val openContainer = mc.player?.containerMenu - - if (openContainer is SingleValueCellContainer<*, *>) { - @Suppress("UNCHECKED_CAST") - (openContainer as? SingleValueCellContainer, Double>)?.setSyncedValue( - packet.value, - packet.pos - ) - ?: error("Attempted to write a double value from GUI to a non-double holding TE") - } - } - } - -} diff --git a/src/main/java/org/eln2/mc/extensions/ByteBufferExtensions.kt b/src/main/java/org/eln2/mc/extensions/ByteBufferExtensions.kt deleted file mode 100644 index 990f7c77..00000000 --- a/src/main/java/org/eln2/mc/extensions/ByteBufferExtensions.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.eln2.mc.extensions - -import net.minecraft.network.FriendlyByteBuf - -object ByteBufferExtensions { - fun FriendlyByteBuf.writeString(string: String){ - this.writeByteArray(string.toByteArray(charset = Charsets.UTF_8)) - } - - fun FriendlyByteBuf.readString() : String{ - return this.readByteArray().toString(charset = Charsets.UTF_8) - } - - fun FriendlyByteBuf.writeStringMap(map: Map) { - val stringToFbb = { fbb: FriendlyByteBuf, str: String -> fbb.writeString(str) } - this.writeMap(map, stringToFbb, stringToFbb) - } - - fun FriendlyByteBuf.readStringMap(): Map { - val fbbToString = {fbb: FriendlyByteBuf -> fbb.readString()} - return this.readMap(fbbToString, fbbToString) - } -} diff --git a/src/main/java/org/eln2/mc/extensions/ComponentExtensions.kt b/src/main/java/org/eln2/mc/extensions/ComponentExtensions.kt deleted file mode 100644 index 8596025d..00000000 --- a/src/main/java/org/eln2/mc/extensions/ComponentExtensions.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.eln2.mc.extensions - -import org.ageseries.libage.sim.electrical.mna.component.Component -import org.eln2.mc.common.cell.ComponentInfo - -object ComponentExtensions { - fun Component.connectToPinOf(localIndex : Int, remoteInfo : ComponentInfo){ - this.connect(localIndex, remoteInfo.component, remoteInfo.index) - } -} diff --git a/src/main/java/org/eln2/mc/extensions/MatrixStackExtensions.kt b/src/main/java/org/eln2/mc/extensions/MatrixStackExtensions.kt deleted file mode 100644 index 4d5b8aeb..00000000 --- a/src/main/java/org/eln2/mc/extensions/MatrixStackExtensions.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.eln2.mc.extensions - -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.gui.GuiComponent - -object MatrixStackExtensions : GuiComponent() { - fun PoseStack.rect4(x : Int, y : Int, width : Int, height : Int, color : Int){ - hLine(this, x, x + width, y, color) - hLine(this, x, x + width, y + height, color) - vLine(this, x, y, y + height, color) - vLine(this, x + width, y, y + height, color) - } -} diff --git a/src/main/java/org/eln2/mc/extensions/NbtExtensions.kt b/src/main/java/org/eln2/mc/extensions/NbtExtensions.kt deleted file mode 100644 index 12c400b9..00000000 --- a/src/main/java/org/eln2/mc/extensions/NbtExtensions.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.eln2.mc.extensions - -import net.minecraft.core.BlockPos -import net.minecraft.nbt.CompoundTag - -object NbtExtensions { - fun CompoundTag.putBlockPos(key : String, pos : BlockPos) { - val dataTag = CompoundTag() - dataTag.putInt("X", pos.x) - dataTag.putInt("Y", pos.y) - dataTag.putInt("Z", pos.z) - this.put(key, dataTag) - } - - fun CompoundTag.getBlockPos(key : String) : BlockPos { - val dataTag = this.get(key) as CompoundTag - val x = dataTag.getInt("X") - val y = dataTag.getInt("Y") - val z = dataTag.getInt("Z") - - return BlockPos(x, y, z) - } - - fun CompoundTag.getStringList(key: String): List { - val tag = this.getCompound(key) - return tag.allKeys.map {tag.getString(it)} - } - - fun CompoundTag.setStringList(key: String, list: List) { - val tag = CompoundTag() - list.forEachIndexed { index, it -> - tag.putString("$index", it) - } - this.put(key, tag) - } - - fun CompoundTag.getStringMap(key: String): Map { - val tag = this.getCompound(key) - val map = mutableMapOf() - tag.allKeys.forEach { - tagKey -> - val tagValue = tag.getString(tagKey) - map[tagKey] = tagValue - } - return map - } - - fun CompoundTag.setStringMap(key: String, map: Map) { - val tag = CompoundTag() - map.forEach { (k, v) -> - tag.putString(k, v) - } - this.put(key, tag) - } -} diff --git a/src/main/java/org/eln2/mc/extensions/PoseStackExtensions.kt b/src/main/java/org/eln2/mc/extensions/PoseStackExtensions.kt deleted file mode 100644 index 757ed8a5..00000000 --- a/src/main/java/org/eln2/mc/extensions/PoseStackExtensions.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.eln2.mc.extensions - -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.* -import net.minecraft.client.renderer.GameRenderer - -object PoseStackExtensions { - class Union4i(val a : Int, val b : Int, val c : Int, val d : Int) - fun PoseStack.blitMultiple(collection : ArrayList) { - val tesselator = Tesselator.getInstance() - val builder = tesselator.builder - - val matrix = this.last().pose() - - RenderSystem.setShader { GameRenderer.getPositionTexShader() } - collection.forEach { union4i -> - val pX1 = union4i.a.toFloat() - val pY1 = union4i.b.toFloat() - val width = union4i.c.toFloat() - val height = union4i.d.toFloat() - - val pX2 = pX1 + width - val pY2 = pY1 + height - - builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX) - builder.vertex(matrix, pX1, pY2, 0f).uv(0f, height).endVertex() - builder.vertex(matrix, pX2, pY2, 0f).uv(width, height).endVertex() - builder.vertex(matrix, pX2, pY1, 0f).uv(width, 0f).endVertex() - builder.vertex(matrix, pX1, pY1, 0f).uv(0f, 0f).endVertex() - builder.end() - } - - BufferUploader.end(builder) - } -} - diff --git a/src/main/java/org/eln2/mc/extensions/ServerLevelExtensions.kt b/src/main/java/org/eln2/mc/extensions/ServerLevelExtensions.kt deleted file mode 100644 index 6b9cc473..00000000 --- a/src/main/java/org/eln2/mc/extensions/ServerLevelExtensions.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.eln2.mc.extensions - -import net.minecraft.core.BlockPos -import net.minecraft.server.level.ServerLevel -import org.eln2.mc.common.blocks.CellTileEntity -import org.eln2.mc.common.cell.CellBase - -object ServerLevelExtensions { - fun ServerLevel.getCellAt(pos : BlockPos) : CellBase { - return (this.getBlockEntity(pos) as CellTileEntity).cell!! - } - - fun ServerLevel.getCellEntityAt(pos : BlockPos) : CellTileEntity { - return this.getBlockEntity(pos) as CellTileEntity - } -} diff --git a/src/main/java/org/eln2/mc/extensions/VoxelShapeExtensions.kt b/src/main/java/org/eln2/mc/extensions/VoxelShapeExtensions.kt deleted file mode 100644 index a40b84b1..00000000 --- a/src/main/java/org/eln2/mc/extensions/VoxelShapeExtensions.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.eln2.mc.extensions - -import net.minecraft.core.Direction -import net.minecraft.world.phys.shapes.Shapes -import net.minecraft.world.phys.shapes.VoxelShape - - - - -object VoxelShapeExtensions { - private fun indexOfDirection(dir : Direction) : Int{ - return when(dir){ - Direction.SOUTH -> 0 - Direction.WEST -> 1 - Direction.NORTH -> 2 - Direction.EAST -> 3 - - else -> error("Out of bounds!") - } - } - - fun VoxelShape.align(from: Direction, to: Direction): VoxelShape { - val buffer = arrayOf(this, Shapes.empty()) - val times: Int = (indexOfDirection(to) - indexOfDirection(from) + 4) % 4 - - for (i in 0 until times) { - buffer[0].forAllBoxes { minX, minY, minZ, maxX, maxY, maxZ -> - buffer[1] = Shapes.or(buffer[1], Shapes.box(1 - maxZ, minY, minX, 1 - minZ, maxY, maxX)) - } - - buffer[0] = buffer[1] - buffer[1] = Shapes.empty() - } - - return buffer[0] - } -} diff --git a/src/main/java/org/eln2/mc/utility/AnalyticsAcknowledgementsData.kt b/src/main/java/org/eln2/mc/utility/AnalyticsAcknowledgementsData.kt deleted file mode 100644 index d1808155..00000000 --- a/src/main/java/org/eln2/mc/utility/AnalyticsAcknowledgementsData.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.eln2.mc.utility - -import kotlinx.serialization.Serializable - -@Serializable -data class AnalyticsAcknowledgementsData ( - val entries: MutableMap -) diff --git a/src/main/java/org/eln2/mc/utility/McColor.kt b/src/main/java/org/eln2/mc/utility/McColor.kt deleted file mode 100644 index 9b5cbfaf..00000000 --- a/src/main/java/org/eln2/mc/utility/McColor.kt +++ /dev/null @@ -1,67 +0,0 @@ -package org.eln2.mc.utility - -import net.minecraft.network.FriendlyByteBuf - -class McColor(val r : UByte, val g : UByte, val b : UByte, val a : UByte) { - constructor(r : Int, g : Int, b : Int, a : Int) : this( - if (r < 256 && r > -1) r.toUByte() else error("R is not within bounds."), - if (g < 256 && g > -1) g.toUByte() else error("G is not within bounds."), - if (b < 256 && b > -1) b.toUByte() else error("B is not within bounds."), - if (a < 256 && a > -1) a.toUByte() else error("A is not within bounds.")) - - constructor(r : Int, g : Int, b : Int) : this(r, g, b, 255) - - constructor(r : UByte, g : UByte, b : UByte) : this(r, g, b,255u) - constructor(binary : Int) : this( - (binary shr 16 and 0xFF).toUByte(), - (binary shr 8 and 0xFF).toUByte(), - (binary and 0xFF).toUByte(), - (binary shr 24 and 0xFF).toUByte() - ) - - val value = (b.toUInt() or (g.toUInt() shl 8) or (r.toUInt() shl 16) or (a.toUInt() shl 24)).toInt() - - fun serialize(buffer : FriendlyByteBuf) : FriendlyByteBuf { - buffer.writeInt(value) - return buffer - } - - override fun toString(): String { - return Integer.toHexString(value) - } - - companion object{ - fun deserialize(buffer : FriendlyByteBuf) : McColor{ - return McColor(buffer.readInt()) - } - - fun fromString(hex : String) : McColor { - return McColor(java.lang.Long.parseLong(hex, 16).toInt()) - } - } -} - -// This really looks like it could be an enum, but honestly it makes the call syntax worse. -object McColors { - val red = McColor(255u, 0u, 0u) - val green = McColor(0u, 255u, 0u) - val blue = McColor(0u, 0u, 255u) - val white = McColor(255u,255u,255u) - val black = McColor(0u,0u,0u) - val cyan = McColor(0u,255u,255u) - val purple = McColor(172u,79u,198u) - val yellow = McColor(255u, 255u, 0u) - val lightPink = McColor(255u,182u,193u) -} - -object McColorValues { - val red = McColors.red.value - val green = McColors.green.value - val blue = McColors.blue.value - val white = McColors.white.value - val black = McColors.black.value - val cyan = McColors.cyan.value - val purple = McColors.purple.value - val yellow = McColors.yellow.value - val lightPink = McColors.lightPink.value -} diff --git a/src/main/java/org/eln2/mc/utility/UnitType.kt b/src/main/java/org/eln2/mc/utility/UnitType.kt deleted file mode 100644 index 2e2f14d6..00000000 --- a/src/main/java/org/eln2/mc/utility/UnitType.kt +++ /dev/null @@ -1,57 +0,0 @@ -@file:Suppress("UNUSED_PARAMETER", "unused") - -package org.eln2.mc.utility - -/** - * @param unit The unit type (eg, for amps, A) - * - * // https://www.britannica.com/science/International-System-of-Units - */ -enum class UnitType(val unit: String) { - METRE("m"), - SECOND("s"), - GRAM("g"), - AMPERE("A"), - KELVIN("K"), - CANDELA("cd"), - MOLE("mol"), - SQUARE_METRE("m²"), - CUBIC_METRE("m³"), - LITRE("L"), - HERTZ("Hz"), - NEWTON("N"), - JOULE("J"), - PASCAL("Pa"), - WATT("W"), - COULOMB("C"), - VOLT("V"), - FARAD("F"), - OHM("Ω"), - SIEMENS("S"), - WEBER("Wb"), - TESLA("T"), - HENRY("H"), - LUMEN("lm"), - LUX("lx") -} - -/** - * @param prefix The prefix symbol - * @param factor The number to multiply by - * - * https://www.nist.gov/pml/weights-and-measures/metric-si-prefixes - */ -enum class MetricPrefix(prefix: String, factor: Double) { - TERA("T", 1000000000000.0), - GIGA("G", 1000000000.0), - MEGA("M", 1000000.0), - KILO("k", 1000.0), - HECTO("h", 100.0), - DEKA("da", 10.0), - DECI("d", 0.1), - CENTI("c", 0.01), - MILLI("m", 0.001), - MICRO("μ", 0.000001), - NANO("n", 0.000000001), - PICO("p", 0.000000000001) -} diff --git a/src/main/java/org/eln2/mc/utility/ValueText.kt b/src/main/java/org/eln2/mc/utility/ValueText.kt deleted file mode 100644 index b6876d15..00000000 --- a/src/main/java/org/eln2/mc/utility/ValueText.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.eln2.mc.utility - -import kotlin.math.abs - -object ValueText { - fun valueText(value: Double, baseUnit: UnitType): String { - val valueAbs = abs(value) - return when { - valueAbs < 0.0000001 -> - "0" - valueAbs < 0.000999 -> - String.format("%1.2fµ", value * 1000000) - valueAbs < 0.00999 -> - String.format("%1.2fm", value * 1000) - valueAbs < 0.0999 -> - String.format("%2.1fm", value * 1000) - valueAbs < 0.999 -> - String.format("%3.0fm", value * 1000) - valueAbs < 9.99 -> - String.format("%1.2f", value) - valueAbs < 99.9 -> - String.format("%2.1f", value) - valueAbs < 999 -> - String.format("%3.0f", value) - valueAbs < 9999 -> - String.format("%1.2fk", value / 1000.0) - valueAbs < 99999 -> - String.format("%2.1fk", value / 1000.0) - else -> // if(value < 1000000) - String.format("%3.0fk", value / 1000.0) - } + baseUnit.unit - } -} diff --git a/src/main/kotlin/org/eln2/mc/Annotations.kt b/src/main/kotlin/org/eln2/mc/Annotations.kt new file mode 100644 index 00000000..ebf433d0 --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Annotations.kt @@ -0,0 +1,10 @@ +package org.eln2.mc + +annotation class ClientOnly +annotation class ServerOnly + +/** + * Indicates that the code element is accessed from multiple threads. + * */ +annotation class CrossThreadAccess +annotation class RaceCondition diff --git a/src/main/kotlin/org/eln2/mc/Configuration.kt b/src/main/kotlin/org/eln2/mc/Configuration.kt new file mode 100644 index 00000000..4501804d --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Configuration.kt @@ -0,0 +1,48 @@ +package org.eln2.mc + +import java.io.File + +object Configuration { + private val CONFIG_FILE: File = File("config/electrical_age.yaml") + + var instance: ElnConfig = ElnConfig() + + /* fun loadConfig(configFile: File = CONFIG_FILE) { + try { + if (configFile.isFile) { + LOGGER.info("[Electrical Age] Reading config from ${configFile.absoluteFile}") + instance = Yaml.default.decodeFromStream(ElnConfig.serializer(), configFile.inputStream()) + } else { + instance = ElnConfig() + saveConfig() + } + } catch (e: Exception) { + LOGGER.error("Electrical Age had an issue with loading the configuration file, please check the file for errors.") + LOGGER.error("Check that 1) You have valid YAML 2) the config directives are spelled correctly (see documentation)") + } + } + + private fun saveConfig(configFile: File = CONFIG_FILE) { + try { + LOGGER.info("[Electrical Age] Writing config to ${configFile.absoluteFile}") + val configText = Yaml.default.encodeToString(ElnConfig.serializer(), instance) + if (!configFile.exists()) { + configFile.createNewFile() + } + configFile.writeText(configText) + } catch (e: Exception) { + LOGGER.error("Electrical Age was unable to write the config file, please check filesystem permissions: $e") + } + }*/ +} + +/** + * ElectricalAgeConfiguration + * + * NOTE: ALL FIELDS _MUST_ have default values when called, since the user will likely want a sane default! + * They may be blank, but MUST be present. Thanks! + */ +//@Serializable +data class ElnConfig( + var simulationThreads: Int = 8, +) diff --git a/src/main/kotlin/org/eln2/mc/Eln2.kt b/src/main/kotlin/org/eln2/mc/Eln2.kt new file mode 100644 index 00000000..065f3a7a --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Eln2.kt @@ -0,0 +1,91 @@ +package org.eln2.mc + +import net.minecraft.client.Minecraft +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.packs.resources.Resource +import net.minecraftforge.api.distmarker.Dist +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext +import net.minecraftforge.fml.loading.FMLEnvironment +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.eln2.mc.client.render.FlywheelRegistry +import org.eln2.mc.client.render.PartialModels +import org.eln2.mc.client.render.RenderTypes +import org.eln2.mc.common.blocks.BlockRegistry +import org.eln2.mc.common.cells.CellRegistry +import org.eln2.mc.common.containers.ContainerRegistry +import org.eln2.mc.common.content.Content +import org.eln2.mc.common.entities.EntityRegistry +import org.eln2.mc.common.fluids.FluidRegistry +import org.eln2.mc.common.items.ItemRegistry +import org.eln2.mc.common.network.Networking +import org.eln2.mc.common.parts.PartRegistry +import java.io.InputStream +import java.nio.charset.Charset +import java.nio.file.Files +import kotlin.io.path.Path + +val LOG: Logger = LogManager.getLogger() +const val MODID = "eln2" + +@Mod(MODID) +class Eln2 { + init { + val modEventBus = FMLJavaModLoadingContext.get().modEventBus + + BlockRegistry.setup(modEventBus) + EntityRegistry.setup(modEventBus) + ItemRegistry.setup(modEventBus) + ContainerRegistry.setup(modEventBus) + FluidRegistry.setup(modEventBus) + + if (Dist.CLIENT == FMLEnvironment.dist) { + // Client-side setup + + modEventBus.addListener { event: FMLClientSetupEvent -> + event.enqueueWork { + FlywheelRegistry.initialize() + RenderTypes.initialize() + } + } + + modEventBus.register(Content.ClientSetup::clientSetup) + + PartialModels.initialize() + + LOG.info("Prepared client-side") + } + + Networking.setup() + + CellRegistry.setup(modEventBus) + PartRegistry.setup(modEventBus) + Content.initialize() + + LOG.info("Prepared registries.") + } +} + +fun resource(path: String): ResourceLocation { + return ResourceLocation(MODID, path) +} + +fun getResource(location: ResourceLocation): Resource = + Minecraft.getInstance().resourceManager.getResource(location).orElseThrow() + +fun getResourceStream(location: ResourceLocation): InputStream = getResource(location).open() +fun getResourceBinary(location: ResourceLocation) = getResourceStream(location).readAllBytes() +fun getResourceString(location: ResourceLocation): String = + getResourceStream(location).readAllBytes().toString(Charset.defaultCharset()) + +val GAME = false + +fun getResourceStringHelper(s: String) = + if (GAME) getResourceString(resource(s)) + else Files.readString(Path("./src/main/resources/assets/eln2/$s")) + +fun getResourceBinaryHelper(s: String) = + if (GAME) getResourceBinary(resource(s)) + else Files.readAllBytes(Path("./src/main/resources/assets/eln2/$s")) diff --git a/src/main/kotlin/org/eln2/mc/Environments.kt b/src/main/kotlin/org/eln2/mc/Environments.kt new file mode 100644 index 00000000..ebf281c4 --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Environments.kt @@ -0,0 +1,50 @@ +package org.eln2.mc + +import net.minecraft.world.level.Level +import net.minecraft.world.level.biome.Biome +import org.ageseries.libage.sim.thermal.Temperature +import org.ageseries.libage.sim.thermal.ThermalUnits +import org.eln2.mc.data.BlockLocator +import org.eln2.mc.data.DataFieldMap +import org.eln2.mc.data.LocatorSet +import org.eln2.mc.data.requireLocator +import java.util.concurrent.ConcurrentHashMap + +fun interface EnvTemperatureField { + fun readTemperature(): Temperature +} + +fun interface EnvThermalConductivityField { + fun readConductivity(): Double +} + +data class EnvironmentInformation( + val temperature: Temperature, + val airThermalConductivity: Double, +) { + fun fieldMap() = DataFieldMap() + .withField { EnvTemperatureField { temperature } } + .withField { EnvThermalConductivityField { airThermalConductivity } } +} + +object BiomeEnvironments { + private val biomes = ConcurrentHashMap() + + private val AIR_THERMAL_CONDUCTIVITY = loadCsvSpline("air_thermal_conductivity/ds.csv", 0, 2) + private val MINECRAFT_TEMPERATURE_CELSIUS = loadCsvSpline("minecraft_temperature/ds.csv", 0, 1) + + fun cellEnv(level: Level, pos: LocatorSet): EnvironmentInformation { + val biome = level.getBiome(pos.requireLocator { + "Biome Environments need a block pos locator" + }).value() + + val temperature = MINECRAFT_TEMPERATURE_CELSIUS.evaluate(biome.baseTemperature.toDouble()) + + return biomes.computeIfAbsent(biome) { + return@computeIfAbsent EnvironmentInformation( + Temperature.from(temperature, ThermalUnits.CELSIUS), + AIR_THERMAL_CONDUCTIVITY.evaluate(temperature) + ) + } + } +} diff --git a/src/main/kotlin/org/eln2/mc/Extensions.kt b/src/main/kotlin/org/eln2/mc/Extensions.kt new file mode 100644 index 00000000..ba6e542f --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Extensions.kt @@ -0,0 +1,949 @@ +package org.eln2.mc + +import com.jozufozu.flywheel.core.materials.model.ModelData +import com.mojang.math.* +import mcp.mobius.waila.api.IPluginConfig +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.core.Vec3i +import net.minecraft.core.particles.ParticleOptions +import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer +import net.minecraft.sounds.SoundEvent +import net.minecraft.sounds.SoundSource +import net.minecraft.world.InteractionResult +import net.minecraft.world.MenuProvider +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.item.ItemEntity +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.entity.player.Player +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.inventory.Slot +import net.minecraft.world.level.ChunkPos +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.HorizontalDirectionalBlock +import net.minecraft.world.level.block.Rotation +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 +import net.minecraftforge.items.ItemStackHandler +import net.minecraftforge.network.NetworkHooks +import org.ageseries.libage.data.BiMap +import org.ageseries.libage.data.MutableSetMapMultiMap +import org.ageseries.libage.data.mutableBiMapOf +import org.ageseries.libage.sim.Material +import org.ageseries.libage.sim.Scale +import org.ageseries.libage.sim.electrical.mna.Circuit +import org.ageseries.libage.sim.electrical.mna.component.Resistor +import org.ageseries.libage.sim.electrical.mna.component.VoltageSource +import org.ageseries.libage.sim.thermal.ConnectionParameters +import org.ageseries.libage.sim.thermal.Simulator +import org.ageseries.libage.sim.thermal.Temperature +import org.ageseries.libage.sim.thermal.ThermalMass +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D +import org.eln2.mc.common.blocks.foundation.CellBlockEntity +import org.eln2.mc.common.blocks.foundation.MultiblockManager +import org.eln2.mc.common.blocks.foundation.MultipartBlockEntity +import org.eln2.mc.common.cells.foundation.Cell +import org.eln2.mc.common.cells.foundation.ComponentHolder +import org.eln2.mc.common.cells.foundation.ElectricalComponentInfo +import org.eln2.mc.common.parts.foundation.Part +import org.eln2.mc.common.parts.foundation.PartUpdateType +import org.eln2.mc.data.* +import org.eln2.mc.integration.WailaTooltipBuilder +import org.eln2.mc.mathematics.* +import org.joml.Quaternionf +import org.joml.Vector3f +import java.io.InputStream +import java.io.OutputStream +import java.nio.ByteBuffer +import java.util.* +import kotlin.math.abs + +fun AABB.viewClip(entity: LivingEntity): Optional { + val viewDirection = entity.lookAngle + + val start = Vec3(entity.x, entity.eyeY, entity.z) + + val distance = 5.0 + + val end = start + viewDirection * distance + + return this.clip(start, end) +} + +fun AABB.minVec3(): Vec3 { + return Vec3(this.minX, this.minY, this.minZ) +} + +fun AABB.maxVec3(): Vec3 { + return Vec3(this.maxX, this.maxY, this.maxZ) +} + +fun AABB.size(): Vec3 { + return this.maxVec3() - this.minVec3() +} + +fun AABB.corners(list: MutableList) { + val min = this.minVec3() + val max = this.maxVec3() + + list.add(min) + list.add(Vec3(min.x, min.y, max.z)) + list.add(Vec3(min.x, max.y, min.z)) + list.add(Vec3(max.x, min.y, min.z)) + list.add(Vec3(min.x, max.y, max.z)) + list.add(Vec3(max.x, min.y, max.z)) + list.add(Vec3(max.x, max.y, min.z)) + list.add(max) +} + +fun AABB.corners(): ArrayList { + val list = ArrayList() + + this.corners(list) + + return list +} + +fun Vector3f.toVec3() = Vec3(this.x.toDouble(), this.y.toDouble(), this.z.toDouble()) + +/** + * Transforms the Axis Aligned Bounding Box by the given rotation. + * This operation does not change the volume for axis aligned transformations. + * */ +fun AABB.transformed(quaternion: Quaternionf): AABB { + var min = Vector3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE) + var max = Vector3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE) + + this.corners().forEach { + val corner = quaternion.transform(it.toVector3f()) + + min = componentMin(min, corner) + max = componentMax(max, corner) + } + + return AABB(min.toVec3(), max.toVec3()) +} + +fun BlockState.facing(): Direction = this.getValue(HorizontalDirectionalBlock.FACING) + +operator fun BlockPos.plus(displacement: Vec3i): BlockPos { + return this.offset(displacement) +} + +operator fun BlockPos.plus(direction: Direction): BlockPos { + return this + direction.normal +} + +operator fun BlockPos.minus(displacement: Vec3i): BlockPos { + return this.subtract(displacement) +} + +operator fun BlockPos.minus(other: BlockPos): BlockPos { + return BlockPos(this.x - other.x, this.y - other.y, this.z - other.z) +} + +operator fun BlockPos.minus(direction: Direction): BlockPos { + return this - direction.normal +} + +fun BlockPos.toVec3(): Vec3 { + return Vec3(this.x.toDouble(), this.y.toDouble(), this.z.toDouble()) +} + +fun BlockPos.directionTo(other: BlockPos): Direction? { + return Direction.fromNormal(other - this) +} + +fun Direction.isVertical(): Boolean { + return this == Direction.UP || this == Direction.DOWN +} + +fun Direction.isHorizontal(): Boolean { + return !isVertical() +} + +val Direction.alias: Base6Direction3d + get() = when (this) { + Direction.DOWN -> Base6Direction3d.Down + Direction.UP -> Base6Direction3d.Up + Direction.NORTH -> Base6Direction3d.Front + Direction.SOUTH -> Base6Direction3d.Back + Direction.WEST -> Base6Direction3d.Left + Direction.EAST -> Base6Direction3d.Right + } + +val Base6Direction3d.alias: Direction + get() = when (this) { + Base6Direction3d.Front -> Direction.NORTH + Base6Direction3d.Back -> Direction.SOUTH + Base6Direction3d.Left -> Direction.WEST + Base6Direction3d.Right -> Direction.EAST + Base6Direction3d.Up -> Direction.UP + Base6Direction3d.Down -> Direction.DOWN + } + +fun Direction.index(): Int { + return this.get3DDataValue() +} + +fun Direction.toVector3D(): Vector3D { + return Vector3D(this.stepX.toDouble(), this.stepY.toDouble(), this.stepZ.toDouble()) +} + +fun AbstractContainerMenu.addPlayerGrid(playerInventory: Inventory, addSlot: ((Slot) -> Unit)): Int { + var slots = 0 + + for (i in 0..2) { + for (j in 0..8) { + addSlot(Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)) + slots++ + } + } + for (k in 0..8) { + addSlot(Slot(playerInventory, k, 8 + k * 18, 142)) + slots++ + } + + return slots +} + +fun interface ContainerFactory { + fun create(id: Int, inventory: Inventory, player: Player, entity: T): AbstractContainerMenu +} + +fun Level.playLocalSound( + pos: Vec3, + pSound: SoundEvent, + pCategory: SoundSource, + pVolume: Float, + pPitch: Float, + pDistanceDelay: Boolean, +) { + this.playLocalSound(pos.x, pos.y, pos.z, pSound, pCategory, pVolume, pPitch, pDistanceDelay) +} + +fun Level.addParticle( + pParticleData: ParticleOptions, + pos: Vec3, + pXSpeed: Double, + pYSpeed: Double, + pZSpeed: Double, +) { + this.addParticle(pParticleData, pos.x, pos.y, pos.z, pXSpeed, pYSpeed, pZSpeed) +} + +fun Level.addParticle( + pParticleData: ParticleOptions, + pos: Vec3, + speed: Vec3, +) { + this.addParticle(pParticleData, pos.x, pos.y, pos.z, speed.x, speed.y, speed.z) +} + +@ServerOnly +fun ServerLevel.destroyPart(part: Part<*>, dropPart: Boolean) { + val pos = part.placement.pos + + val multipart = this.getBlockEntity(pos) + as? MultipartBlockEntity + + if (multipart == null) { + LOG.error("Multipart null at $pos") + + return + } + + val saveTag = CompoundTag() + + multipart.breakPart(part, saveTag) + + if(dropPart) { + val itemEntity = ItemEntity( + this, + pos.x.toDouble(), + pos.y.toDouble(), + pos.z.toDouble(), + Part.createPartDropStack(part.id, saveTag) + ) + + this.addFreshEntity(itemEntity) + } + + if (multipart.isEmpty) { + this.destroyBlock(pos, false) + } +} + +inline fun Level.constructMenu( + pos: BlockPos, + player: Player, + crossinline title: (() -> Component), + factory: ContainerFactory, +): InteractionResult { + + if (!this.isClientSide) { + val entity = this.getBlockEntity(pos) as? TEntity + ?: return InteractionResult.FAIL + + val containerProvider = object : MenuProvider { + override fun getDisplayName(): Component { + return title() + } + + override fun createMenu( + pContainerId: Int, + pInventory: Inventory, + pPlayer: Player, + ): AbstractContainerMenu { + return factory.create( + pContainerId, + pInventory, + pPlayer, + entity + ) + } + } + + NetworkHooks.openScreen(player as ServerPlayer, containerProvider, entity.blockPos) + return InteractionResult.SUCCESS + } + + return InteractionResult.SUCCESS +} + +inline fun Level.constructMenu( + pos: BlockPos, + player: Player, + crossinline title: (() -> Component), + crossinline factory: ((Int, Inventory, ItemStackHandler) -> AbstractContainerMenu), + crossinline accessor: ((TEntity) -> ItemStackHandler), +): InteractionResult { + + return this.constructMenu(pos, player, title) { id, inventory, _, entity -> + factory(id, inventory, accessor(entity)) + } +} + +fun Level.getDataAccess(pos: BlockPos): DataNode? { + return ((this.getBlockEntity(pos) ?: return null) + as? DataEntity ?: return null) + .dataNode +} + +inline fun Level.getCellOrNull(mb: MultiblockManager, cellPosId: BlockPos): T? { + val entity = this.getBlockEntity(mb.txIdWorld(cellPosId)) as? CellBlockEntity + ?: return null + + return entity.cell as? T +} + +inline fun Level.getCell(mb: MultiblockManager, cellPosId: BlockPos): T = + getCellOrNull(mb, cellPosId) ?: error("Cell was not present") + +private const val LIBAGE_SET_EPS = 0.001 +fun org.ageseries.libage.sim.electrical.mna.component.Component.connect(pin: Int, info: ElectricalComponentInfo) { + this.connect(pin, info.component, info.index) +} + +fun Circuit.add(holder: ComponentHolder<*>) { + this.add(holder.instance) +} + +fun Resistor.setResistanceEpsilon(resistance: Double, epsilon: Double = LIBAGE_SET_EPS): Boolean { + if (abs(this.resistance - resistance) < epsilon) { + return false + } + + this.resistance = resistance + + return true +} + +fun VoltageSource.setPotentialEpsilon(potential: Double, epsilon: Double = LIBAGE_SET_EPS): Boolean { + if (abs(this.potential - potential) < epsilon) { + return false + } + + this.potential = potential + + return true +} + +fun Simulator.add(body: ThermalBody) { + this.add(body.thermal) +} + +fun Simulator.remove(body: ThermalBody) { + this.remove(body.thermal) +} + +fun Simulator.connect(a: ThermalBody, b: ThermalBody, parameters: ConnectionParameters) { + this.connect(a.thermal, b.thermal, parameters) +} + +fun Simulator.connect(a: ThermalMass, environmentInformation: EnvironmentInformation) { + val connectionInfo = ConnectionParameters( + conductance = environmentInformation.airThermalConductivity + ) + + this.connect(a, environmentInformation.temperature, connectionInfo) +} + +fun Simulator.connect(a: ThermalBody, environmentInformation: EnvironmentInformation) { + this.connect(a.thermal, environmentInformation) +} + +/** + * This removes the translation I observed in BlockBench models. + * Useful for applying transformations like rotation and scale. + * */ +fun ModelData.zeroCenter(): ModelData { + return this.translate(Vec3(-0.5, 0.0, -0.5)) +} + +fun ModelData.blockCenter(): ModelData { + return this.translate(Vec3(0.5, 0.0, 0.5)) +} + +private const val NBT_ELECTRICAL_RESISTIVITY = "electricalResistivity" +private const val NBT_THERMAL_CONDUCTIVITY = "thermalConductivity" +private const val NBT_SPECIFIC_HEAT = "specificHeat" +private const val NBT_DENSITY = "density" +private const val NBT_MATERIAL_NAME = "materialName" +private const val NBT_ENERGY = "energy" +private const val NBT_MASS = "mass" +private const val NBT_MATERIAL = "material" +fun CompoundTag.putBlockPos(key: String, pos: BlockPos) { + val dataTag = CompoundTag() + dataTag.putInt("X", pos.x) + dataTag.putInt("Y", pos.y) + dataTag.putInt("Z", pos.z) + this.put(key, dataTag) +} + +fun CompoundTag.getBlockPos(key: String): BlockPos { + val dataTag = this.get(key) as CompoundTag + val x = dataTag.getInt("X") + val y = dataTag.getInt("Y") + val z = dataTag.getInt("Z") + + return BlockPos(x, y, z) +} + +fun CompoundTag.putLocatorSet(id: String, descriptor: LocatorSet) { + this.put(id, descriptor.toNbt()) +} + +fun CompoundTag.getLocatorSet(id: String): LocatorSet { + return LocatorSet.fromNbt(this.getCompound(id)) +} + +fun CompoundTag.getStringList(key: String): List { + val tag = this.getCompound(key) + return tag.allKeys.map { tag.getString(it) } +} + +fun CompoundTag.putStringList(key: String, list: List) { + val tag = CompoundTag() + list.forEachIndexed { index, it -> + tag.putString("$index", it) + } + this.put(key, tag) +} + +fun CompoundTag.getStringMap(key: String): Map { + val tag = this.getCompound(key) + val map = mutableMapOf() + tag.allKeys.forEach { tagKey -> + val tagValue = tag.getString(tagKey) + map[tagKey] = tagValue + } + return map +} + +fun CompoundTag.putStringMap(key: String, map: Map) { + val tag = CompoundTag() + map.forEach { (k, v) -> + tag.putString(k, v) + } + this.put(key, tag) +} + +fun CompoundTag.putResourceLocation(key: String, resourceLocation: ResourceLocation) { + this.putString(key, resourceLocation.toString()) +} + +fun CompoundTag.tryGetResourceLocation(key: String): ResourceLocation? { + val str = this.getString(key) + + return ResourceLocation.tryParse(str) +} + +fun CompoundTag.getResourceLocation(key: String): ResourceLocation { + return this.tryGetResourceLocation(key) ?: error("Invalid resource location with key $key") +} + +fun CompoundTag.putDirection(key: String, direction: Direction) { + this.putInt(key, direction.get3DDataValue()) +} + +fun CompoundTag.getDirection(key: String): Direction { + val data3d = this.getInt(key) + + return Direction.from3DDataValue(data3d) +} + +fun CompoundTag.putRelativeDirection(key: String, direction: Base6Direction3d) { + val data = direction.id + + this.putInt(key, data) +} + +fun CompoundTag.getDirectionActual(key: String): Base6Direction3d { + val data = this.getInt(key) + + return Base6Direction3d.fromId(data) +} + +fun CompoundTag.putPartUpdateType(key: String, type: PartUpdateType) { + val data = type.id + + this.putInt(key, data) +} + +fun CompoundTag.getPartUpdateType(key: String): PartUpdateType { + val data = this.getInt(key) + + return PartUpdateType.fromId(data) +} + +/** + * Creates a new compound tag, calls the consumer method with the new tag, and adds the created tag to this instance. + * @return The Compound Tag that was created. + * */ +fun CompoundTag.putSubTag(key: String, consumer: ((CompoundTag) -> Unit)): CompoundTag { + val tag = CompoundTag() + + consumer(tag) + + this.put(key, tag) + + return tag +} + +fun CompoundTag.withSubTag(key: String, tag: CompoundTag): CompoundTag { + this.put(key, tag) + return this +} + +fun CompoundTag.withSubTagOptional(key: String, tag: CompoundTag?): CompoundTag { + if (tag != null) { + this.put(key, tag) + } + + return this +} + +/** + * Gets the compound tag from this instance, and calls the consumer method with the found tag. + * @return The tag that was found. + * */ +fun CompoundTag.useSubTag(key: String, consumer: ((CompoundTag) -> Unit)): CompoundTag { + val tag = this.get(key) as CompoundTag + consumer(tag) + + return tag +} + +fun CompoundTag.placeSubTag(key: String, consumer: ((CompoundTag) -> Unit)): CompoundTag { + val tag = CompoundTag() + consumer(tag) + + this.put(key, tag) + + return tag +} + +/** + * Gets the compound tag from this instance, and calls the consumer method with the found tag. + * @return The tag that was found. + * */ +fun CompoundTag.useSubTagIfPreset(key: String, consumer: ((CompoundTag) -> Unit)): CompoundTag? { + val tag = this.get(key) as? CompoundTag + ?: return null + + consumer(tag) + + return tag +} + +fun CompoundTag.putMaterial(id: String, material: Material) { + this.putSubTag(id) { + it.putDouble(NBT_ELECTRICAL_RESISTIVITY, material.electricalResistivity) + it.putDouble(NBT_THERMAL_CONDUCTIVITY, material.thermalConductivity) + it.putDouble(NBT_SPECIFIC_HEAT, material.specificHeat) + it.putDouble(NBT_DENSITY, material.density) + } +} + +fun CompoundTag.getMaterial(id: String): Material { + val tag = this.getCompound(id) + + return Material( + tag.getDouble(NBT_ELECTRICAL_RESISTIVITY), + tag.getDouble(NBT_THERMAL_CONDUCTIVITY), + tag.getDouble(NBT_SPECIFIC_HEAT), + tag.getDouble(NBT_DENSITY) + ) +} + +fun CompoundTag.putMaterialMapped(id: String, material: Material) { + this.putSubTag(id) { + it.putString(NBT_MATERIAL_NAME, MaterialMapping.getName(material)) + } +} + +fun CompoundTag.getMaterialMapped(id: String): Material { + val tag = this.getCompound(id) + + return MaterialMapping.getMaterial(tag.getString(NBT_MATERIAL_NAME)) +} + +fun CompoundTag.putThermalMass( + id: String, + thermalMass: ThermalMass, + materialSerializer: ((String, Material, CompoundTag) -> Unit), +) { + this.putSubTag(id) { + materialSerializer(NBT_MATERIAL, thermalMass.material, it) + it.putDouble(NBT_ENERGY, thermalMass.energy) + it.putDouble(NBT_MASS, thermalMass.mass) + } +} + +fun CompoundTag.getThermalMass(id: String, materialDeserializer: ((String, CompoundTag) -> Material)): ThermalMass { + val tag = this.getCompound(id) + + return ThermalMass( + materialDeserializer(NBT_MATERIAL, tag), + tag.getDouble(NBT_ENERGY), + tag.getDouble(NBT_MASS) + ) +} + +fun CompoundTag.putThermalMass(id: String, thermalMass: ThermalMass) { + this.putThermalMass(id, thermalMass) { key, material, tag -> + tag.putMaterial(key, material) + } +} + +fun CompoundTag.putThermalMassMapped(id: String, thermalMass: ThermalMass) { + this.putThermalMass(id, thermalMass) { key, material, tag -> + tag.putMaterialMapped(key, material) + } +} + +fun CompoundTag.getThermalMass(id: String): ThermalMass { + return this.getThermalMass(id) { key, tag -> + tag.getMaterial(key) + } +} + +fun CompoundTag.getThermalMassMapped(id: String): ThermalMass { + return this.getThermalMass(id) { key, tag -> + tag.getMaterialMapped(key) + } +} + +fun CompoundTag.putThermalBody(id: String, body: ThermalBody) { + this.putSubTag(id) { + it.putThermalMass("Mass", body.thermal) + it.putDouble("Area", body.area) + } +} + +fun CompoundTag.getThermalBody(id: String): ThermalBody { + val tag = this.getCompound(id) + + return ThermalBody( + tag.getThermalMass("Mass"), + tag.getDouble("Area") + ) +} + +fun CompoundTag.putTemperature(id: String, temperature: Temperature) { + this.putDouble(id, temperature.kelvin) +} + +fun CompoundTag.getTemperature(id: String): Temperature { + return Temperature(this.getDouble(id)) +} + +fun Double.formatted(decimals: Int = 2): String { + return "%.${decimals}f".format(this) +} + +fun Double.formattedPercentN(decimals: Int = 2): String { + return "${(this * 100.0).formatted(decimals)}%" +} + +fun Rotation.inverse() = when (this) { + Rotation.NONE -> Rotation.NONE + Rotation.CLOCKWISE_90 -> Rotation.COUNTERCLOCKWISE_90 + Rotation.CLOCKWISE_180 -> Rotation.CLOCKWISE_180 + Rotation.COUNTERCLOCKWISE_90 -> Rotation.CLOCKWISE_90 +} + +operator fun Rotation.times(p: BlockPos) = p.rotate(this) +fun rot(dir: Direction) = when (dir) { + Direction.NORTH -> Rotation.COUNTERCLOCKWISE_90 + Direction.SOUTH -> Rotation.CLOCKWISE_90 + Direction.WEST -> Rotation.CLOCKWISE_180 + Direction.EAST -> Rotation.NONE + else -> error("Invalid horizontal facing $dir") +} + +fun ThermalMass.appendBody(builder: WailaTooltipBuilder, config: IPluginConfig?) { + builder.energy(this.energy) + builder.mass(this.mass) + builder.temperature(this.temperature.kelvin) +} + +fun Simulator.subStep(dt: Double, steps: Int, consumer: ((Int, Double) -> Unit)? = null) { + val stepSize = dt / steps + + repeat(steps) { + this.step(stepSize) + consumer?.invoke(it, stepSize) + } +} + +fun WailaTooltipBuilder.resistor(resistor: Resistor): WailaTooltipBuilder { + this.resistance(resistor.resistance) + this.pinVoltages(resistor.pins) + this.current(resistor.current) + this.power(resistor.power) + + return this +} + +fun WailaTooltipBuilder.voltageSource(source: VoltageSource): WailaTooltipBuilder { + this.voltage(source.potential) + this.current(source.current) + + return this +} + +operator fun Vec3.plus(b: Vec3): Vec3 { + return Vec3(this.x + b.x, this.y + b.y, this.z + b.z) +} + +operator fun Vec3.plus(delta: Double): Vec3 { + return Vec3(this.x + delta, this.y + delta, this.z + delta) +} + +operator fun Vec3.minus(b: Vec3): Vec3 { + return Vec3(this.x - b.x, this.y - b.y, this.z - b.z) +} + +operator fun Vec3.minus(delta: Double): Vec3 { + return Vec3(this.x - delta, this.y - delta, this.z - delta) +} + +operator fun Vec3.times(b: Vec3): Vec3 { + return Vec3(this.x * b.x, this.y * b.y, this.z * b.z) +} + +operator fun Vec3.times(scalar: Double): Vec3 { + return Vec3(this.x * scalar, this.y * scalar, this.z * scalar) +} + +operator fun Vec3.div(b: Vec3): Vec3 { + return Vec3(this.x / b.x, this.y / b.y, this.z / b.z) +} + +operator fun Vec3.div(scalar: Double): Vec3 { + return Vec3(this.x / scalar, this.y / scalar, this.z / scalar) +} + +operator fun Vec3.unaryMinus(): Vec3 { + return Vec3(-this.x, -this.y, -this.z) +} + +operator fun Vec3.unaryPlus(): Vec3 { + // For completeness + + return Vec3(this.x, this.y, this.z) +} + +fun Vec3i.toVec3(): Vec3 { + return Vec3(this.x.toDouble(), this.y.toDouble(), this.z.toDouble()) +} + +fun BlockPos.toVector3d() = Vector3d(this.x.toDouble(), this.y.toDouble(), this.z.toDouble()) +fun BlockPos.toVector3di() = Vector3di(this.x, this.y, this.z) + +fun BlockEntity.sendClientUpdate() = + this.level!!.sendBlockUpdated(this.blockPos, this.blockState, this.blockState, Block.UPDATE_CLIENTS) + +fun MutableSetMapMultiMap.bind(): MutableSetMapMultiMap { + val result = MutableSetMapMultiMap() + + this.keys.forEach { k -> + result[k].addAll(this[k]) + } + + return result +} + +fun ArrayList.bind() = ArrayList(this.size).also { it.addAll(this) } + +@Suppress("UNCHECKED_CAST") +fun HashMap.bind() = this.clone() as HashMap + +fun MutableList.swapi(i: Int, j: Int) { + val tmp = this[i] + this[i] = this[j] + this[j] = tmp +} + +fun Entity.moveTo(v: Vector3d) = this.moveTo(v.x, v.y, v.z) +fun Vector3d.toVec3() = Vec3(this.x, this.y, this.z) + +fun CompoundTag.putQuantity(key: String, e: Quantity) = this.putDouble(key, !e) +fun CompoundTag.getQuantity(key: String) = Quantity(this.getDouble(key)) + +inline fun Iterable.associateWithBi(valueSelector: (K) -> V): BiMap { + val result = mutableBiMapOf() + + this.forEach { k -> + result.add(k, valueSelector(k)) + } + + return result +} + +fun ByteBuffer.putVector3di(v: Vector3di) { + this.putInt(v.x) + this.putInt(v.y) + this.putInt(v.z) +} + +fun ByteBuffer.getVector3di() = Vector3di( + this.int, + this.int, + this.int +) + +fun Direction.valueHashCode() = this.normal.hashCode() + +fun Vector3di.toBlockPos() = BlockPos(this.x, this.y, this.z) +fun Vec3.toVector3d() = Vector3d(this.x, this.y, this.z) + +fun Scale.map(u: Dual) = factor * u + base +fun Scale.unmap(u: Dual) = (u - base) / factor + +fun ChunkPos.toVector2d() = Vector2d(this.x.toDouble(), this.z.toDouble()) + +fun List.averageOf(valueSelector: (T) -> Double): Double = this.sumOf(valueSelector) / this.size +fun Collection.sumOfDual(n: Int, dualSelector: (T) -> Dual): Dual { + var result = Dual.const(0.0, n) + this.forEach { result += dualSelector(it) } + return result +} + +// This thing is so useful: + +fun MutableMap.increment(k: K, incr: Double) { + if (!this.containsKey(k)) this[k] = incr + else this[k] = this[k]!! + incr +} + +fun MutableMap.increment(k: K, incr: Int) { + if (!this.containsKey(k)) this[k] = incr + else this[k] = this[k]!! + incr +} + +fun OutputStream.putIntPacked(i: Int) { + var value = i + do { + var b = (value and 0xFF).toByte() + if (value >= 0x80) { + b = (b.toInt() or 0x80).toByte() + } + this.write(b.toInt()) + value = value shr 7 + } while (value > 0) +} + +fun OutputStream.putByteArray(arr: ByteArray) { + this.putIntPacked(arr.size) + if (arr.isNotEmpty()) this.write(arr) +} + +fun OutputStream.putString(s: String) = this.putByteArray(s.encodeToByteArray()) +fun OutputStream.putBool(b: Boolean) = this.write(if (b) 1 else 0) +fun OutputStream.putFloat(f: Float) = this.putIntPacked(f.toBits()) +fun OutputStream.putNullable(t: T?, serialize: (OutputStream, T) -> Unit) { + this.putBool(t != null) + if (t != null) { + serialize(this, t) + } +} + +fun OutputStream.putList(s: List, serialize: (OutputStream, T) -> Unit) { + this.putIntPacked(s.size) + s.forEach { serialize(this, it) } +} + +fun OutputStream.putFloatList(s: List) = this.putList(s) { o, f -> o.putFloat(f) } +fun OutputStream.putStringList(s: List) = this.putList(s) { o, f -> o.putString(f) } +fun InputStream.getIntPacked(): Int { + var grissess = true + var lsc = 0 + var result = 0 + + while (grissess) { + var b = this.read() + if (b >= 0x80) { + grissess = true + b = (b xor 0x80) + } else { + grissess = false + } + result = result or (b shl lsc) + lsc += 7 + } + + return result +} + +fun InputStream.getByteArray(): ByteArray { + val sz = this.getIntPacked() + if (sz == 0) return ByteArray(0) + return this.readNBytes(sz) +} + +fun InputStream.getString() = this.getByteArray().decodeToString() +fun InputStream.getBool() = this.read() == 1 +fun InputStream.getFloat() = Float.fromBits(this.getIntPacked()) +fun InputStream.getNullable(deserialize: (InputStream) -> T) = + if (this.getBool()) deserialize(this) + else null + +fun InputStream.getList(deserialize: (InputStream) -> T) = this.getIntPacked().let { sz -> + ArrayList(sz).also { list -> + repeat(sz) { list.add(deserialize(this)) } + } +} + +fun InputStream.getFloatList() = this.getList { it.getFloat() } +fun InputStream.getStringList() = this.getList { it.getString() } diff --git a/src/main/kotlin/org/eln2/mc/Libage.kt b/src/main/kotlin/org/eln2/mc/Libage.kt new file mode 100644 index 00000000..011d4fcd --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Libage.kt @@ -0,0 +1,77 @@ +package org.eln2.mc + +import mcp.mobius.waila.api.IPluginConfig +import org.ageseries.libage.data.biMapOf +import org.ageseries.libage.sim.Material +import org.ageseries.libage.sim.thermal.Temperature +import org.ageseries.libage.sim.thermal.ThermalMass +import org.eln2.mc.data.DataFieldMap +import org.eln2.mc.integration.WailaEntity +import org.eln2.mc.integration.WailaTooltipBuilder + +object MaterialMapping { + private val map = biMapOf( + "iron" to Material.IRON + ) + + fun getMaterial(name: String): Material { + return map.forward[name] ?: error("Name $name does not correspond to any material.") + } + + fun getName(material: Material): String { + return map.backward[material] ?: error("Material $material does not have a mapping!") + } +} + +data class ThermalBodyDef(val material: Material, val mass: Double, val area: Double, val energy: Double? = null) { + fun create() = ThermalBody( + ThermalMass( + material, + energy, + mass, + ), + area + ) +} + +val nullMaterial = Material(0.0, 0.0, 0.0, 0.0) +fun nullThermalMass() = ThermalMass(nullMaterial, 0.0, 0.0) +fun nullThermalBody() = ThermalBody(nullThermalMass(), 0.0) + +class ThermalBody(var thermal: ThermalMass, var area: Double) : WailaEntity { + var temp: Temperature + get() = thermal.temperature + set(value) { + thermal.temperature = value + } + + var tempK: Double + get() = temp.kelvin + set(value) { + thermal.temperature = Temperature(value) + } + + var energy: Double + get() = thermal.energy + set(value) { + thermal.energy = value + } + + override fun appendWaila(builder: WailaTooltipBuilder, config: IPluginConfig?) { + thermal.appendBody(builder, config) + } + + companion object { + fun createDefault(): ThermalBody { + return ThermalBody(ThermalMass(Material.COPPER), 0.5) + } + + fun createDefault(env: DataFieldMap): ThermalBody { + return createDefault().also { b -> + env.get()?.readTemperature()?.also { + b.temp = it + } + } + } + } +} diff --git a/src/main/kotlin/org/eln2/mc/Reflection.kt b/src/main/kotlin/org/eln2/mc/Reflection.kt new file mode 100644 index 00000000..c140d39f --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Reflection.kt @@ -0,0 +1,170 @@ +package org.eln2.mc + +import java.util.concurrent.ConcurrentHashMap +import kotlin.reflect.KClass +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.javaField + +fun noop() {} + +/** + * Scans the target class [I] for fields annotated with [FA], and creates a list of [FieldReader]s, caching the result in [target]. + * The field types must be subclasses of [superK] + * */ +fun fieldScan( + inst: Class, + superK: KClass<*>, + annotC: Class, + target: ConcurrentHashMap, List>>, +): List> { + return target.getOrPut(inst) { + val accessors = mutableListOf>() + + inst.kotlin + .memberProperties + .filter { it.javaField?.isAnnotationPresent(annotC) ?: false } + .forEach { + if (!(it.returnType.classifier as KClass<*>).isSubclassOf(superK)) { + error("Invalid $superK field $it") + } + + accessors.add(it::get) + } + + accessors + } +} + +fun interface FieldReader { + fun get(inst: I): Any? +} + +private val classId = HashMap, Int>() + +val KClass<*>.reflectId: Int + get() = synchronized(classId) { + classId.getOrPut(this) { + val result = (this.qualifiedName ?: error("Failed to get name of $this")).hashCode() + + if (classId.values.any { it == result }) { + error("reflect ID collision $this") + } + + result + } + } + +fun interface ServiceProvider { + fun getInstance(): T +} + +fun interface ExternalResolver { + fun resolve(c: Class<*>): Any? +} + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CONSTRUCTOR) +annotation class Inj + +class ServiceCollection { + private val services = HashMap, ServiceProvider<*>>() + private val externalResolvers = ArrayList() + + fun withService(c: Class, provider: ServiceProvider): ServiceCollection { + if (services.put(c, provider) != null) { + error("Duplicate service $c") + } + + return this + } + + inline fun withService(provider: ServiceProvider) = withService(T::class.java, provider) + + fun withExternalResolver(r: ExternalResolver): ServiceCollection { + externalResolvers.add(r) + return this + } + + fun resolve(c: Class<*>): Any? { + var instance = services[c]?.getInstance() + + if (instance != null) { + return instance + } + + externalResolvers.forEach { + instance = it.resolve(c) + + if (instance != null) { + return instance + } + } + + return null + } + + fun activate(c: Class<*>, extraParams: List): Any { + // If @Inj is used on any of the constructors, only constructors annotated with @Inj are used. Otherwise, all constructors are used. + val activators = activators.getOrPut(c) { + val constructors = if (c.constructors.any { it.getAnnotation(Inj::class.java) != null }) { + c.constructors.filter { it.getAnnotation(Inj::class.java) != null } + } else { + c.constructors.toList() + } + + ArrayList( + constructors.map { ctor -> + val args = ArrayList>() + + ctor.parameters.forEach { + val pClass = it.parameterizedType as Class<*> + + if (args.contains(pClass)) { + error("Ambiguous inject parameter $it") + } + + args.add(pClass) + } + + ActivatorRsi(ArrayList(args)) { inst -> ctor.newInstance(*inst) } + } + ) + } + + activators.forEach { rsi -> + val args = Array(rsi.parameters.size) { null } + + rsi.parameters.forEachIndexed { index, paramClass -> + args[index] = resolve(paramClass) + ?: extraParams.firstOrNull { it.javaClass == paramClass } + ?: return@forEach + } + + return rsi.activator(args) + } + + error("Failed to solve constructor for $c") + } + + inline fun activate(extraParams: List): T = activate(T::class.java, extraParams) as T + + private data class ActivatorRsi( + val parameters: ArrayList>, + val activator: (Array) -> Any, + ) + + companion object { + private val activators = ConcurrentHashMap, ArrayList>() + } +} + +inline fun ServiceCollection.withSingleton(noinline resolver: () -> T): ServiceCollection { + val lazy = lazy(resolver) + return this.withService { lazy.value } +} + +fun ServiceCollection.withSingleton(c: Class, resolver: () -> T): ServiceCollection { + val lazy = lazy(resolver) + return this.withService(c) { lazy.value } +} diff --git a/src/main/kotlin/org/eln2/mc/Symbols.kt b/src/main/kotlin/org/eln2/mc/Symbols.kt new file mode 100644 index 00000000..27fa5ec1 --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Symbols.kt @@ -0,0 +1,50 @@ +package org.eln2.mc + +const val ALPHA = "Α" +const val alpha = "α" +const val BETA = "Β" +const val beta = "β" +const val GAMMA = "Γ" +const val gamma = "γ" +const val DELTA = "Δ" +const val delta = "δ" +const val EPSILON = "Ε" +const val epsilon = "ε" +const val ZETA = "Ζ" +const val zeta = "ζ" +const val ETA = "Η" +const val eta = "η" +const val THETA = "Θ" +const val theta = "θ" +const val IOTA = "Ι" +const val iota = "ι" +const val KAPPA = "Κ" +const val kappa = "κ" +const val LAMBDA = "Λ" +const val lambda = "λ" +const val MU = "Μ" +const val mu = "μ" +const val NU = "Ν" +const val nu = "ν" +const val XI = "Ξ" +const val xi = "ξ" +const val OMICRON = "Ο" +const val omicron = "ο" +const val PI = "Π" +const val pi = "π" +const val RHO = "Ρ" +const val rho = "ρ" +const val SIGMA = "Σ" +const val sigma = "σ" +const val TAU = "Τ" +const val tau = "τ" +const val UPSILON = "Υ" +const val upsilon = "υ" +const val PHI = "Φ" +const val phi = "φ" +const val CHI = "Χ" +const val chi = "χ" +const val PSI = "Ψ" +const val psi = "ψ" +const val OMEGA = "Ω" +const val omega = "ω" diff --git a/src/main/kotlin/org/eln2/mc/Utilities.kt b/src/main/kotlin/org/eln2/mc/Utilities.kt new file mode 100644 index 00000000..5b59b005 --- /dev/null +++ b/src/main/kotlin/org/eln2/mc/Utilities.kt @@ -0,0 +1,278 @@ +package org.eln2.mc + +import net.minecraft.core.BlockPos +import net.minecraft.sounds.SoundEvent +import net.minecraft.sounds.SoundEvents +import net.minecraft.sounds.SoundSource +import net.minecraft.world.InteractionHand +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.ItemUtils +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.entity.BlockEntityTicker +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 +import org.ageseries.libage.data.MultiMap +import org.ageseries.libage.data.MutableSetMapMultiMap +import org.eln2.mc.data.CsvLoader +import org.eln2.mc.data.NANOSECONDS +import org.eln2.mc.data.Quantity +import org.eln2.mc.data.Time +import org.eln2.mc.mathematics.* +import org.joml.Vector3f +import kotlin.math.max +import kotlin.math.min +import kotlin.system.measureNanoTime + +fun all(vararg items: T, condition: (T) -> Boolean) = items.asList().all(condition) + +fun measureDuration(block: () -> Unit) = Quantity( + measureNanoTime(block).toDouble(), NANOSECONDS +) + +val digitRange = '0'..'9' +val subscriptDigitRange = '₀'..'₉' + +operator fun CharRange.get(x: Int) = this.elementAt(x) + +val Char.isLetter get() = this in 'a'..'z' || this in 'A'..'Z' +val Char.isDigit get() = this in digitRange +val Char.isSubscriptDigit get() = this in subscriptDigitRange +val Char.isDigitOrSubscriptDigit get() = this.isDigit || this.isSubscriptDigit + +fun subscriptToDigit(c: Char): Char { + require(c.isSubscriptDigit) { "$c is not a subscript digit" } + return digitRange[subscriptDigitRange.indexOf(c)] +} + +fun digitToSubscript(c: Char): Char { + require(c.isDigit) { "$c is not a digit" } + return subscriptDigitRange[digitRange.indexOf(c)] +} + +fun Int.toStringSubscript() = String(this.toString().map { digitToSubscript(it) }.toCharArray()) + +fun charDigitValue(c: Char): Char { + if (c.isDigit) return c + if (c.isSubscriptDigit) return subscriptToDigit(c) + error("$c is not a digit or subscript digit") +} + +inline fun List.associateByMulti(keySelector: (T) -> K): MultiMap { + val result = MutableSetMapMultiMap() + this.forEach { value -> result[keySelector(value)].add(value) } + return result +} + +inline fun Array.associateByMulti(keySelector: (T) -> K): MultiMap { + val result = MutableSetMapMultiMap() + this.forEach { value -> result[keySelector(value)].add(value) } + return result +} + + +inline fun Set.associateByMulti(keySelector: (T) -> K): MultiMap { + val result = MutableSetMapMultiMap() + this.forEach { value -> result[keySelector(value)].add(value) } + return result +} + + +inline fun Collection.associateByMulti(keySelector: (T) -> K): MultiMap { + val result = MutableSetMapMultiMap() + this.forEach { value -> result[keySelector(value)].add(value) } + return result +} + +@Suppress("UNCHECKED_CAST") +fun ticker(f: (pLevel: Level, pPos: BlockPos, pState: BlockState, pBlockEntity: U) -> Unit) = + BlockEntityTicker { level, pos, state, e -> + f(level, pos, state, e as U) + } + +fun clipScene(entity: LivingEntity, access: ((T) -> AABB), objects: Collection): T? { + val intersections = LinkedHashMap() + + val eyePos = Vec3(entity.x, entity.eyeY, entity.z) + + objects.forEach { obj -> + val box = access(obj) + + val intersection = box.viewClip(entity) + + if (!intersection.isEmpty) { + intersections[intersection.get()] = obj + } + } + + val entry = intersections.minByOrNull { entry -> + (eyePos - entry.key).length() + } + + return entry?.value +} + +fun componentMin(a: Vector3f, b: Vector3f): Vector3f { + return Vector3f( + min(a.x(), b.x()), + min(a.y(), b.y()), + min(a.z(), b.z()) + ) +} + +fun componentMax(a: Vector3f, b: Vector3f): Vector3f { + return Vector3f( + max(a.x(), b.x()), + max(a.y(), b.y()), + max(a.z(), b.z()) + ) +} + +class Stopwatch { + private var initialTimeStamp = System.nanoTime() + private var lastTimeStamp = initialTimeStamp + + fun sample(): Quantity