commit 84e394e1898acc31b5bfb7e8a39e0d636c9cdf69 Author: Oier Bravo Urtasun Date: Thu Sep 26 00:04:47 2024 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c37caf --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7436249 --- /dev/null +++ b/build.gradle @@ -0,0 +1,193 @@ +plugins { + id 'eclipse' + id 'idea' + id 'net.minecraftforge.gradle' version '[6.0.16,6.2)' + id 'maven-publish' +} + + +group = "com.${author}.${modid}" +version = "${minecraft_version}-${mod_version}" +archivesBaseName = modid + +java { + toolchain.languageVersion = JavaLanguageVersion.of(17) +} + +minecraft { + // The mappings can be changed at any time and must be in the following format. + // Channel: Version: + // official MCVersion Official field/method names from Mojang mapping files + // parchment YYYY.MM.DD-MCVersion Open community-sourced parameter names and javadocs layered on top of official + // + // You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. + // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md + // + // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge + // Additional setup is needed to use their mappings: https://parchmentmc.org/docs/getting-started + // + // Use non-default mappings at your own risk. They may not always work. + // Simply re-run your setup task after changing the mappings to update your workspace. + mappings channel: mapping_channel, version: mapping_version + + // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game. + // In most cases, it is not necessary to enable. + // enableEclipsePrepareRuns = true + // enableIdeaPrepareRuns = true + + // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game. + // It is REQUIRED to be set to true for this template to function. + // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html + copyIdeResources = true + + // When true, this property will add the folder name of all declared run configurations to generated IDE run configurations. + // The folder name can be set on a run configuration using the "folderName" property. + // By default, the folder name of a run configuration is the name of the Gradle project containing it. + // generateRunFolders = true + + // This property enables access transformers for use in development. + // They will be applied to the Minecraft artifact. + // The access transformer file can be anywhere in the project. + // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge. + // This default location is a best practice to automatically put the file in the right place in the final jar. + // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information. + // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + // applies to all the run configs below + configureEach { + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + // 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' + + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + property 'forge.logging.console.level', 'debug' + + mods { + "${modid}" { + source sourceSets.main + } + } + } + + client { + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', modid + } + + server { + property 'forge.enabledGameTestNamespaces', modid + args '--nogui' + } + + // This run config launches GameTestServer and runs all registered gametests, then exits. + // By default, the server will crash when no gametests are provided. + // The gametest system is also enabled by default for other run configs under the /test command. + gameTestServer { + property 'forge.enabledGameTestNamespaces', modid + } + + data { + // example of overriding the workingDirectory set in configureEach above + workingDirectory project.file('run-data') + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + args '--mod', modid, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + } + } +} + +// Include resources generated by data generators. +sourceSets.main.resources { srcDir 'src/generated/resources' } + +repositories { + maven { + // location of the maven for Registrate and Flywheel + name = 'tterrag maven' + url = 'https://maven.tterrag.com' + } + maven { + // location of the maven that hosts JEI files since January 2023 + // location of the maven for Vazkii's mods + name = "Jared's maven" + url = "https://maven.blamejared.com/" + } + maven { + // location of the maven for Curios API + url = "https://maven.theillusivec4.top/" + } + maven { + url = 'https://www.cursemaven.com' + content { + includeGroup "curse.maven" + } + } +} + +dependencies { + minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" + + + compileOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}-common-api:${jei_version}") + compileOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}-forge-api:${jei_version}") + runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}-forge:${jei_version}") + + implementation fg.deobf("curse.maven:jade-324717:${jade_id}") + +} + +// This block of code expands all declared replace properties in the specified resource targets. +// A missing property will result in an error. Properties are expanded using ${} Groovy notation. +// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. +// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html +tasks.named('processResources', ProcessResources).configure { + var replaceProperties = [minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, + forge_version : forge_version, forge_version_range: forge_version_range, + loader_version_range: loader_version_range, + modid : modid, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, + author : author, mod_description: mod_description,] + + inputs.properties replaceProperties + + filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { + expand replaceProperties + [project: project] + } +} + +// Example for how to get properties into the manifest for reading at runtime. +tasks.named('jar', Jar).configure { + manifest { + attributes(["Specification-Title" : modid, + "Specification-Vendor" : author, + "Specification-Version" : "1", // We are version 1 of ourselves + "Implementation-Title" : project.name, + "Implementation-Version" : project.jar.archiveVersion, + "Implementation-Vendor" : author, + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")]) + } + + // This is the preferred method to reobfuscate your jar file + finalizedBy 'reobfJar' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation +} +publishing { + // other settings of publication + publications { + mavenJava(MavenPublication) { + artifact jar + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..ae5d6ed --- /dev/null +++ b/gradle.properties @@ -0,0 +1,26 @@ +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false + +minecraft_version=1.20.1 +minecraft_version_range=[1.20.1,1.21) +forge_version=47.3.7 +forge_version_range=[47,) +loader_version_range=[47,) +mapping_channel=official +mapping_version=1.20.1 + +modid=mechanical_lemon_ui +mod_name=Mechanical Lemon UI +mod_license=MIT +mod_version=0.0.2 +mod_group_id=com.oierbravo +author=oierbravo +mod_description=Library + + +jei_minecraft_version = 1.20.1 +jei_version = 15.2.0.22 +curios_minecraft_version = 1.20.1 +curios_version = 5.2.0-beta.3 + +jade_id = 4654448 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e644113 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..a441313 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..b740cf1 --- /dev/null +++ b/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + 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. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..7101f8e --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +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! +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 + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..396089d --- /dev/null +++ b/settings.gradle @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = 'MinecraftForge' + url = 'https://maven.minecraftforge.net/' + } + } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' +} + +rootProject.name = 'MechanicalLemonUI' diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/MechanicalLemonUI.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/MechanicalLemonUI.java new file mode 100644 index 0000000..ced4aea --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/MechanicalLemonUI.java @@ -0,0 +1,31 @@ +package com.oierbravo.mechanical_lemon_ui; + +import com.mojang.logging.LogUtils; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.slf4j.Logger; + +// The value here should match an entry in the META-INF/mods.toml file +@Mod(MechanicalLemonUI.MODID) +public class MechanicalLemonUI { + + public static final String MODID = "mechanical_lemon_ui"; + private static final Logger LOGGER = LogUtils.getLogger(); + + public MechanicalLemonUI() { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + + MinecraftForge.EVENT_BUS.register(this); + } + + public static ResourceLocation asResource(String path) { + return new ResourceLocation(MODID, path); + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/AbstractSimiScreen.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/AbstractSimiScreen.java new file mode 100644 index 0000000..7c88f17 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/AbstractSimiScreen.java @@ -0,0 +1,182 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.vertex.PoseStack; +import com.oierbravo.mechanical_lemon_ui.foundation.gui.widget.AbstractSimiWidget; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.Components; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.Collection; +import java.util.List; + +@OnlyIn(Dist.CLIENT) +public abstract class AbstractSimiScreen extends Screen { + + protected int windowWidth, windowHeight; + protected int windowXOffset, windowYOffset; + protected int guiLeft, guiTop; + + protected AbstractSimiScreen(Component title) { + super(title); + } + + protected AbstractSimiScreen() { + this(Components.immutableEmpty()); + } + + /** + * This method must be called before {@code super.init()}! + */ + protected void setWindowSize(int width, int height) { + windowWidth = width; + windowHeight = height; + } + + /** + * This method must be called before {@code super.init()}! + */ + protected void setWindowOffset(int xOffset, int yOffset) { + windowXOffset = xOffset; + windowYOffset = yOffset; + } + + @Override + protected void init() { + guiLeft = (width - windowWidth) / 2; + guiTop = (height - windowHeight) / 2; + guiLeft += windowXOffset; + guiTop += windowYOffset; + } + + @Override + public void tick() { + for (GuiEventListener listener : children()) { + if (listener instanceof TickableGuiEventListener tickable) { + tickable.tick(); + } + } + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { + if (getFocused() != null && !getFocused().isMouseOver(pMouseX, pMouseY)) + setFocused(null); + return super.mouseClicked(pMouseX, pMouseY, pButton); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @SuppressWarnings("unchecked") + protected void addRenderableWidgets(W... widgets) { + for (W widget : widgets) { + addRenderableWidget(widget); + } + } + + protected void addRenderableWidgets(Collection widgets) { + for (W widget : widgets) { + addRenderableWidget(widget); + } + } + + protected void removeWidgets(GuiEventListener... widgets) { + for (GuiEventListener widget : widgets) { + removeWidget(widget); + } + } + + protected void removeWidgets(Collection widgets) { + for (GuiEventListener widget : widgets) { + removeWidget(widget); + } + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + partialTicks = minecraft.getFrameTime(); + PoseStack ms = graphics.pose(); + + ms.pushPose(); + + prepareFrame(); + + renderWindowBackground(graphics, mouseX, mouseY, partialTicks); + renderWindow(graphics, mouseX, mouseY, partialTicks); + super.render(graphics, mouseX, mouseY, partialTicks); + renderWindowForeground(graphics, mouseX, mouseY, partialTicks); + + endFrame(); + + ms.popPose(); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + boolean keyPressed = super.keyPressed(keyCode, scanCode, modifiers); + if (keyPressed || getFocused() instanceof EditBox) + return keyPressed; + + InputConstants.Key mouseKey = InputConstants.getKey(keyCode, scanCode); + if (this.minecraft.options.keyInventory.isActiveAndMatches(mouseKey)) { + this.onClose(); + return true; + } + + return false; + } + + protected void prepareFrame() {} + + protected void renderWindowBackground(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + renderBackground(graphics); + } + + protected abstract void renderWindow(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks); + + protected void renderWindowForeground(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + for (Renderable widget : renderables) { + if (widget instanceof AbstractSimiWidget simiWidget && simiWidget.isMouseOver(mouseX, mouseY) + && simiWidget.visible) { + List tooltip = simiWidget.getToolTip(); + if (tooltip.isEmpty()) + continue; + int ttx = simiWidget.lockedTooltipX == -1 ? mouseX : simiWidget.lockedTooltipX + simiWidget.getX(); + int tty = simiWidget.lockedTooltipY == -1 ? mouseY : simiWidget.lockedTooltipY + simiWidget.getY(); + graphics.renderComponentTooltip(font, tooltip, ttx, tty); + } + } + } + + protected void endFrame() {} + + @Deprecated + protected void debugWindowArea(GuiGraphics graphics) { + graphics.fill(guiLeft + windowWidth, guiTop + windowHeight, guiLeft, guiTop, 0xD3D3D3D3); + } + + @Override + public GuiEventListener getFocused() { + GuiEventListener focused = super.getFocused(); + if (focused instanceof AbstractWidget && !((AbstractWidget) focused).isFocused()) + focused = null; + setFocused(focused); + return focused; + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/TickableGuiEventListener.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/TickableGuiEventListener.java new file mode 100644 index 0000000..cb5c63e --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/TickableGuiEventListener.java @@ -0,0 +1,11 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import net.minecraft.client.gui.components.events.GuiEventListener; + +public interface TickableGuiEventListener extends GuiEventListener { + void tick(); +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/UIRenderHelper.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/UIRenderHelper.java new file mode 100644 index 0000000..dabce9e --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/UIRenderHelper.java @@ -0,0 +1,101 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.Color; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import org.joml.Matrix4f; + +public class UIRenderHelper { + public static CustomRenderTarget framebuffer; + + public UIRenderHelper() { + } + + public static void init() { + RenderSystem.recordRenderCall(() -> { + Window mainWindow = Minecraft.getInstance().getWindow(); + framebuffer = UIRenderHelper.CustomRenderTarget.create(mainWindow); + }); + } + + public static void updateWindowSize(Window mainWindow) { + if (framebuffer != null) { + framebuffer.resize(mainWindow.getWidth(), mainWindow.getHeight(), Minecraft.ON_OSX); + } + + } + public static void drawColoredTexture(GuiGraphics graphics, Color c, int x, int y, int tex_left, int tex_top, int width, int height) { + drawColoredTexture(graphics, c, x, y, 0, (float) tex_left, (float) tex_top, width, height, 256, 256); + } + + public static void drawColoredTexture(GuiGraphics graphics, Color c, int x, int y, int z, float tex_left, float tex_top, int width, int height, int sheet_width, int sheet_height) { + drawColoredTexture(graphics, c, x, x + width, y, y + height, z, width, height, tex_left, tex_top, sheet_width, sheet_height); + } + private static void drawColoredTexture(GuiGraphics graphics, Color c, int left, int right, int top, int bot, int z, int tex_width, int tex_height, float tex_left, float tex_top, int sheet_width, int sheet_height) { + drawTexturedQuad(graphics.pose().last().pose(), c, left, right, top, bot, z, (tex_left + 0.0F) / (float)sheet_width, (tex_left + (float)tex_width) / (float)sheet_width, (tex_top + 0.0F) / (float)sheet_height, (tex_top + (float)tex_height) / (float)sheet_height); + } + + private static void drawTexturedQuad(Matrix4f m, Color c, int left, int right, int top, int bot, int z, float u1, float u2, float v1, float v2) { + Tesselator tesselator = Tesselator.getInstance(); + BufferBuilder bufferbuilder = tesselator.getBuilder(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorTexShader); + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + bufferbuilder.vertex(m, (float)left, (float)bot, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u1, v2).endVertex(); + bufferbuilder.vertex(m, (float)right, (float)bot, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u2, v2).endVertex(); + bufferbuilder.vertex(m, (float)right, (float)top, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u2, v1).endVertex(); + bufferbuilder.vertex(m, (float)left, (float)top, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u1, v1).endVertex(); + tesselator.end(); + RenderSystem.disableBlend(); + } + + public static class CustomRenderTarget extends RenderTarget { + public CustomRenderTarget(boolean useDepth) { + super(useDepth); + } + + public static CustomRenderTarget create(Window mainWindow) { + CustomRenderTarget framebuffer = new CustomRenderTarget(true); + framebuffer.resize(mainWindow.getWidth(), mainWindow.getHeight(), Minecraft.ON_OSX); + framebuffer.setClearColor(0.0F, 0.0F, 0.0F, 0.0F); + framebuffer.enableStencil(); + return framebuffer; + } + + public void renderWithAlpha(float alpha) { + Window window = Minecraft.getInstance().getWindow(); + float vx = (float)window.getGuiScaledWidth(); + float vy = (float)window.getGuiScaledHeight(); + float tx = (float)this.viewWidth / (float)this.width; + float ty = (float)this.viewHeight / (float)this.height; + RenderSystem.enableDepthTest(); + RenderSystem.setShader(() -> { + return Minecraft.getInstance().gameRenderer.blitShader; + }); + RenderSystem.getShader().setSampler("DiffuseSampler", this.colorTextureId); + this.bindRead(); + Tesselator tessellator = Tesselator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuilder(); + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + bufferbuilder.vertex(0.0, (double)vy, 0.0).color(1.0F, 1.0F, 1.0F, alpha).uv(0.0F, 0.0F).endVertex(); + bufferbuilder.vertex((double)vx, (double)vy, 0.0).color(1.0F, 1.0F, 1.0F, alpha).uv(tx, 0.0F).endVertex(); + bufferbuilder.vertex((double)vx, 0.0, 0.0).color(1.0F, 1.0F, 1.0F, alpha).uv(tx, ty).endVertex(); + bufferbuilder.vertex(0.0, 0.0, 0.0).color(1.0F, 1.0F, 1.0F, alpha).uv(0.0F, ty).endVertex(); + tessellator.end(); + this.unbindRead(); + } + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/menu/AbstractSimiContainerScreen.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/menu/AbstractSimiContainerScreen.java new file mode 100644 index 0000000..77764f7 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/menu/AbstractSimiContainerScreen.java @@ -0,0 +1,188 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui.menu; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.mojang.blaze3d.platform.InputConstants; +import com.oierbravo.mechanical_lemon_ui.foundation.gui.TickableGuiEventListener; +import com.oierbravo.mechanical_lemon_ui.foundation.gui.widget.AbstractSimiWidget; +import com.oierbravo.mechanical_lemon_ui.register.LibGuiTextures; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.ContainerScreen; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@OnlyIn(Dist.CLIENT) +@ParametersAreNonnullByDefault +public abstract class AbstractSimiContainerScreen extends AbstractContainerScreen { + protected int titleXOffset = 2; + protected int titleYOffset = 6; + protected int windowXOffset, windowYOffset; + + public AbstractSimiContainerScreen(T container, Inventory inv, Component title) { + super(container, inv, title); + } + + /** + * This method must be called before {@code super.init()}! + */ + protected void setWindowSize(int width, int height) { + imageWidth = width; + imageHeight = height; + } + + /** + * This method must be called before {@code super.init()}! + */ + protected void setWindowOffset(int xOffset, int yOffset) { + windowXOffset = xOffset; + windowYOffset = yOffset; + } + + @Override + protected void init() { + super.init(); + leftPos += windowXOffset; + topPos += windowYOffset; + } + + @Override + protected void containerTick() { + for (GuiEventListener listener : children()) { + if (listener instanceof TickableGuiEventListener tickable) { + tickable.tick(); + } + } + } + + @SuppressWarnings("unchecked") + protected void addRenderableWidgets(W... widgets) { + for (W widget : widgets) { + addRenderableWidget(widget); + } + } + + protected void addRenderableWidgets(Collection widgets) { + for (W widget : widgets) { + addRenderableWidget(widget); + } + } + + protected void removeWidgets(GuiEventListener... widgets) { + for (GuiEventListener widget : widgets) { + removeWidget(widget); + } + } + + protected void removeWidgets(Collection widgets) { + for (GuiEventListener widget : widgets) { + removeWidget(widget); + } + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + partialTicks = minecraft.getFrameTime(); + + renderBackground(graphics); + + super.render(graphics, mouseX, mouseY, partialTicks); + + renderForeground(graphics, mouseX, mouseY, partialTicks); + } + + @Override + protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) { + // no-op to prevent screen- and inventory-title from being rendered at incorrect + // location + // could also set this.titleX/Y and this.playerInventoryTitleX/Y to the proper + // values instead + } + + protected void renderForeground(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + renderTooltip(graphics, mouseX, mouseY); + for (Renderable widget : renderables) { + if (widget instanceof AbstractSimiWidget simiWidget && simiWidget.isMouseOver(mouseX, mouseY)) { + List tooltip = simiWidget.getToolTip(); + if (tooltip.isEmpty()) + continue; + int ttx = simiWidget.lockedTooltipX == -1 ? mouseX : simiWidget.lockedTooltipX + simiWidget.getX(); + int tty = simiWidget.lockedTooltipY == -1 ? mouseY : simiWidget.lockedTooltipY + simiWidget.getY(); + graphics.renderComponentTooltip(font, tooltip, ttx, tty); + } + } + } + + public int getLeftOfCentered(int textureWidth) { + return leftPos - windowXOffset + (imageWidth - textureWidth) / 2; + } + + public void renderPlayerInventory(GuiGraphics graphics, int x, int y) { + LibGuiTextures.PLAYER_INVENTORY.render(graphics, x, y); + graphics.drawString(font, playerInventoryTitle, x + titleXOffset, y + titleYOffset, 0x404040, false); + } + + @Override + public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { + InputConstants.Key mouseKey = InputConstants.getKey(pKeyCode, pScanCode); + if (getFocused() instanceof EditBox && this.minecraft.options.keyInventory.isActiveAndMatches(mouseKey)) + return false; + return super.keyPressed(pKeyCode, pScanCode, pModifiers); + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { + if (getFocused() != null && !getFocused().isMouseOver(pMouseX, pMouseY)) + setFocused(null); + return super.mouseClicked(pMouseX, pMouseY, pButton); + } + + @Override + public GuiEventListener getFocused() { + GuiEventListener focused = super.getFocused(); + if (focused instanceof AbstractWidget && !((AbstractWidget) focused).isFocused()) + focused = null; + setFocused(focused); + return focused; + } + + /** + * Used for moving JEI out of the way of extra things like block renders. + * + * @return the space that the GUI takes up outside the normal rectangle defined + * by {@link ContainerScreen}. + */ + public List getExtraAreas() { + return Collections.emptyList(); + } + + @Deprecated + protected void debugWindowArea(GuiGraphics graphics) { + graphics.fill(leftPos + imageWidth, topPos + imageHeight, leftPos, topPos, 0xD3D3D3D3); + } + + @Deprecated + protected void debugExtraAreas(GuiGraphics graphics) { + for (Rect2i area : getExtraAreas()) { + graphics.fill(area.getX() + area.getWidth(), area.getY() + area.getHeight(), area.getX(), area.getY(), + 0xD3D3D3D3); + } + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/menu/MenuBase.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/menu/MenuBase.java new file mode 100644 index 0000000..b9ee3a8 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/menu/MenuBase.java @@ -0,0 +1,74 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui.menu; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.oierbravo.mechanical_lemon_ui.foundation.utility.IInteractionChecker; +import net.minecraft.network.FriendlyByteBuf; +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.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class MenuBase extends AbstractContainerMenu { + + public Player player; + public Inventory playerInventory; + public T contentHolder; + + protected MenuBase(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id); + init(inv, createOnClient(extraData)); + } + + protected MenuBase(MenuType type, int id, Inventory inv, T contentHolder) { + super(type, id); + init(inv, contentHolder); + } + + protected void init(Inventory inv, T contentHolderIn) { + player = inv.player; + playerInventory = inv; + contentHolder = contentHolderIn; + initAndReadInventory(contentHolder); + addSlots(); + broadcastChanges(); + } + + @OnlyIn(Dist.CLIENT) + protected abstract T createOnClient(FriendlyByteBuf extraData); + + protected abstract void initAndReadInventory(T contentHolder); + + protected abstract void addSlots(); + + protected abstract void saveData(T contentHolder); + + protected void addPlayerSlots(int x, int y) { + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) + this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 9; ++col) + this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); + } + + @Override + public void removed(Player playerIn) { + super.removed(playerIn); + saveData(contentHolder); + } + + @Override + public boolean stillValid(Player player) { + if (contentHolder == null) + return false; + if (contentHolder instanceof IInteractionChecker) + return ((IInteractionChecker) contentHolder).canPlayerUse(player); + return true; + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/AbstractSimiWidget.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/AbstractSimiWidget.java new file mode 100644 index 0000000..0736622 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/AbstractSimiWidget.java @@ -0,0 +1,106 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui.widget; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.oierbravo.mechanical_lemon_ui.foundation.gui.TickableGuiEventListener; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.Components; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner; +import net.minecraft.client.gui.screens.inventory.tooltip.DefaultTooltipPositioner; +import net.minecraft.network.chat.Component; + +import javax.annotation.Nonnull; +import java.util.LinkedList; +import java.util.List; +import java.util.function.BiConsumer; + +public abstract class AbstractSimiWidget extends AbstractWidget implements TickableGuiEventListener { + + public static final int HEADER_RGB = 0x5391E1; + public static final int HINT_RGB = 0x96B7E0; + + protected float z; + protected boolean wasHovered = false; + protected List toolTip = new LinkedList<>(); + protected BiConsumer onClick = (_$, _$$) -> {}; + + public int lockedTooltipX = -1; + public int lockedTooltipY = -1; + + protected AbstractSimiWidget(int x, int y) { + this(x, y, 16, 16); + } + + protected AbstractSimiWidget(int x, int y, int width, int height) { + this(x, y, width, height, Components.immutableEmpty()); + } + + protected AbstractSimiWidget(int x, int y, int width, int height, Component message) { + super(x, y, width, height, message); + } + + @Override + protected ClientTooltipPositioner createTooltipPositioner() { + return DefaultTooltipPositioner.INSTANCE; + } + + public T withCallback(BiConsumer cb) { + this.onClick = cb; + //noinspection unchecked + return (T) this; + } + + public T withCallback(Runnable cb) { + return withCallback((_$, _$$) -> cb.run()); + } + + public T atZLevel(float z) { + this.z = z; + //noinspection unchecked + return (T) this; + } + + public List getToolTip() { + return toolTip; + } + + @Override + public void tick() {} + + @Override + public void renderWidget(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + beforeRender(graphics, mouseX, mouseY, partialTicks); + doRender(graphics, mouseX, mouseY, partialTicks); + afterRender(graphics, mouseX, mouseY, partialTicks); + wasHovered = isHoveredOrFocused(); + } + + protected void beforeRender(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + graphics.pose().pushPose(); + } + + protected void doRender(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + } + + protected void afterRender(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + graphics.pose().popPose(); + } + + public void runCallback(double mouseX, double mouseY) { + onClick.accept((int) mouseX, (int) mouseY); + } + + @Override + public void onClick(double mouseX, double mouseY) { + runCallback(mouseX, mouseY); + } + + @Override + public void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) { + defaultButtonNarrationText(pNarrationElementOutput); + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/EnergyDisplay.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/EnergyDisplay.java new file mode 100644 index 0000000..ccdff30 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/EnergyDisplay.java @@ -0,0 +1,56 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui.widget; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.oierbravo.mechanical_lemon_ui.register.LibGuiTextures; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraftforge.energy.IEnergyStorage; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Optional; + +public class EnergyDisplay extends AbstractSimiWidget { + private final IEnergyStorage energy; + private final int xPos; + private final int yPos; + private final int width; + private final int height; + + public EnergyDisplay(int x, int y, IEnergyStorage pEnergy) { + super(x, y); + this.xPos = x; + this.yPos = y; + this.width = 9; + this.height = 30; + this.energy = pEnergy; + } + + @Override + protected void doRender(@NotNull GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float partialTicks) { + if (visible) { + isHovered = pMouseX >= getX() && pMouseY >= getY() && pMouseX < getX() + width && pMouseY < getY() + height; + + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + drawBg(pGuiGraphics, LibGuiTextures.RF_VERTIVAL_BAR); + + int stored = (int)(height * (energy.getEnergyStored() / (float)energy.getMaxEnergyStored())); + pGuiGraphics.fillGradient(xPos,yPos + (height - stored),xPos + width, yPos + height,0xffb51500, 0xff600b00); + if(isHovered()) { + Font font = Minecraft.getInstance().font; + pGuiGraphics.renderTooltip(font, getTooltips(), + Optional.empty(), pMouseX, pMouseY); + } + } + + } + protected void drawBg(GuiGraphics graphics, LibGuiTextures button) { + graphics.blit(button.location, getX(), getY(), button.startX, button.startY, button.width, button.height); + } + + public List getTooltips() { + return List.of(Component.literal(energy.getEnergyStored()+" / "+energy.getMaxEnergyStored()+" FE")); + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/IconButton.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/IconButton.java new file mode 100644 index 0000000..5ea9920 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/IconButton.java @@ -0,0 +1,52 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui.widget; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.mojang.blaze3d.systems.RenderSystem; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.ScreenElement; +import com.oierbravo.mechanical_lemon_ui.register.LibGuiTextures; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; + +public class IconButton extends AbstractSimiWidget { + + protected ScreenElement icon; + + public IconButton(int x, int y, ScreenElement icon) { + this(x, y, 18, 18, icon); + } + + public IconButton(int x, int y, int w, int h, ScreenElement icon) { + super(x, y, w, h); + this.icon = icon; + } + + @Override + public void doRender(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + if (visible) { + isHovered = mouseX >= getX() && mouseY >= getY() && mouseX < getX() + width && mouseY < getY() + height; + + LibGuiTextures button = !active ? LibGuiTextures.BUTTON_DOWN + : isMouseOver(mouseX, mouseY) ? LibGuiTextures.BUTTON_HOVER : LibGuiTextures.BUTTON; + + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + drawBg(graphics, button); + icon.render(graphics, getX() + 1, getY() + 1); + } + } + + protected void drawBg(GuiGraphics graphics, LibGuiTextures button) { + graphics.blit(button.location, getX(), getY(), button.startX, button.startY, button.width, button.height); + } + + public void setToolTip(Component text) { + toolTip.clear(); + toolTip.add(text); + } + + public void setIcon(ScreenElement icon) { + this.icon = icon; + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/ProgressArrow.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/ProgressArrow.java new file mode 100644 index 0000000..1b4eed1 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/gui/widget/ProgressArrow.java @@ -0,0 +1,25 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.gui.widget; + +import com.oierbravo.mechanical_lemon_ui.register.LibGuiTextures; +import net.minecraft.client.gui.GuiGraphics; +import org.jetbrains.annotations.NotNull; + +public class ProgressArrow extends AbstractSimiWidget { + LibGuiTextures TEXTURE = LibGuiTextures.PROGRESS_ARROW_EMPTY; + int currentProgress; + private int progress; + + public ProgressArrow(int x, int y) { + super(x, y); + } + + @Override + protected void doRender(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + graphics.blit(TEXTURE.location, getX(), getY(), TEXTURE.startX, TEXTURE.startY, currentProgress, TEXTURE.height); + } + + public void setProgress(int progress, int maxProgress) { + int progressArrowSize = TEXTURE.width; + this.currentProgress = maxProgress != 0 && progress != 0 ? progress * progressArrowSize / maxProgress : 0; + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Color.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Color.java new file mode 100644 index 0000000..f7b9a6f --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Color.java @@ -0,0 +1,243 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ + +import com.google.common.hash.Hashing; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.joml.Vector3f; + +import javax.annotation.Nonnull; +import java.util.function.UnaryOperator; + +public class Color { + public static final Color TRANSPARENT_BLACK = (new Color(0, 0, 0, 0)).setImmutable(); + public static final Color BLACK = (new Color(0, 0, 0)).setImmutable(); + public static final Color WHITE = (new Color(255, 255, 255)).setImmutable(); + public static final Color RED = (new Color(255, 0, 0)).setImmutable(); + public static final Color GREEN = (new Color(0, 255, 0)).setImmutable(); + public static final Color SPRING_GREEN = (new Color(0, 255, 187)).setImmutable(); + protected boolean mutable; + protected int value; + + public Color(int r, int g, int b) { + this(r, g, b, 255); + } + + public Color(int r, int g, int b, int a) { + this.mutable = true; + this.value = (a & 255) << 24 | (r & 255) << 16 | (g & 255) << 8 | (b & 255) << 0; + } + + public Color(float r, float g, float b, float a) { + this((int)(0.5 + (double)(255.0F * Mth.clamp(r, 0.0F, 1.0F))), (int)(0.5 + (double)(255.0F * Mth.clamp(g, 0.0F, 1.0F))), (int)(0.5 + (double)(255.0F * Mth.clamp(b, 0.0F, 1.0F))), (int)(0.5 + (double)(255.0F * Mth.clamp(a, 0.0F, 1.0F)))); + } + + public Color(int rgba) { + this.mutable = true; + this.value = rgba; + } + + public Color(int rgb, boolean hasAlpha) { + this.mutable = true; + if (hasAlpha) { + this.value = rgb; + } else { + this.value = rgb | -16777216; + } + + } + + public Color copy() { + return this.copy(true); + } + + public Color copy(boolean mutable) { + return mutable ? new Color(this.value) : (new Color(this.value)).setImmutable(); + } + + public Color setImmutable() { + this.mutable = false; + return this; + } + + public int getRed() { + return this.getRGB() >> 16 & 255; + } + + public int getGreen() { + return this.getRGB() >> 8 & 255; + } + + public int getBlue() { + return this.getRGB() >> 0 & 255; + } + + public int getAlpha() { + return this.getRGB() >> 24 & 255; + } + + public float getRedAsFloat() { + return (float)this.getRed() / 255.0F; + } + + public float getGreenAsFloat() { + return (float)this.getGreen() / 255.0F; + } + + public float getBlueAsFloat() { + return (float)this.getBlue() / 255.0F; + } + + public float getAlphaAsFloat() { + return (float)this.getAlpha() / 255.0F; + } + + public int getRGB() { + return this.value; + } + + public Vec3 asVector() { + return new Vec3((double)this.getRedAsFloat(), (double)this.getGreenAsFloat(), (double)this.getBlueAsFloat()); + } + + public Vector3f asVectorF() { + return new Vector3f(this.getRedAsFloat(), this.getGreenAsFloat(), this.getBlueAsFloat()); + } + + public Color setRed(int r) { + return this.ensureMutable().setRedUnchecked(r); + } + + public Color setGreen(int g) { + return this.ensureMutable().setGreenUnchecked(g); + } + + public Color setBlue(int b) { + return this.ensureMutable().setBlueUnchecked(b); + } + + public Color setAlpha(int a) { + return this.ensureMutable().setAlphaUnchecked(a); + } + + public Color setRed(float r) { + return this.ensureMutable().setRedUnchecked((int)(255.0F * Mth.clamp(r, 0.0F, 1.0F))); + } + + public Color setGreen(float g) { + return this.ensureMutable().setGreenUnchecked((int)(255.0F * Mth.clamp(g, 0.0F, 1.0F))); + } + + public Color setBlue(float b) { + return this.ensureMutable().setBlueUnchecked((int)(255.0F * Mth.clamp(b, 0.0F, 1.0F))); + } + + public Color setAlpha(float a) { + return this.ensureMutable().setAlphaUnchecked((int)(255.0F * Mth.clamp(a, 0.0F, 1.0F))); + } + + public Color scaleAlpha(float factor) { + return this.ensureMutable().setAlphaUnchecked((int)((float)this.getAlpha() * Mth.clamp(factor, 0.0F, 1.0F))); + } + + public Color mixWith(Color other, float weight) { + return this.ensureMutable().setRedUnchecked((int)((float)this.getRed() + (float)(other.getRed() - this.getRed()) * weight)).setGreenUnchecked((int)((float)this.getGreen() + (float)(other.getGreen() - this.getGreen()) * weight)).setBlueUnchecked((int)((float)this.getBlue() + (float)(other.getBlue() - this.getBlue()) * weight)).setAlphaUnchecked((int)((float)this.getAlpha() + (float)(other.getAlpha() - this.getAlpha()) * weight)); + } + + public Color darker() { + int a = this.getAlpha(); + return this.ensureMutable().mixWith(BLACK, 0.25F).setAlphaUnchecked(a); + } + + public Color brighter() { + int a = this.getAlpha(); + return this.ensureMutable().mixWith(WHITE, 0.25F).setAlphaUnchecked(a); + } + + public Color setValue(int value) { + return this.ensureMutable().setValueUnchecked(value); + } + + public Color modifyValue(UnaryOperator function) { + int newValue = (Integer)function.apply(this.value); + return newValue == this.value ? this : this.ensureMutable().setValueUnchecked(newValue); + } + + protected Color ensureMutable() { + return this.mutable ? this : new Color(this.value); + } + + protected Color setRedUnchecked(int r) { + this.value = this.value & -16711681 | (r & 255) << 16; + return this; + } + + protected Color setGreenUnchecked(int g) { + this.value = this.value & -65281 | (g & 255) << 8; + return this; + } + + protected Color setBlueUnchecked(int b) { + this.value = this.value & -256 | (b & 255) << 0; + return this; + } + + protected Color setAlphaUnchecked(int a) { + this.value = this.value & 16777215 | (a & 255) << 24; + return this; + } + + protected Color setValueUnchecked(int value) { + this.value = value; + return this; + } + + public static Color mixColors(@Nonnull Color c1, @Nonnull Color c2, float w) { + return new Color((int)((float)c1.getRed() + (float)(c2.getRed() - c1.getRed()) * w), (int)((float)c1.getGreen() + (float)(c2.getGreen() - c1.getGreen()) * w), (int)((float)c1.getBlue() + (float)(c2.getBlue() - c1.getBlue()) * w), (int)((float)c1.getAlpha() + (float)(c2.getAlpha() - c1.getAlpha()) * w)); + } + + public static Color mixColors(@Nonnull Couple colors, float w) { + return mixColors((Color)colors.getFirst(), (Color)colors.getSecond(), w); + } + + public static int mixColors(int color1, int color2, float w) { + int a1 = color1 >> 24; + int r1 = color1 >> 16 & 255; + int g1 = color1 >> 8 & 255; + int b1 = color1 & 255; + int a2 = color2 >> 24; + int r2 = color2 >> 16 & 255; + int g2 = color2 >> 8 & 255; + int b2 = color2 & 255; + return ((int)((float)a1 + (float)(a2 - a1) * w) << 24) + ((int)((float)r1 + (float)(r2 - r1) * w) << 16) + ((int)((float)g1 + (float)(g2 - g1) * w) << 8) + ((int)((float)b1 + (float)(b2 - b1) * w) << 0); + } + + public static Color rainbowColor(int timeStep) { + int localTimeStep = Math.abs(timeStep) % 1536; + int timeStepInPhase = localTimeStep % 256; + int phaseBlue = localTimeStep / 256; + int red = colorInPhase(phaseBlue + 4, timeStepInPhase); + int green = colorInPhase(phaseBlue + 2, timeStepInPhase); + int blue = colorInPhase(phaseBlue, timeStepInPhase); + return new Color(red, green, blue); + } + + private static int colorInPhase(int phase, int progress) { + phase %= 6; + if (phase <= 1) { + return 0; + } else if (phase == 2) { + return progress; + } else { + return phase <= 4 ? 255 : 255 - progress; + } + } + + public static Color generateFromLong(long l) { + return rainbowColor(Hashing.crc32().hashLong(l).asInt()).mixWith(WHITE, 0.5F); + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Components.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Components.java new file mode 100644 index 0000000..6489365 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Components.java @@ -0,0 +1,37 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; + +public final class Components { + private static final Component IMMUTABLE_EMPTY = Component.empty(); + + public static Component immutableEmpty() { + return IMMUTABLE_EMPTY; + } + + /** Use {@link #immutableEmpty()} when possible to prevent creating an extra object. */ + public static MutableComponent empty() { + return Component.empty(); + } + + public static MutableComponent literal(String str) { + return Component.literal(str); + } + + public static MutableComponent translatable(String key) { + return Component.translatable(key); + } + + public static MutableComponent translatable(String key, Object... args) { + return Component.translatable(key, args); + } + + public static MutableComponent keybind(String name) { + return Component.keybind(name); + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Couple.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Couple.java new file mode 100644 index 0000000..dfb0e96 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Couple.java @@ -0,0 +1,155 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import com.google.common.collect.ImmutableList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; + +import java.util.Iterator; +import java.util.List; +import java.util.function.*; +import java.util.stream.Stream; + +public class Couple extends Pair implements Iterable { + + private static final Couple TRUE_AND_FALSE = Couple.create(true, false); + + protected Couple(T first, T second) { + super(first, second); + } + + public static Couple create(T first, T second) { + return new Couple<>(first, second); + } + + public static Couple create(Supplier factory) { + return new Couple<>(factory.get(), factory.get()); + } + + public static Couple createWithContext(Function factory) { + return new Couple<>(factory.apply(true), factory.apply(false)); + } + + public T get(boolean first) { + return first ? getFirst() : getSecond(); + } + + public void set(boolean first, T value) { + if (first) + setFirst(value); + else + setSecond(value); + } + + @Override + public Couple copy() { + return create(first, second); + } + + public Couple map(Function function) { + return Couple.create(function.apply(first), function.apply(second)); + } + + public Couple mapWithContext(BiFunction function) { + return Couple.create(function.apply(first, true), function.apply(second, false)); + } + + public Couple mapWithParams(BiFunction function, Couple values) { + return Couple.create(function.apply(first, values.first), function.apply(second, values.second)); + } + + public Couple mapNotNullWithParam(BiFunction function, R value) { + return Couple.create(first != null ? function.apply(first, value) : null, + second != null ? function.apply(second, value) : null); + } + + public boolean both(Predicate test) { + return test.test(getFirst()) && test.test(getSecond()); + } + + public boolean either(Predicate test) { + return test.test(getFirst()) || test.test(getSecond()); + } + + public void replace(Function function) { + setFirst(function.apply(getFirst())); + setSecond(function.apply(getSecond())); + } + + public void replaceWithContext(BiFunction function) { + replaceWithParams(function, TRUE_AND_FALSE); + } + + public void replaceWithParams(BiFunction function, Couple values) { + setFirst(function.apply(getFirst(), values.getFirst())); + setSecond(function.apply(getSecond(), values.getSecond())); + } + + @Override + public void forEach(Consumer consumer) { + consumer.accept(getFirst()); + consumer.accept(getSecond()); + } + + public void forEachWithContext(BiConsumer consumer) { + forEachWithParams(consumer, TRUE_AND_FALSE); + } + + public void forEachWithParams(BiConsumer function, Couple values) { + function.accept(getFirst(), values.getFirst()); + function.accept(getSecond(), values.getSecond()); + } + + public Couple swap() { + return Couple.create(second, first); + } + + public ListTag serializeEach(Function serializer) { + return NBTHelper.writeCompoundList(ImmutableList.of(first, second), serializer); + } + + public static Couple deserializeEach(ListTag list, Function deserializer) { + List readCompoundList = NBTHelper.readCompoundList(list, deserializer); + return new Couple<>(readCompoundList.get(0), readCompoundList.get(1)); + } + + @Override + public Iterator iterator() { + return new Couplerator<>(this); + } + + public Stream stream() { + return Stream.of(first, second); + } + + private static class Couplerator implements Iterator { + + int state; + private final Couple couple; + + public Couplerator(Couple couple) { + this.couple = couple; + state = 0; + } + + @Override + public boolean hasNext() { + return state != 2; + } + + @Override + public T next() { + state++; + if (state == 1) + return couple.first; + if (state == 2) + return couple.second; + return null; + } + + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/FakeItemRenderer.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/FakeItemRenderer.java new file mode 100644 index 0000000..41d8c89 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/FakeItemRenderer.java @@ -0,0 +1,35 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * smashingmods + * + * This code is licensed under "GNU Lesser General Public License" + * https://github.com/SmashingMods/AlchemyLib/ + * + * Slightly Modified Version by: oierbravo + */ +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.item.ItemStack; + +public class FakeItemRenderer { + + public static void renderFakeItem(GuiGraphics pGuiGraphics, ItemStack pItemStack, int pX, int pY) { + renderFakeItem(pGuiGraphics, pItemStack, pX, pY, true, false); + } + + public static void renderFakeItem(GuiGraphics pGuiGraphics, ItemStack pItemStack, int pX, int pY, boolean pDrawItemDecorations) { + renderFakeItem(pGuiGraphics, pItemStack, pX, pY, true, pDrawItemDecorations); + } + + public static void renderFakeItem(GuiGraphics pGuiGraphics, ItemStack pItemStack, int pX, int pY, boolean pSemiTransparent, boolean pDrawItemDecorations) { + pGuiGraphics.renderFakeItem(pItemStack, pX, pY); + if (pSemiTransparent) { + pGuiGraphics.fill(RenderType.guiGhostRecipeOverlay(), pX, pY, pX + 16, pY + 16, 0x88888888); + } + + if (pDrawItemDecorations) { + pGuiGraphics.renderItemDecorations(Minecraft.getInstance().font, pItemStack, pX, pY); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/IGuiTextures.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/IGuiTextures.java new file mode 100644 index 0000000..29469cb --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/IGuiTextures.java @@ -0,0 +1,39 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.oierbravo.mechanical_lemon_ui.foundation.gui.UIRenderHelper; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.resources.ResourceLocation; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class IGuiTextures { + + ResourceLocation location = null; + int width = 0; + int height = 0; + int startX = 0; + int startY = 0; + + + @OnlyIn(Dist.CLIENT) + public void bind() { + RenderSystem.setShaderTexture(0, location); + } + + @OnlyIn(Dist.CLIENT) + public void render(GuiGraphics graphics, int x, int y) { + graphics.blit(location, x, y, startX, startY, width, height); + } + + @OnlyIn(Dist.CLIENT) + public void render(GuiGraphics graphics, int x, int y, Color c) { + bind(); + UIRenderHelper.drawColoredTexture(graphics, c, x, y, startX, startY, width, height); + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/IInteractionChecker.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/IInteractionChecker.java new file mode 100644 index 0000000..15873cd --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/IInteractionChecker.java @@ -0,0 +1,11 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import net.minecraft.world.entity.player.Player; + +public interface IInteractionChecker { + boolean canPlayerUse(Player player); +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Lang.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Lang.java new file mode 100644 index 0000000..a6d4690 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Lang.java @@ -0,0 +1,85 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fluids.FluidStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class Lang { + public Lang() { + } + + public static MutableComponent translateDirect(String key, Object... args) { + return Components.translatable("create." + key, resolveBuilders(args)); + } + + public static String asId(String name) { + return name.toLowerCase(Locale.ROOT); + } + + public static String nonPluralId(String name) { + String asId = asId(name); + return asId.endsWith("s") ? asId.substring(0, asId.length() - 1) : asId; + } + + public static List translatedOptions(String prefix, String... keys) { + List result = new ArrayList(keys.length); + String[] var3 = keys; + int var4 = keys.length; + + for(int var5 = 0; var5 < var4; ++var5) { + String key = var3[var5]; + result.add(translate((prefix != null ? prefix + "." : "") + key).component()); + } + + return result; + } + + public static LangBuilder builder() { + return new LangBuilder("create"); + } + + public static LangBuilder builder(String namespace) { + return new LangBuilder(namespace); + } + + public static LangBuilder blockName(BlockState state) { + return builder().add(state.getBlock().getName()); + } + + public static LangBuilder itemName(ItemStack stack) { + return builder().add(stack.getHoverName().copy()); + } + + public static LangBuilder fluidName(FluidStack stack) { + return builder().add(stack.getDisplayName().copy()); + } + + public static LangBuilder number(double d) { + return builder().text(LangNumberFormat.format(d)); + } + + public static LangBuilder translate(String langKey, Object... args) { + return builder().translate(langKey, args); + } + + public static LangBuilder text(String text) { + return builder().text(text); + } + + public static Object[] resolveBuilders(Object[] args) { + for(int i = 0; i < args.length; ++i) { + Object var3 = args[i]; + if (var3 instanceof LangBuilder cb) { + args[i] = cb.component(); + } + } + + return args; + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/LangBuilder.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/LangBuilder.java new file mode 100644 index 0000000..bf722b5 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/LangBuilder.java @@ -0,0 +1,190 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; + +import joptsimple.internal.Strings; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; + +import java.util.List; + +public class LangBuilder { + + String namespace; + MutableComponent component; + + public LangBuilder(String namespace) { + this.namespace = namespace; + } + + public LangBuilder space() { + return text(" "); + } + + public LangBuilder newLine() { + return text("\n"); + } + + /** + * Appends a localised component
+ * To add an independently formatted localised component, use add() and a nested + * builder + * + * @param langKey + * @param args + * @return + */ + public LangBuilder translate(String langKey, Object... args) { + return add(Components.translatable(namespace + "." + langKey, Lang.resolveBuilders(args))); + } + + /** + * Appends a text component + * + * @param literalText + * @return + */ + public LangBuilder text(String literalText) { + return add(Components.literal(literalText)); + } + + /** + * Appends a colored text component + * + * @param format + * @param literalText + * @return + */ + public LangBuilder text(ChatFormatting format, String literalText) { + return add(Components.literal(literalText).withStyle(format)); + } + + /** + * Appends a colored text component + * + * @param color + * @param literalText + * @return + */ + public LangBuilder text(int color, String literalText) { + return add(Components.literal(literalText).withStyle(s -> s.withColor(color))); + } + + /** + * Appends the contents of another builder + * + * @param otherBuilder + * @return + */ + public LangBuilder add(LangBuilder otherBuilder) { + return add(otherBuilder.component()); + } + + /** + * Appends a component + * + * @param customComponent + * @return + */ + public LangBuilder add(MutableComponent customComponent) { + component = component == null ? customComponent : component.append(customComponent); + return this; + } + + /** + * Appends a component + * + * @param component the component to append + * @return this builder + */ + public LangBuilder add(Component component) { + if (component instanceof MutableComponent mutableComponent) + return add(mutableComponent); + else + return add(component.copy()); + } + + // + + /** + * Applies the format to all added components + * + * @param format + * @return + */ + public LangBuilder style(ChatFormatting format) { + assertComponent(); + component = component.withStyle(format); + return this; + } + + /** + * Applies the color to all added components + * + * @param color + * @return + */ + public LangBuilder color(int color) { + assertComponent(); + component = component.withStyle(s -> s.withColor(color)); + return this; + } + + // + + public MutableComponent component() { + assertComponent(); + return component; + } + + public String string() { + return component().getString(); + } + + public String json() { + return Component.Serializer.toJson(component()); + } + + public void sendStatus(Player player) { + player.displayClientMessage(component(), true); + } + + public void sendChat(Player player) { + player.displayClientMessage(component(), false); + } + + public void addTo(List tooltip) { + tooltip.add(component()); + } + + public void forGoggles(List tooltip) { + forGoggles(tooltip, 0); + } + + public void forGoggles(List tooltip, int indents) { + tooltip.add(Lang.builder() + .text(Strings.repeat(' ', getIndents(Minecraft.getInstance().font, 4 + indents))) + .add(this) + .component()); + } + + public static final float DEFAULT_SPACE_WIDTH = 4.0F; // space width in vanilla's default font + static int getIndents(Font font, int defaultIndents) { + int spaceWidth = font.width(" "); + if (DEFAULT_SPACE_WIDTH == spaceWidth) { + return defaultIndents; + } + return Mth.ceil(DEFAULT_SPACE_WIDTH * defaultIndents / spaceWidth); + } + + // + + private void assertComponent() { + if (component == null) + throw new IllegalStateException("No components were added to builder"); + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/LangNumberFormat.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/LangNumberFormat.java new file mode 100644 index 0000000..c9fe30a --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/LangNumberFormat.java @@ -0,0 +1,35 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; + +import java.text.NumberFormat; +import java.util.Locale; + +public class LangNumberFormat { + + private NumberFormat format = NumberFormat.getNumberInstance(Locale.ROOT); + public static LangNumberFormat numberFormat = new LangNumberFormat(); + + public NumberFormat get() { + return format; + } + + public void update() { + format = NumberFormat.getInstance(Minecraft.getInstance() + .getLanguageManager() + .getJavaLocale()); + format.setMaximumFractionDigits(2); + format.setMinimumFractionDigits(0); + format.setGroupingUsed(true); + } + + public static String format(double d) { + if (Mth.equal(d, 0)) + d = 0; + return numberFormat.get() + .format(d) + .replace("\u00A0", " "); + } + +} \ No newline at end of file diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/NBTHelper.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/NBTHelper.java new file mode 100644 index 0000000..60fccb7 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/NBTHelper.java @@ -0,0 +1,129 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class NBTHelper { + + public static void putMarker(CompoundTag nbt, String marker) { + nbt.putBoolean(marker, true); + } + + public static > T readEnum(CompoundTag nbt, String key, Class enumClass) { + T[] enumConstants = enumClass.getEnumConstants(); + if (enumConstants == null) + throw new IllegalArgumentException("Non-Enum class passed to readEnum: " + enumClass.getName()); + if (nbt.contains(key, Tag.TAG_STRING)) { + String name = nbt.getString(key); + for (T t : enumConstants) { + if (t.name() + .equals(name)) + return t; + } + } + return enumConstants[0]; + } + + public static > void writeEnum(CompoundTag nbt, String key, T enumConstant) { + nbt.putString(key, enumConstant.name()); + } + + public static ListTag writeCompoundList(Iterable list, Function serializer) { + ListTag listNBT = new ListTag(); + list.forEach(t -> { + CompoundTag apply = serializer.apply(t); + if (apply == null) + return; + listNBT.add(apply); + }); + return listNBT; + } + + public static List readCompoundList(ListTag listNBT, Function deserializer) { + List list = new ArrayList<>(listNBT.size()); + listNBT.forEach(inbt -> list.add(deserializer.apply((CompoundTag) inbt))); + return list; + } + + public static void iterateCompoundList(ListTag listNBT, Consumer consumer) { + listNBT.forEach(inbt -> consumer.accept((CompoundTag) inbt)); + } + + public static ListTag writeItemList(Iterable stacks) { + return writeCompoundList(stacks, ItemStack::serializeNBT); + } + + public static List readItemList(ListTag stacks) { + return readCompoundList(stacks, ItemStack::of); + } + + public static ListTag writeAABB(AABB bb) { + ListTag bbtag = new ListTag(); + bbtag.add(FloatTag.valueOf((float) bb.minX)); + bbtag.add(FloatTag.valueOf((float) bb.minY)); + bbtag.add(FloatTag.valueOf((float) bb.minZ)); + bbtag.add(FloatTag.valueOf((float) bb.maxX)); + bbtag.add(FloatTag.valueOf((float) bb.maxY)); + bbtag.add(FloatTag.valueOf((float) bb.maxZ)); + return bbtag; + } + + public static AABB readAABB(ListTag bbtag) { + if (bbtag == null || bbtag.isEmpty()) + return null; + return new AABB(bbtag.getFloat(0), bbtag.getFloat(1), bbtag.getFloat(2), bbtag.getFloat(3), + bbtag.getFloat(4), bbtag.getFloat(5)); + } + + public static ListTag writeVec3i(Vec3i vec) { + ListTag tag = new ListTag(); + tag.add(IntTag.valueOf(vec.getX())); + tag.add(IntTag.valueOf(vec.getY())); + tag.add(IntTag.valueOf(vec.getZ())); + return tag; + } + + public static Vec3i readVec3i(ListTag tag) { + return new Vec3i(tag.getInt(0), tag.getInt(1), tag.getInt(2)); + } + + @Nonnull + public static Tag getINBT(CompoundTag nbt, String id) { + Tag inbt = nbt.get(id); + if (inbt != null) + return inbt; + return new CompoundTag(); + } + + public static CompoundTag intToCompound(int i) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putInt("V", i); + return compoundTag; + } + + public static int intFromCompound(CompoundTag compoundTag) { + return compoundTag.getInt("V"); + } + + public static void writeResourceLocation(CompoundTag nbt, String key, ResourceLocation location) { + nbt.putString(key, location.toString()); + } + + public static ResourceLocation readResourceLocation(CompoundTag nbt, String key) { + return new ResourceLocation(nbt.getString(key)); + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Pair.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Pair.java new file mode 100644 index 0000000..d62ca97 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/Pair.java @@ -0,0 +1,72 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import java.util.Objects; + +public class Pair { + + F first; + S second; + + protected Pair(F first, S second) { + this.first = first; + this.second = second; + } + + public static Pair of(F first, S second) { + return new Pair<>(first, second); + } + + public F getFirst() { + return first; + } + + public S getSecond() { + return second; + } + + public void setFirst(F first) { + this.first = first; + } + + public void setSecond(S second) { + this.second = second; + } + + public Pair copy() { + return Pair.of(first, second); + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) + return true; + if (obj instanceof Pair) { + final Pair other = (Pair) obj; + return Objects.equals(first, other.first) && Objects.equals(second, other.second); + } + return false; + } + + @Override + public int hashCode() { + return (nullHash(first) * 31) ^ nullHash(second); + } + + int nullHash(Object o) { + return o == null ? 0 : o.hashCode(); + } + + @Override + public String toString() { + return "(" + first + ", " + second + ")"; + } + + public Pair swap() { + return Pair.of(second, first); + } + +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/ScreenElement.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/ScreenElement.java new file mode 100644 index 0000000..54a8bd8 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/foundation/utility/ScreenElement.java @@ -0,0 +1,14 @@ +package com.oierbravo.mechanical_lemon_ui.foundation.utility; +/* + * Credits: Creators of create + * https://github.com/Creators-of-Create/Create + * License: MIT + */ +import net.minecraft.client.gui.GuiGraphics; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public interface ScreenElement { + @OnlyIn(Dist.CLIENT) + void render(GuiGraphics var1, int var2, int var3); +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/register/LibGuiTextures.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/register/LibGuiTextures.java new file mode 100644 index 0000000..9fbe428 --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/register/LibGuiTextures.java @@ -0,0 +1,67 @@ +package com.oierbravo.mechanical_lemon_ui.register; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.oierbravo.mechanical_lemon_ui.MechanicalLemonUI; +import com.oierbravo.mechanical_lemon_ui.foundation.gui.UIRenderHelper; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.Color; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.ScreenElement; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public enum LibGuiTextures implements ScreenElement { + PLAYER_INVENTORY("player_inventory", 176, 108), + + + BUTTON("widgets", 18, 18), + BUTTON_HOVER("widgets", 18, 0, 18, 18), + BUTTON_DOWN("widgets", 36, 0, 18, 18), + SLOT_EMPTY("widgets", 36, 0, 18, 18), + RF_VERTIVAL_BAR("widgets",0,18,10,30), + PROGRESS_ARROW_EMPTY("widgets",0,48,32,8), + PROGRESS_ARROW_FULL("widgets",0,56,32,8) + ; + + public static final int FONT_COLOR = 0x575F7A; + + public final ResourceLocation location; + public int width, height; + public int startX, startY; + + private LibGuiTextures(String location, int width, int height) { + this(location, 0, 0, width, height); + } + + private LibGuiTextures(int startX, int startY) { + this("icons", startX * 16, startY * 16, 16, 16); + } + + private LibGuiTextures(String location, int startX, int startY, int width, int height) { + this(MechanicalLemonUI.MODID, location, startX, startY, width, height); + } + + private LibGuiTextures(String namespace, String location, int startX, int startY, int width, int height) { + this.location = new ResourceLocation(namespace, "textures/gui/" + location + ".png"); + this.width = width; + this.height = height; + this.startX = startX; + this.startY = startY; + } + + @OnlyIn(Dist.CLIENT) + public void bind() { + RenderSystem.setShaderTexture(0, location); + } + + @OnlyIn(Dist.CLIENT) + public void render(GuiGraphics graphics, int x, int y) { + graphics.blit(location, x, y, startX, startY, width, height); + } + + @OnlyIn(Dist.CLIENT) + public void render(GuiGraphics graphics, int x, int y, Color c) { + bind(); + UIRenderHelper.drawColoredTexture(graphics, c, x, y, startX, startY, width, height); + } +} diff --git a/src/main/java/com/oierbravo/mechanical_lemon_ui/register/LibIcons.java b/src/main/java/com/oierbravo/mechanical_lemon_ui/register/LibIcons.java new file mode 100644 index 0000000..6e0bb2c --- /dev/null +++ b/src/main/java/com/oierbravo/mechanical_lemon_ui/register/LibIcons.java @@ -0,0 +1,81 @@ +package com.oierbravo.mechanical_lemon_ui.register; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.oierbravo.mechanical_lemon_ui.MechanicalLemonUI; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.Color; +import com.oierbravo.mechanical_lemon_ui.foundation.utility.ScreenElement; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.joml.Matrix4f; + +public class LibIcons implements ScreenElement { + public static final ResourceLocation ICON_ATLAS = MechanicalLemonUI.asResource("textures/gui/icons.png"); + public static final int ICON_ATLAS_SIZE = 256; + private static int x = 0; + private static int y = -1; + private int iconX; + private int iconY; + public static final LibIcons ARROW_LEFT = newRow(); + public static final LibIcons TRASH = next(); + public static final LibIcons REDSTONE_HIGH = next(); + public static final LibIcons REDSTONE_LOW = next(); + public static final LibIcons REDSTONE_IGNORE = next(); + public static final LibIcons SEARCH = next(); + public static final LibIcons CHECK = next(); + + public LibIcons(int x, int y) { + this.iconX = x * 16; + this.iconY = y * 16; + } + + private static LibIcons next() { + return new LibIcons(++x, y); + } + + private static LibIcons newRow() { + x = 0; + return new LibIcons(0, ++y); + } + + @OnlyIn(Dist.CLIENT) + public void bind() { + RenderSystem.setShaderTexture(0, ICON_ATLAS); + } + + @OnlyIn(Dist.CLIENT) + public void render(GuiGraphics graphics, int x, int y) { + graphics.blit(ICON_ATLAS, x, y, 0, (float)this.iconX, (float)this.iconY, 16, 16, 256, 256); + } + + @OnlyIn(Dist.CLIENT) + public void render(PoseStack ms, MultiBufferSource buffer, int color) { + VertexConsumer builder = buffer.getBuffer(RenderType.text(ICON_ATLAS)); + Matrix4f matrix = ms.last().pose(); + Color rgb = new Color(color); + int light = 15728880; + Vec3 vec1 = new Vec3(0.0, 0.0, 0.0); + Vec3 vec2 = new Vec3(0.0, 1.0, 0.0); + Vec3 vec3 = new Vec3(1.0, 1.0, 0.0); + Vec3 vec4 = new Vec3(1.0, 0.0, 0.0); + float u1 = (float)this.iconX * 1.0F / 256.0F; + float u2 = (float)(this.iconX + 16) * 1.0F / 256.0F; + float v1 = (float)this.iconY * 1.0F / 256.0F; + float v2 = (float)(this.iconY + 16) * 1.0F / 256.0F; + this.vertex(builder, matrix, vec1, rgb, u1, v1, light); + this.vertex(builder, matrix, vec2, rgb, u1, v2, light); + this.vertex(builder, matrix, vec3, rgb, u2, v2, light); + this.vertex(builder, matrix, vec4, rgb, u2, v1, light); + } + + @OnlyIn(Dist.CLIENT) + private void vertex(VertexConsumer builder, Matrix4f matrix, Vec3 vec, Color rgb, float u, float v, int light) { + builder.vertex(matrix, (float)vec.x, (float)vec.y, (float)vec.z).color(rgb.getRed(), rgb.getGreen(), rgb.getBlue(), 255).uv(u, v).uv2(light).endVertex(); + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..3b79691 --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,24 @@ +modLoader = "javafml" #mandatory +loaderVersion = "${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +license = "${mod_license}" + +[[mods]] #mandatory +modId = "${modid}" #mandatory +version = "${mod_version}" #mandatory +displayName = "${mod_name}" #mandatory +authors = "${author}" #optional +description = '''${mod_description}''' + +[[dependencies."${modid}"]] #optional +modId = "forge" #mandatory +mandatory = true #mandatory +versionRange = "${forge_version_range}" #mandatory +ordering = "NONE" +side = "BOTH"# Here's another dependency + +[[dependencies."${modid}"]] +modId = "minecraft" +mandatory = true +versionRange = "${minecraft_version_range}" +ordering = "NONE" +side = "BOTH" diff --git a/src/main/resources/assets/mechanical_lemon_ui/lang/en_us.json b/src/main/resources/assets/mechanical_lemon_ui/lang/en_us.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/src/main/resources/assets/mechanical_lemon_ui/lang/en_us.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/src/main/resources/assets/mechanical_lemon_ui/textures/gui/icons.png b/src/main/resources/assets/mechanical_lemon_ui/textures/gui/icons.png new file mode 100644 index 0000000..91af026 Binary files /dev/null and b/src/main/resources/assets/mechanical_lemon_ui/textures/gui/icons.png differ diff --git a/src/main/resources/assets/mechanical_lemon_ui/textures/gui/player_inventory.png b/src/main/resources/assets/mechanical_lemon_ui/textures/gui/player_inventory.png new file mode 100644 index 0000000..80a4ff8 Binary files /dev/null and b/src/main/resources/assets/mechanical_lemon_ui/textures/gui/player_inventory.png differ diff --git a/src/main/resources/assets/mechanical_lemon_ui/textures/gui/widgets.png b/src/main/resources/assets/mechanical_lemon_ui/textures/gui/widgets.png new file mode 100644 index 0000000..2e2efce Binary files /dev/null and b/src/main/resources/assets/mechanical_lemon_ui/textures/gui/widgets.png differ diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..5a1df0c --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "mechanical_lemon_ui resources", + "pack_format": 15 + } +}