diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf5ec74 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# exclude all +/* + +# include important folders +# need gradle +!gradle/ +!bintray/ +!gradlew +!gradlew.bat +!build.gradle +!build.properties +!gradle.properties +!settings.gradle +!.github/ + +# include markdowns +!README.md +!LICENSE +!COPYING.txt + +# include sourcecode +!src/ +src/generated/resources/.cache + +# include git important files +!.gitmodules +!.gitignore + +# code format to reduce noise in git commits +!codeformat/ + +# include web files +!web/ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..397eb44 --- /dev/null +++ b/build.gradle @@ -0,0 +1,385 @@ +plugins { + id 'java-library' + id 'idea' + id 'maven-publish' + id 'net.neoforged.moddev' version '1.0.14' + id "org.sonarqube" version "5.0.0.4638" + id "net.darkhax.curseforgegradle" version "1.1.15" + id "com.modrinth.minotaur" version "2.+" +} + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +version = "${project.minecraft_version}-${project.mod_version}.${getBuildNumber()}${getStable()}" +group = mod_group_id + +repositories { + mavenCentral() + maven { url "https://maven.tterrag.com/" } + maven { url = "https://modmaven.dev/" } + maven { url "https://minecraft.curseforge.com/api/maven/"} + maven { + url "https://www.cursemaven.com" + content { + includeGroup "curse.maven" + } + } + maven { url "https://maven.blamejared.com/" } + maven { + name = "GHPCore" + url = uri("https://maven.pkg.github.com/p3pp3rf1y/sophisticatedcore") + credentials { + username = System.getenv("USERNAME") + password = System.getenv("READ_PACKAGES_TOKEN") + } + content { + includeGroupByRegex "sophisticatedcore.*" + } + } + maven { + name = "GHPStorage" + url = uri("https://maven.pkg.github.com/p3pp3rf1y/sophisticatedstorage") + credentials { + username = System.getenv("USERNAME") + password = System.getenv("READ_PACKAGES_TOKEN") + } + content { + includeGroupByRegex "sophisticatedstorage.*" + } + } + maven { + url = "https://maven.octo-studios.com/#/releases" + content { + includeGroup 'top.theillusivec4.curios' + } + } +} + +base { + archivesName = mod_id +} + +java.toolchain.languageVersion = JavaLanguageVersion.of(21) + +neoForge { + version = project.neo_version + + parchment { + mappingsVersion = project.parchment_mappings_version + minecraftVersion = project.parchment_minecraft_version + } + + accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg') + + runs { + configureEach { + systemProperty 'forge.logging.markers', 'REGISTRIES' + systemProperty 'forge.logging.console.level', 'debug' + systemProperty 'mixin.env.disableRefMap', 'true' + } + + client { + client() + } + + client2 { + client() + + programArguments.addAll '--username', 'Dev2' + } + + server { + server() + programArgument '--nogui' + } + + data { + data() + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + } + } + + mods { + "${mod_id}" { + sourceSet(sourceSets.main) + } + if (findProject(':SophisticatedCore') != null) { + "sophisticatedcore" { + sourceSet(project(':SophisticatedCore').sourceSets.main) + } + } + if (findProject(':SophisticatedStorage') != null) { + "sophisticatedcore" { + sourceSet(project(':SophisticatedStorage').sourceSets.main) + } + } + } + + unitTest { + enable() + testedMod = mods."${mod_id}" + } +} + +sourceSets.main.resources { + srcDir 'src/generated/resources' +} + +configurations { + runtimeClasspath.extendsFrom localRuntime +} + +dependencies { + compileOnly "mezz.jei:jei-${jei_mc_version}-api:${jei_version}" + localRuntime "mezz.jei:jei-${jei_mc_version}:${jei_version}" + + if (findProject(':SophisticatedCore') != null) { + dependencies.implementation project(':SophisticatedCore') + } else { + dependencies.implementation("sophisticatedcore:sophisticatedcore:${sc_version}") { + transitive = false + } + dependencies.testImplementation("sophisticatedcore:sophisticatedcore:${sc_version}") { + transitive = false + } + } + if (findProject(':SophisticatedStorage') != null) { + dependencies.implementation project(':SophisticatedStorage') + } else { + dependencies.implementation("sophisticatedstorage:sophisticatedstorage:${ss_version}") { + transitive = false + } + dependencies.testImplementation("sophisticatedstorage:sophisticatedstorage:${ss_version}") { + transitive = false + } + } +} + +var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { + var replaceProperties = [ + minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, + neo_version : neo_version, neo_version_range: neo_version_range, + loader_version_range: loader_version_range, + mod_id : mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, + mod_issue_tracker_url: mod_issue_tracker_url, mod_logo_file: mod_logo_file, mod_credits: mod_credits, + mod_authors : mod_authors, mod_description: mod_description, mod_display_url: mod_display_url, + mod_full_version : "${project.mod_version}.${getBuildNumber()}${getStable()}", + jei_version_range : jei_version_range, + ss_version :"[" + ss_version.substring(ss_version.indexOf("-") + 1, ss_version.lastIndexOf(',')) + ",)" + ] + inputs.properties replaceProperties + + expand replaceProperties + from "src/main/templates" + into "build/generated/sources/modMetadata" +} + +// Include the output of "generateModMetadata" as an input directory for the build +// this works with both building through Gradle and the IDE. +sourceSets.main.resources.srcDir generateModMetadata +// To avoid having to run "generateModMetadata" manually, make it run on every project reload +neoForge.ideSyncTask generateModMetadata + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +jar { + manifest { + attributes(["Specification-Title" : project.mod_id, + "Specification-Vendor" : project.mod_id, + "Specification-Version" : "1", + "Implementation-Title" : project.name, + "Implementation-Version" : "${version}", + "Implementation-Vendor" : project.mod_id, + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")],) + } +} + + +static def getBuildNumber() { + if (System.getenv("GITHUB_RUN_NUMBER") != null) { + return System.getenv("GITHUB_RUN_NUMBER").toString() + } + return "" +} + +static def getStable() { + if (System.getenv("GITHUB_REF") == null || System.getenv("GITHUB_REF").endsWith("-dev")) { + return "-SNAPSHOT" + } + return "" +} + +publishing { + repositories { + maven { + name = "GitHubPackages" + url = uri("${github_package_url}") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } + publications { + gpr(MavenPublication) { + artifactId = mod_id + from(components.java) + } + } +} + +sonarqube { + properties { + property "sonar.projectName", "${mod_id}" + property "sonar.projectKey", "${sonar_project_key}" + } +} + +task generateChangelog { + doLast { + def changelog = new StringBuilder() + + // Function to remove characters with Unicode code points 129 or higher + def removeHighUnicodeChars = { text -> + text.codePoints() + .filter { codePoint -> codePoint <= 0x007F } // Keep only ASCII characters (U+0000 to U+007F) + .collect { codePoint -> new String(Character.toChars(codePoint)) } + .join('') + } + + // Function to format commit messages with nesting + def formatMultilineMessage = { message -> + // Split message by lines, trim whitespace, and create formatted list + def lines = message.split('\n') + def formattedMessage = lines[0].trim() // First line as top-level list item + if (lines.size() > 1) { + formattedMessage += "\n" + lines[1..-1].collect { line -> + // Trim the line and remove leading dash if present + def trimmedLine = line.trim() + if (trimmedLine.startsWith('-')) { + trimmedLine = trimmedLine.substring(1).trim() + } + " - ${trimmedLine}" // Nested list for additional lines + }.join('\n') + } + return formattedMessage + } + + // Function to remove [DEV] section from commit message + def removeDevSection = { message -> + def devIndex = message.indexOf('[DEV]') + if (devIndex != -1) { + return message.substring(0, devIndex).trim() + } + return message + } + + // Get the latest commit hash + def latestCommitHash = "git rev-parse HEAD".execute().text.trim() + + // Check if the latest commit is a merge commit + def parentCommits = "git rev-list --parents -n 1 ${latestCommitHash}".execute().text.split() + logger.info("Parent commits: ${parentCommits}") + + def commitMessages = [] + if (parentCommits.size() > 2) { // Merge commit has more than 2 parents + def firstParent = parentCommits[1] + def secondParent = parentCommits[2] + def gitLogCommand = [ + "bash", "-c", "git log --pretty=format:%B ${firstParent}..${secondParent}" + ] + commitMessages = gitLogCommand.execute().text.split('\n\n') // Split by two newlines for each commit + logger.info("Merge commit, ran git log command: ${gitLogCommand.join(' ')} and got ${commitMessages}") + } else { + // Single commit log + commitMessages = "git log -1 --pretty=%B".execute().text.split('\n\n') + // Split by two newlines for each commit + logger.info("Single commit, ran git log command: git log -1 --pretty=%B and got ${commitMessages}"); + } + + def features = [] + def fixes = [] + commitMessages.each { commitMessage -> + commitMessage = removeHighUnicodeChars(commitMessage) // Remove high Unicode characters + commitMessage = removeDevSection(commitMessage) // Remove [DEV] section + + if (commitMessage.startsWith('feat: ')) { + features.add(commitMessage.replaceFirst('feat: ', '').trim()) + } else if (commitMessage.startsWith('fix: ')) { + fixes.add(commitMessage.replaceFirst('fix: ', '').trim()) + } + } + + if (features) { + changelog.append("### Features\n") + features.each { feature -> changelog.append("- ${formatMultilineMessage(feature)}\n") } + } + + if (fixes) { + changelog.append("### Fixes\n") + fixes.each { fix -> changelog.append("- ${formatMultilineMessage(fix)}\n") } + } + + // Store the changelog in a project property or an environment variable + logger.info("Compiled changelog: " + changelog.toString()) + project.ext.changelog = changelog.toString() + } + project.ext.changelog = "" +} + +task curseforge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { + dependsOn 'generateChangelog' + + apiToken = System.getenv("CURSEFORGE_TOKEN") + def mainFile = upload(project.curseforge_id, file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar")) + mainFile.changelogType = 'markdown' + mainFile.changelog = {project.ext.changelog} + mainFile.addModLoader('NeoForge') + mainFile.releaseType = "${release_type}" + "${release_versions}".split(',').each { + mainFile.addGameVersion("${it}") + } + mainFile.addRequirement('sophisticated-core') + mainFile.addOptional('jei') + mainFile.addOptional('crafting-tweaks') + onlyIf { !project.ext.changelog.isEmpty() } +} + +modrinth { + token = System.getenv("MODRINTH_TOKEN") + projectId = "${modrinth_project_id}" + versionType = "${release_type}" + uploadFile = jar + gameVersions = "${release_versions}".split(',').collect {e -> e} + loaders = ["neoforge"] + dependencies { + required.project "sophisticated-core" + optional.project "jei" + optional.project "crafting-tweaks" + } + changelog = provider { + project.ext.changelog + } +} +tasks.modrinth { + dependsOn(tasks.generateChangelog) + onlyIf { !project.ext.changelog.isEmpty() } +} + +task printVersionName { + println "version:" + project.version +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..d32bbce --- /dev/null +++ b/gradle.properties @@ -0,0 +1,39 @@ +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false +org.gradle.debug=false + +parchment_minecraft_version=1.21 +parchment_mappings_version=2024.11.10 +minecraft_version=1.21.1 +minecraft_version_range=[1.21.1,1.21.2) +neo_version=21.1.80 +neo_version_range=[21.1.0,) +loader_version_range=[4,) + +mod_id=sophisticatedstorageinmotion +mod_name=Sophisticated Storage In Motion +mod_license=GNU General Public License v3.0 +mod_version=0.0.1 +mod_group_id=sophisticatedstorageinmotion +mod_authors=P3pp3rF1y +mod_description=Sophisticated Storage on moving entities. +mod_credits=Created by P3pp3rF1y. +mod_logo_file=logo.png +mod_display_url=https://www.curseforge.com/minecraft/mc-mods/sophisticated-storage-in-motion +mod_issue_tracker_url=https://github.com/P3pp3rF1y/SophisticatedStorageInMotion/issues +sonar_project_key=sophisticatedstorageinmotion:SophisticatedStorageInMotion +github_package_url=https://maven.pkg.github.com/P3pp3rF1y/SophisticatedStorageInMotion + +jei_mc_version=1.21.1-neoforge +jei_version=19.12.0.131 +# first JEI version with Object UID support +jei_version_range=[19.9.0,) +ss_version=[1.21.1-1.0.1,1.22) + +#publish +#TODO add curseforge_id +curseforge_id=0 +release_type=release +release_versions=1.21.1 +#TODO add modrinth_project_id +modrinth_project_id=n/a \ 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..e4a5f61 --- /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.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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" + which java >/dev/null 2>&1 || 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 + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@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 + +@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= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +: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 %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..ada876e --- /dev/null +++ b/settings.gradle @@ -0,0 +1,11 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + maven { url = 'https://maven.neoforged.net/releases' } + } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/SophisticatedStorageInMotion.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/SophisticatedStorageInMotion.java new file mode 100644 index 0000000..89fb2ec --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/SophisticatedStorageInMotion.java @@ -0,0 +1,37 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion; + +import net.minecraft.resources.ResourceLocation; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.common.Mod; +import net.p3pp3rf1y.sophisticatedstorageinmotion.client.ClientEventHandler; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Mod(SophisticatedStorageInMotion.MOD_ID) +public class SophisticatedStorageInMotion { + public static final String MOD_ID = "sophisticatedstorageinmotion"; + public static final Logger LOGGER = LogManager.getLogger(MOD_ID); + + @SuppressWarnings("java:S1118") //needs to be public for mod to work + public SophisticatedStorageInMotion(IEventBus modBus, Dist dist, ModContainer container) { + ModItems.registerHandlers(modBus); + ModEntities.registerHandlers(modBus); + ModDataComponents.register(modBus); + if (dist == Dist.CLIENT) { + ClientEventHandler.registerHandlers(modBus); + ModEntitiesClient.registerHandlers(modBus); //TODO move this to client event handler + } + modBus.addListener(ModPayloads::registerPayloads); + } + + public static ResourceLocation getRL(String regName) { + return ResourceLocation.parse(getRegistryName(regName)); + } + + public static String getRegistryName(String regName) { + return MOD_ID + ":" + regName; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/ClientEventHandler.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/ClientEventHandler.java new file mode 100644 index 0000000..f78e392 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/ClientEventHandler.java @@ -0,0 +1,16 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client; + +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModItems; + +public class ClientEventHandler{ + + public static void registerHandlers(IEventBus modBus) { + modBus.addListener(ClientEventHandler::registerClientExtensions); + } + + private static void registerClientExtensions(RegisterClientExtensionsEvent event) { + event.registerItem(StorageMinecartItemRenderer.getItemRenderProperties(), ModItems.STORAGE_MINECART.get()); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/StorageMinecartItemRenderer.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/StorageMinecartItemRenderer.java new file mode 100644 index 0000000..28c0eaf --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/StorageMinecartItemRenderer.java @@ -0,0 +1,57 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.geom.EntityModelSet; +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.StorageMinecart; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModEntities; + +import javax.annotation.Nullable; + +public class StorageMinecartItemRenderer extends BlockEntityWithoutLevelRenderer { + @Nullable + private static StorageMinecart MINECART = null; + public StorageMinecartItemRenderer(BlockEntityRenderDispatcher blockEntityRenderDispatcher, EntityModelSet entityModelSet) { + super(blockEntityRenderDispatcher, entityModelSet); + } + + public static IClientItemExtensions getItemRenderProperties() { + return new IClientItemExtensions() { + @Override + public BlockEntityWithoutLevelRenderer getCustomRenderer() { + return new StorageMinecartItemRenderer(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels()); + } + }; + } + + @Override + public void renderByItem(ItemStack stack, ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) { + super.renderByItem(stack, displayContext, poseStack, buffer, packedLight, packedOverlay); + Minecraft mc = Minecraft.getInstance(); + if (mc.level == null) { + return; + } + + StorageMinecart minecart = getStorageMinecart(mc); + minecart.getStorageHolder().setStorageItemFrom(stack); + + poseStack.pushPose(); + poseStack.translate(0.5, 0, 0.5); + mc.getEntityRenderDispatcher().render(minecart, 0, 0, 0, 0, 0, poseStack, buffer, packedLight); + poseStack.popPose(); + } + + private static StorageMinecart getStorageMinecart(Minecraft mc) { + if (MINECART == null) { + MINECART = new StorageMinecart(ModEntities.STORAGE_MINECART.get(), mc.level); + } + + return MINECART; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/StorageMinecartRenderer.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/StorageMinecartRenderer.java new file mode 100644 index 0000000..0e28c09 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/StorageMinecartRenderer.java @@ -0,0 +1,141 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.client.renderer.entity.MinecartRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.ColorResolver; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import net.neoforged.neoforge.client.RenderTypeHelper; +import net.neoforged.neoforge.client.model.data.ModelData; +import net.p3pp3rf1y.sophisticatedstorage.block.BarrelBlockEntity; +import net.p3pp3rf1y.sophisticatedstorage.block.ShulkerBoxBlockEntity; +import net.p3pp3rf1y.sophisticatedstorage.block.StorageBlockEntity; +import net.p3pp3rf1y.sophisticatedstorage.client.render.BarrelBakedModelBase; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.StorageMinecart; +import org.jetbrains.annotations.Nullable; + +public class StorageMinecartRenderer extends MinecartRenderer { + public StorageMinecartRenderer(EntityRendererProvider.Context context) { + super(context, ModelLayers.MINECART); + } + + @Override + protected void renderMinecartContents(StorageMinecart entity, float partialTicks, BlockState state, PoseStack poseStack, MultiBufferSource buffer, int packedLight) { + StorageBlockEntity renderBlockEntity = entity.getStorageHolder().getRenderBlockEntity(); + + Minecraft minecraft = Minecraft.getInstance(); + + BlockAndTintGetter wrappedLevel = new StaticBlockEntityTintGetter(minecraft.level, renderBlockEntity, packedLight); //TODO try to optimize not to create a new instance all the time, perhaps level keyed cache for these and then only setting blockentity in the render call + + poseStack.pushPose(); + double yOffset = 0; + if (renderBlockEntity instanceof BarrelBlockEntity || renderBlockEntity instanceof ShulkerBoxBlockEntity) { + yOffset -= 2 / 16D; + } + poseStack.translate(0, yOffset, 0); + if (renderBlockEntity instanceof BarrelBlockEntity barrel) { + BlockRenderDispatcher blockRenderer = minecraft.getBlockRenderer(); + BakedModel bakedModel = blockRenderer.getBlockModel(barrel.getBlockState()); + ModelData modelData = BarrelBakedModelBase.getModelDataFromBlockEntity(barrel); + for (RenderType renderType : bakedModel.getRenderTypes(state, RandomSource.create(42L), modelData)) { + VertexConsumer vertexConsumer = buffer.getBuffer(RenderTypeHelper.getEntityRenderType(renderType, false)); + RandomSource randomsource = RandomSource.create(); + randomsource.setSeed(42L); + blockRenderer.getModelRenderer().tesselateWithoutAO(wrappedLevel, bakedModel, barrel.getBlockState(), BlockPos.ZERO, poseStack, vertexConsumer, false, randomsource, state.getSeed(BlockPos.ZERO), OverlayTexture.NO_OVERLAY, modelData, renderType); + } + } + + BlockEntityRenderer renderer = minecraft.getBlockEntityRenderDispatcher().getRenderer(renderBlockEntity); + if (renderer != null) { + renderer.render(renderBlockEntity, partialTicks, poseStack, buffer, packedLight, OverlayTexture.NO_OVERLAY); + } + poseStack.popPose(); + } + + private static class StaticBlockEntityTintGetter implements BlockAndTintGetter { + private final BlockAndTintGetter level; + private final BlockEntity blockEntity; + private final int packedLight; + + public StaticBlockEntityTintGetter(BlockAndTintGetter level, BlockEntity blockEntity, int packedLight) { + this.level = level; + this.blockEntity = blockEntity; + this.packedLight = packedLight; + } + + @Override + public float getShade(Direction direction, boolean b) { + return level.getShade(direction, b); + } + + @Override + public LevelLightEngine getLightEngine() { + return level.getLightEngine(); + } + + @Override + public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { + return level.getBlockTint(blockPos, colorResolver); + } + + @Nullable + @Override + public BlockEntity getBlockEntity(BlockPos blockPos) { + return blockPos == BlockPos.ZERO ? blockEntity : level.getBlockEntity(blockPos); + } + + @Override + public BlockState getBlockState(BlockPos blockPos) { + return blockPos == BlockPos.ZERO ? blockEntity.getBlockState() : level.getBlockState(blockPos); + } + + @Override + public FluidState getFluidState(BlockPos blockPos) { + return level.getFluidState(blockPos); + } + + @Override + public int getHeight() { + return level.getHeight(); + } + + @Override + public int getMinBuildHeight() { + return level.getMinBuildHeight(); + } + + @Override + public int getLightEmission(BlockPos pos) { + return 0; + } + + @Override + public int getBrightness(LightLayer lightType, BlockPos blockPos) { + return lightType == LightLayer.SKY ? packedLight >> 20 : packedLight >> 4 & 15; + } + + @Override + public int getRawBrightness(BlockPos blockPos, int amount) { + int skyValue = packedLight >> 20; + int blockValue = packedLight >> 4 & 15; + return Math.max(blockValue, skyValue - amount); + } + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/BackToMovingStorageTab.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/BackToMovingStorageTab.java new file mode 100644 index 0000000..a696b50 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/BackToMovingStorageTab.java @@ -0,0 +1,26 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.minecraft.network.chat.Component; +import net.neoforged.neoforge.network.PacketDistributor; +import net.p3pp3rf1y.sophisticatedcore.client.gui.Tab; +import net.p3pp3rf1y.sophisticatedcore.client.gui.controls.ImageButton; +import net.p3pp3rf1y.sophisticatedcore.client.gui.utils.*; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageTranslationHelper; +import net.p3pp3rf1y.sophisticatedstorageinmotion.network.OpenMovingStorageInventoryPayload; + +public class BackToMovingStorageTab extends Tab { + private static final TextureBlitData ICON = new TextureBlitData(GuiHelper.ICONS, Dimension.SQUARE_256, new UV(64, 80), Dimension.SQUARE_16); + + private final int entityId; + + protected BackToMovingStorageTab(Position position, int entityId) { + super(position, Component.translatable(StorageTranslationHelper.INSTANCE.translGui("back_to_storage.tooltip")), + onTabIconClicked -> new ImageButton(new Position(position.x() + 1, position.y() + 4), Dimension.SQUARE_16, ICON, onTabIconClicked)); + this.entityId = entityId; + } + + @Override + protected void onTabIconClicked(int button) { + PacketDistributor.sendToServer(new OpenMovingStorageInventoryPayload(entityId)); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingLimitedBarrelScreen.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingLimitedBarrelScreen.java new file mode 100644 index 0000000..fef7b8f --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingLimitedBarrelScreen.java @@ -0,0 +1,46 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.LimitedBarrelScreen; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageContainerMenu; + +public class MovingLimitedBarrelScreen extends MovingStorageScreen { + public static final int STORAGE_SLOTS_HEIGHT = 82; + + public MovingLimitedBarrelScreen(MovingStorageContainerMenu menu, Inventory playerInventory, Component title) { + super(menu, playerInventory, title); + } + + @Override + protected void drawSlotBg(GuiGraphics guiGraphics, int x, int y, int visibleSlotsCount) { + LimitedBarrelScreen.drawSlotBg(this, guiGraphics, x, y, getMenu().getNumberOfStorageInventorySlots()); + } + + @Override + protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { + super.renderLabels(guiGraphics, mouseX, mouseY); + LimitedBarrelScreen.renderBars(font, imageWidth, getMenu(), guiGraphics, getMenu()::getSlotFillPercentage); + } + + @Override + protected int getStorageInventoryHeight(int displayableNumberOfRows) { + return STORAGE_SLOTS_HEIGHT; + } + + @Override + protected void updateStorageSlotsPositions() { + LimitedBarrelScreen.updateSlotPositions(getMenu(), getMenu().getNumberOfStorageInventorySlots(), imageWidth); + } + + @Override + protected boolean shouldShowSortButtons() { + return false; + } + + @Override + protected void addSearchBox() { + // No search box for limited barrels + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingLimitedBarrelSettingsScreen.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingLimitedBarrelSettingsScreen.java new file mode 100644 index 0000000..c3ef397 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingLimitedBarrelSettingsScreen.java @@ -0,0 +1,42 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.p3pp3rf1y.sophisticatedcore.client.gui.utils.Position; +import net.p3pp3rf1y.sophisticatedcore.common.gui.SettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedcore.settings.StorageSettingsTabControlBase; +import net.p3pp3rf1y.sophisticatedcore.settings.itemdisplay.ItemDisplaySettingsCategory; +import net.p3pp3rf1y.sophisticatedcore.settings.nosort.NoSortSettingsCategory; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.LimitedBarrelScreen; + +public class MovingLimitedBarrelSettingsScreen extends MovingStorageSettingsScreen { + public MovingLimitedBarrelSettingsScreen(SettingsContainerMenu screenContainer, Inventory inv, Component title) { + super(screenContainer, inv, title); + } + + @Override + protected int getStorageInventoryHeight(int displayableNumberOfRows) { + return LimitedBarrelScreen.STORAGE_SLOTS_HEIGHT; + } + + @Override + protected void updateStorageSlotsPositions() { + LimitedBarrelScreen.updateSlotPositions(getMenu(), getMenu().getNumberOfStorageInventorySlots(), imageWidth); + } + + @Override + protected void drawSlotBg(GuiGraphics guiGraphics, int x, int y, int visibleSlotsCount) { + LimitedBarrelScreen.drawSlotBg(this, guiGraphics, x, y, getMenu().getNumberOfStorageInventorySlots()); + } + + @Override + protected StorageSettingsTabControlBase initializeTabControl() { + return new MovingStorageSettingsTabControl(this, new Position(leftPos + imageWidth, topPos + 4)) { + @Override + protected boolean isSettingsCategoryDisabled(String categoryName) { + return categoryName.equals(ItemDisplaySettingsCategory.NAME) || categoryName.equals(NoSortSettingsCategory.NAME); + } + }; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageScreen.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageScreen.java new file mode 100644 index 0000000..14a5b82 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageScreen.java @@ -0,0 +1,22 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.p3pp3rf1y.sophisticatedcore.client.gui.StorageScreenBase; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageTranslationHelper; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageContainerMenu; + +public class MovingStorageScreen extends StorageScreenBase { + public static MovingStorageScreen constructScreen(MovingStorageContainerMenu screenContainer, Inventory inv, Component title) { + return new MovingStorageScreen(screenContainer, inv, title); + } + + protected MovingStorageScreen(MovingStorageContainerMenu menu, Inventory playerInventory, Component title) { + super(menu, playerInventory, title); + } + + @Override + protected String getStorageSettingsTabTooltip() { + return StorageTranslationHelper.INSTANCE.translGui("settings.tooltip"); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageSettingsScreen.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageSettingsScreen.java new file mode 100644 index 0000000..d8dbdcd --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageSettingsScreen.java @@ -0,0 +1,33 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.neoforged.neoforge.network.PacketDistributor; +import net.p3pp3rf1y.sophisticatedcore.client.gui.utils.Position; +import net.p3pp3rf1y.sophisticatedcore.common.gui.SettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedcore.settings.StorageSettingsTabControlBase; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageSettingsScreen; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageSettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.network.OpenMovingStorageInventoryPayload; + +public class MovingStorageSettingsScreen extends StorageSettingsScreen { + private final int entityId; + public MovingStorageSettingsScreen(SettingsContainerMenu screenContainer, Inventory inv, Component title) { + super(screenContainer, inv, title); + this.entityId = screenContainer instanceof MovingStorageSettingsContainerMenu menu ? menu.getEntityId() : -1; + } + + @Override + protected StorageSettingsTabControlBase initializeTabControl() { + return new MovingStorageSettingsTabControl(this, new Position(leftPos + imageWidth, topPos + 4)); + } + + @Override + protected void sendStorageInventoryScreenOpenMessage() { + PacketDistributor.sendToServer(new OpenMovingStorageInventoryPayload(entityId)); + } + + public static MovingStorageSettingsScreen constructScreen(SettingsContainerMenu screenContainer, Inventory inventory, Component title) { + return new MovingStorageSettingsScreen(screenContainer, inventory, title); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageSettingsTabControl.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageSettingsTabControl.java new file mode 100644 index 0000000..dc0995a --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/MovingStorageSettingsTabControl.java @@ -0,0 +1,17 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.p3pp3rf1y.sophisticatedcore.client.gui.Tab; +import net.p3pp3rf1y.sophisticatedcore.client.gui.utils.Position; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageSettingsTabControl; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageSettingsContainerMenu; + +public class MovingStorageSettingsTabControl extends StorageSettingsTabControl { + protected MovingStorageSettingsTabControl(MovingStorageSettingsScreen screen, Position position) { + super(screen, position); + } + + @Override + protected Tab instantiateReturnBackTab() { + return new BackToMovingStorageTab(new Position(x, getTopY()), screen.getMenu() instanceof MovingStorageSettingsContainerMenu menu ? menu.getEntityId() : -1); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/package-info.java new file mode 100644 index 0000000..b48540c --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/gui/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/package-info.java new file mode 100644 index 0000000..3246872 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/client/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.client; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingLimitedBarrelContainerMenu.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingLimitedBarrelContainerMenu.java new file mode 100644 index 0000000..5ced00f --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingLimitedBarrelContainerMenu.java @@ -0,0 +1,28 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModEntities; + +import java.util.List; + +public class MovingLimitedBarrelContainerMenu extends MovingStorageContainerMenu { + public MovingLimitedBarrelContainerMenu(int containerId, Player player, int entityId) { + super(ModEntities.MOVING_LIMITED_BARREL_CONTAINER_TYPE.get(), containerId, player, entityId); + } + + public static MovingLimitedBarrelContainerMenu fromBuffer(int windowId, Inventory playerInventory, FriendlyByteBuf buffer) { + return new MovingLimitedBarrelContainerMenu(windowId, playerInventory.player, buffer.readInt()); + } + + @Override + protected MovingStorageSettingsContainerMenu instantiateSettingsContainerMenu(int windowId, Player player, int entityId) { + return new MovingLimitedBarrelSettingsContainerMenu(windowId, player, entityId); + } + + @Override + public List getSlotOverlayColors(int slot) { + return List.of(); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingLimitedBarrelSettingsContainerMenu.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingLimitedBarrelSettingsContainerMenu.java new file mode 100644 index 0000000..8883bd6 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingLimitedBarrelSettingsContainerMenu.java @@ -0,0 +1,16 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModEntities; + +public class MovingLimitedBarrelSettingsContainerMenu extends MovingStorageSettingsContainerMenu { + protected MovingLimitedBarrelSettingsContainerMenu(int windowId, Player player, int entityId) { + super(ModEntities.MOVING_LIMITED_BARREL_SETTINGS_CONTAINER_TYPE.get(), windowId, player, entityId); + } + + public static MovingLimitedBarrelSettingsContainerMenu fromBuffer(int windowId, Inventory playerInventory, FriendlyByteBuf buffer) { + return new MovingLimitedBarrelSettingsContainerMenu(windowId, playerInventory.player, buffer.readInt()); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingStorageContainerMenu.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingStorageContainerMenu.java new file mode 100644 index 0000000..42f2f92 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingStorageContainerMenu.java @@ -0,0 +1,169 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.network.PacketDistributor; +import net.p3pp3rf1y.sophisticatedcore.api.IStorageWrapper; +import net.p3pp3rf1y.sophisticatedcore.common.gui.ISyncedContainer; +import net.p3pp3rf1y.sophisticatedcore.common.gui.SophisticatedMenuProvider; +import net.p3pp3rf1y.sophisticatedcore.common.gui.StorageContainerMenuBase; +import net.p3pp3rf1y.sophisticatedcore.settings.itemdisplay.ItemDisplaySettingsCategory; +import net.p3pp3rf1y.sophisticatedcore.upgrades.UpgradeHandler; +import net.p3pp3rf1y.sophisticatedcore.util.NoopStorageWrapper; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageTranslationHelper; +import net.p3pp3rf1y.sophisticatedstorageinmotion.data.MovingStorageData; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.IMovingStorageEntity; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.MovingStorageWrapper; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.StorageMinecart; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModEntities; +import net.p3pp3rf1y.sophisticatedstorageinmotion.network.MovingStorageContentsPayload; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.Optional; + +public class MovingStorageContainerMenu extends StorageContainerMenuBase implements ISyncedContainer { + protected final WeakReference storageEntity; + + @Nullable + private CompoundTag lastSettingsNbt = null; + + public MovingStorageContainerMenu(int containerId, Player player, int entityId) { + this(ModEntities.MOVING_STORAGE_CONTAINER_TYPE.get(), containerId, player, entityId); + } + + public MovingStorageContainerMenu(MenuType menuType, int containerId, Player player, int entityId) { + super(menuType, containerId, player, getWrapper(player.level(), entityId), NoopStorageWrapper.INSTANCE, -1, false); + if (!(player.level().getEntity(entityId) instanceof IMovingStorageEntity movingStorageEntity)) { + throw new IllegalArgumentException("Incorrect entity with id " + entityId + " expected to find IMovingStorageEntity"); + } + storageEntity = new WeakReference<>(movingStorageEntity); + movingStorageEntity.getStorageHolder().startOpen(player); + } + + public Optional getStorageEntity() { + return Optional.ofNullable(storageEntity.get()); + } + + @Override + public void removed(Player player) { + super.removed(player); + getStorageEntity().ifPresent(storageEntity -> storageEntity.getStorageHolder().stopOpen(player)); + } + + private static IStorageWrapper getWrapper(Level level, int entityId) { + if (!(level.getEntity(entityId) instanceof StorageMinecart storageMinecart)) { + return NoopStorageWrapper.INSTANCE; + } + + return storageMinecart.getStorageHolder().getStorageWrapper(); + } + + public static MovingStorageContainerMenu fromBuffer(int windowId, Inventory playerInventory, FriendlyByteBuf buffer) { + return new MovingStorageContainerMenu(windowId, playerInventory.player, buffer.readInt()); + } + + @Override + public Optional getBlockPosition() { + return Optional.empty(); + } + + @Override + protected StorageContainerMenuBase.StorageUpgradeSlot instantiateUpgradeSlot(UpgradeHandler upgradeHandler, int slotIndex) { + return new StorageUpgradeSlot(upgradeHandler, slotIndex) { + @Override + protected void onUpgradeChanged() { + if (player.level().isClientSide()) { + return; + } + storageWrapper.getSettingsHandler().getTypeCategory(ItemDisplaySettingsCategory.class).itemsChanged(); + } + }; + } + + @Override + public void openSettings() { + if (isClientSide()) { + sendToServer(data -> data.putString(ACTION_TAG, "openSettings")); + return; + } + getStorageEntity().ifPresent(entity -> + player.openMenu(new SophisticatedMenuProvider((w, p, pl) -> instantiateSettingsContainerMenu(w, pl, entity.getId()), + Component.translatable(StorageTranslationHelper.INSTANCE.translGui("settings.title")), false), buffer -> buffer.writeInt(entity.getId())) + ); + } + + protected MovingStorageSettingsContainerMenu instantiateSettingsContainerMenu(int windowId, Player player, int entityId) { + return new MovingStorageSettingsContainerMenu(windowId, player, entityId); + } + + @Override + protected boolean storageItemHasChanged() { + return false; //the stack is only used for internal tracking in moving entities so it can't be swapped away by a player + } + + @Override + public boolean detectSettingsChangeAndReload() { + if (player.level().isClientSide) { + return storageWrapper.getContentsUuid().map(uuid -> { + MovingStorageData storage = MovingStorageData.get(uuid); + if (storage.removeUpdatedStorageSettingsFlag(uuid)) { + storageWrapper.getSettingsHandler().reloadFrom(storage.getContents().getCompound(MovingStorageWrapper.SETTINGS_TAG)); + return true; + } + return false; + }).orElse(false); + } + return false; + } + + @Override + public boolean stillValid(Player player) { + return getStorageEntity().map(se -> player.distanceToSqr(se.position()) <= 64.0D).orElse(false); //TODO if packing is allowed check if not packed here + } + + /* TODO base on storage wrapper in stack + public float getSlotFillPercentage(int slot) { + return storageBlockEntity.getSlotFillPercentage(slot); + } +*/ + + @Override + protected void sendStorageSettingsToClient() { + if (player.level().isClientSide) { + return; + } + + if (lastSettingsNbt == null || !lastSettingsNbt.equals(storageWrapper.getSettingsHandler().getNbt())) { + lastSettingsNbt = storageWrapper.getSettingsHandler().getNbt().copy(); + + storageWrapper.getContentsUuid().ifPresent(uuid -> { + CompoundTag settingsContents = new CompoundTag(); + CompoundTag settingsNbt = storageWrapper.getSettingsHandler().getNbt(); + if (!settingsNbt.isEmpty()) { + settingsContents.put(MovingStorageWrapper.SETTINGS_TAG, settingsNbt); + if (player instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new MovingStorageContentsPayload(uuid, settingsContents)); + } + } + }); + } + } + + public float getSlotFillPercentage(int slot) { + IMovingStorageEntity entity = storageEntity.get(); + if (entity == null) { + return 0; + } + List slotFillRatios = entity.getStorageHolder().getStorageWrapper().getRenderInfo().getItemDisplayRenderInfo().getSlotFillRatios(); + return slot > -1 && slot < slotFillRatios.size() ? slotFillRatios.get(slot) : 0; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingStorageSettingsContainerMenu.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingStorageSettingsContainerMenu.java new file mode 100644 index 0000000..b46c9d4 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/MovingStorageSettingsContainerMenu.java @@ -0,0 +1,88 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.network.PacketDistributor; +import net.p3pp3rf1y.sophisticatedcore.api.IStorageWrapper; +import net.p3pp3rf1y.sophisticatedcore.common.gui.SettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedcore.util.NoopStorageWrapper; +import net.p3pp3rf1y.sophisticatedstorageinmotion.data.MovingStorageData; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.MovingStorageWrapper; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.StorageMinecart; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModEntities; +import net.p3pp3rf1y.sophisticatedstorageinmotion.network.MovingStorageContentsPayload; + +public class MovingStorageSettingsContainerMenu extends SettingsContainerMenu { + private final int entityId; + private CompoundTag lastSettingsNbt = null; + + protected MovingStorageSettingsContainerMenu(int windowId, Player player, int entityId) { + this(ModEntities.MOVING_STORAGE_SETTINGS_CONTAINER_TYPE.get(), windowId, player, entityId); + } + + protected MovingStorageSettingsContainerMenu(MenuType menuType, int windowId, Player player, int entityId) { + super(menuType, windowId, player, getWrapper(player.level(), entityId)); + this.entityId = entityId; + } + + private static IStorageWrapper getWrapper(Level level, int entityId) { + if (!(level.getEntity(entityId) instanceof StorageMinecart storageMinecart)) { + return NoopStorageWrapper.INSTANCE; + } + + return storageMinecart.getStorageHolder().getStorageWrapper(); + } + + @Override + public void detectSettingsChangeAndReload() { + if (player.level().isClientSide) { + storageWrapper.getContentsUuid().ifPresent(uuid -> { + MovingStorageData storage = MovingStorageData.get(uuid); + if (storage.removeUpdatedStorageSettingsFlag(uuid)) { + storageWrapper.getSettingsHandler().reloadFrom(storage.getContents().getCompound(MovingStorageWrapper.SETTINGS_TAG)); + } + }); + } + } + + public static MovingStorageSettingsContainerMenu fromBuffer(int windowId, Inventory playerInventory, FriendlyByteBuf buffer) { + return new MovingStorageSettingsContainerMenu(windowId, playerInventory.player, buffer.readInt()); + } + + public int getEntityId() { + return entityId; + } + + private void sendStorageSettingsToClient() { + if (player.level().isClientSide) { + return; + } + + if (lastSettingsNbt == null || !lastSettingsNbt.equals(storageWrapper.getSettingsHandler().getNbt())) { + lastSettingsNbt = storageWrapper.getSettingsHandler().getNbt().copy(); + + storageWrapper.getContentsUuid().ifPresent(uuid -> { + CompoundTag settingsContents = new CompoundTag(); + CompoundTag settingsNbt = storageWrapper.getSettingsHandler().getNbt(); + if (!settingsNbt.isEmpty()) { + settingsContents.put(MovingStorageWrapper.SETTINGS_TAG, settingsNbt); + if (player instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new MovingStorageContentsPayload(uuid, settingsContents)); + } + } + }); + } + } + + @Override + public void broadcastChanges() { + super.broadcastChanges(); + + sendStorageSettingsToClient(); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/package-info.java new file mode 100644 index 0000000..be1c7df --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/common/gui/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/data/MovingStorageData.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/data/MovingStorageData.java new file mode 100644 index 0000000..92270bc --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/data/MovingStorageData.java @@ -0,0 +1,97 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.data; + +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.SavedData; +import net.minecraft.world.level.storage.DimensionDataStorage; +import net.neoforged.fml.util.thread.SidedThreadGroups; +import net.neoforged.neoforge.server.ServerLifecycleHooks; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.MovingStorageWrapper; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.*; + +public class MovingStorageData extends SavedData { + private static final String SAVED_DATA_PREFIX = SophisticatedStorageInMotion.MOD_ID + "/"; + + private CompoundTag movingStorageContents = new CompoundTag(); + + private boolean toRemove = false; + private static final Map clientStorageCopy = new HashMap<>(); //TODO maybe change to cache so that deleted ones get removed? + private final Set updatedStorageSettingsFlags = new HashSet<>(); + + private MovingStorageData() { + } + + public static MovingStorageData get(UUID storageId) { + if (Thread.currentThread().getThreadGroup() == SidedThreadGroups.SERVER) { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + ServerLevel overworld = server.getLevel(Level.OVERWORLD); + //noinspection ConstantConditions - by this time overworld is loaded + DimensionDataStorage storage = overworld.getDataStorage(); + return storage.computeIfAbsent(new Factory<>(MovingStorageData::new, MovingStorageData::load), SAVED_DATA_PREFIX + storageId); + } + } + return clientStorageCopy.computeIfAbsent(storageId, id -> new MovingStorageData()); + } + + public static MovingStorageData load(CompoundTag nbt, HolderLookup.Provider registries) { + MovingStorageData storageData = new MovingStorageData(); + storageData.movingStorageContents = nbt; + return storageData; + } + + @Override + public CompoundTag save(CompoundTag compound, HolderLookup.Provider registries) { + if (movingStorageContents != null) { + return movingStorageContents; + } + return new CompoundTag(); + } + + public void removeStorageContents(UUID backpackUuid) { + toRemove = true; + setDirty(); + } + + @Override + public void save(File file, HolderLookup.Provider registries) { + if (toRemove) { + file.delete(); + } else { + try { + Files.createDirectories(file.toPath().getParent()); + } catch (IOException e) { + SophisticatedStorageInMotion.LOGGER.error("Failed to create directories for moving storage data", e); + } + super.save(file, registries); + } + } + + public void setContents(UUID storageUuid, CompoundTag contents) { + for (String key : contents.getAllKeys()) { + //noinspection ConstantConditions - the key is one of the tag keys so there's no reason it wouldn't exist here + movingStorageContents.put(key, contents.get(key)); + + if (key.equals(MovingStorageWrapper.SETTINGS_TAG)) { + updatedStorageSettingsFlags.add(storageUuid); + } + } + setDirty(); + } + + public CompoundTag getContents() { + return movingStorageContents; + } + + public boolean removeUpdatedStorageSettingsFlag(UUID backpackUuid) { + return updatedStorageSettingsFlags.remove(backpackUuid); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/data/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/data/package-info.java new file mode 100644 index 0000000..ca5f412 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/data/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.data; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/EntityStorageHolder.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/EntityStorageHolder.java new file mode 100644 index 0000000..7e2055a --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/EntityStorageHolder.java @@ -0,0 +1,270 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.monster.piglin.PiglinAi; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.block.state.properties.WoodType; +import net.minecraft.world.level.gameevent.GameEvent; +import net.p3pp3rf1y.sophisticatedcore.api.IStorageWrapper; +import net.p3pp3rf1y.sophisticatedcore.common.gui.SophisticatedMenuProvider; +import net.p3pp3rf1y.sophisticatedcore.init.ModCoreDataComponents; +import net.p3pp3rf1y.sophisticatedcore.renderdata.RenderInfo; +import net.p3pp3rf1y.sophisticatedcore.upgrades.ITickableUpgrade; +import net.p3pp3rf1y.sophisticatedcore.util.NoopStorageWrapper; +import net.p3pp3rf1y.sophisticatedcore.util.SimpleItemContent; +import net.p3pp3rf1y.sophisticatedstorage.block.*; +import net.p3pp3rf1y.sophisticatedstorage.init.ModBlocks; +import net.p3pp3rf1y.sophisticatedstorage.item.BarrelBlockItem; +import net.p3pp3rf1y.sophisticatedstorage.item.StorageBlockItem; +import net.p3pp3rf1y.sophisticatedstorage.item.WoodStorageBlockItem; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingLimitedBarrelContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.data.MovingStorageData; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModDataComponents; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.UUID; + +public class EntityStorageHolder { + private final T entity; + + @Nullable + private StorageBlockEntity renderBlockEntity = null; + + private IStorageWrapper storageWrapper = NoopStorageWrapper.INSTANCE; + + public EntityStorageHolder(T entity) { + this.entity = entity; + } + + public static boolean areUpgradesVisible(ItemStack storageItem) { + return storageItem.getOrDefault(ModDataComponents.UPGRADES_VISIBLE, false); + } + + public void setStorageItemFrom(ItemStack stack) { + SimpleItemContent storageItemContents = stack.get(ModDataComponents.STORAGE_ITEM.get()); + if (storageItemContents == null) { + ItemStack barrel = new ItemStack(ModBlocks.BARREL_ITEM.get()); + WoodStorageBlockItem.setWoodType(barrel, WoodType.SPRUCE); + setStorageItem(barrel); + } else { + ItemStack storageItem = storageItemContents.copy(); + setStorageItem(storageItem); + if (isLimitedBarrel(storageItem)) { + LimitedBarrelBlock.setupDefaultSettings(getStorageWrapper(), storageWrapper instanceof MovingStorageWrapper movingStorageWrapper ? movingStorageWrapper.getNumberOfInventorySlots() : storageWrapper.getInventoryHandler().getSlots()); + } + } + } + + public CompoundTag saveData(HolderLookup.Provider registries) { + CompoundTag ret = new CompoundTag(); + ItemStack storageItem = entity.getStorageItem(); + if (!storageItem.isEmpty()) { + ret.put("storageItem", storageItem.save(registries, new CompoundTag())); + } + return ret; + } + + public void readData(HolderLookup.Provider registries, CompoundTag tag) { + if (tag.contains("storageItem")) { + setStorageItem(ItemStack.parseOptional(registries, tag.getCompound("storageItem"))); + } + } + + public void setStorageItem(ItemStack storageItem) { + entity.setStorageItem(storageItem); + storageWrapper = NoopStorageWrapper.INSTANCE; //reset storage wrapper to force update when it's next requested + renderBlockEntity = null; + } + + public void updateStorageWrapper() { + ItemStack storageItem = entity.getStorageItem(); + UUID id = storageItem.get(ModCoreDataComponents.STORAGE_UUID); + if (id == null) { + id = UUID.randomUUID(); + storageItem.set(ModCoreDataComponents.STORAGE_UUID, id); + setStorageItem(storageItem); + } + + storageWrapper = MovingStorageWrapper.fromStack(storageItem, this::onContentsChanged, this::onStackChanged, entity.level()); + } + + public IStorageWrapper getStorageWrapper() { + if (!entity.getStorageItem().isEmpty() && storageWrapper == NoopStorageWrapper.INSTANCE) { + updateStorageWrapper(); + } + + return storageWrapper; + } + + private void setRenderBlockEntity(StorageBlockEntity storageBlockEntity) { + this.renderBlockEntity = storageBlockEntity; + } + + private void onStackChanged() { + entity.setStorageItem(getStorageWrapper().getWrappedStorageStack()); + renderBlockEntity = null; + } + + private void onContentsChanged() { + if (entity.level().isClientSide()) { + return; + } + + ItemStack storageItem = entity.getStorageItem(); + @Nullable UUID storageId = storageItem.get(ModCoreDataComponents.STORAGE_UUID); + if (storageId == null) { + return; + } + MovingStorageData.get(storageId).setDirty(); + } + + public void dropAllItems() { + //TODO implement + } + + public void startOpen(Player player) { + entity.gameEvent(GameEvent.CONTAINER_OPEN, player); + PiglinAi.angerNearbyPiglins(player, true); + + //TODO implement openers tracking? Would require stopOpen override in that case as well + } + + public void stopOpen(Player player) { + //noop + } + + public void tick() { + if (entity.level().isClientSide()) { + return; + } + getStorageWrapper().getUpgradeHandler().getWrappersThatImplement(ITickableUpgrade.class).forEach(upgrade -> upgrade.tick(entity, entity.level(), entity.blockPosition())); + } + + public static boolean isLocked(ItemStack stack) { + return stack.getOrDefault(ModDataComponents.LOCKED, false); + } + + public static boolean isLockVisible(ItemStack storageItem) { + return storageItem.getOrDefault(ModDataComponents.LOCK_VISIBLE, true); + } + + public static CompoundTag getRenderInfoNbt(ItemStack storageItem) { + return storageItem.getOrDefault(ModCoreDataComponents.RENDER_INFO_TAG, CustomData.EMPTY).copyTag(); + } + + public StorageBlockEntity getRenderBlockEntity() { + if (renderBlockEntity == null) { + ItemStack storageItem = entity.getStorageItem(); + if (storageItem.getItem() instanceof BlockItem blockItem) { + if (blockItem.getBlock() instanceof ChestBlock) { + renderBlockEntity = new ChestBlockEntity(BlockPos.ZERO, blockItem.getBlock().defaultBlockState()); + } else if (blockItem.getBlock() instanceof LimitedBarrelBlock) { + renderBlockEntity = new LimitedBarrelBlockEntity(BlockPos.ZERO, + blockItem.getBlock().defaultBlockState() + .setValue(LimitedBarrelBlock.HORIZONTAL_FACING, Direction.NORTH) + .setValue(LimitedBarrelBlock.VERTICAL_FACING, VerticalFacing.UP) + ); + } else if (blockItem.getBlock() instanceof BarrelBlock) { + renderBlockEntity = new BarrelBlockEntity(BlockPos.ZERO, + blockItem.getBlock().defaultBlockState() + .setValue(BarrelBlock.FACING, Direction.UP) + ); + } else if (blockItem.getBlock() instanceof ShulkerBoxBlock) { + renderBlockEntity = new ShulkerBoxBlockEntity(BlockPos.ZERO, blockItem.getBlock().defaultBlockState()); + } + + if (renderBlockEntity != null) { + if (renderBlockEntity.isLocked() != EntityStorageHolder.isLocked(storageItem)) { + renderBlockEntity.toggleLock(); + } + if (renderBlockEntity.shouldShowLock() != EntityStorageHolder.isLockVisible(storageItem)) { + renderBlockEntity.toggleLockVisibility(); + } + if (renderBlockEntity.shouldShowTier() != StorageBlockItem.showsTier(storageItem)) { + renderBlockEntity.toggleTierVisiblity(); + } + renderBlockEntity.getStorageWrapper().getRenderInfo().deserializeFrom(EntityStorageHolder.getRenderInfoNbt(storageItem)); + if (renderBlockEntity.shouldShowUpgrades() != EntityStorageHolder.areUpgradesVisible(storageItem)) { + renderBlockEntity.toggleUpgradesVisiblity(); + } + if (storageItem.getItem() instanceof ITintableBlockItem tintableBlockItem) { + renderBlockEntity.getStorageWrapper().setMainColor(tintableBlockItem.getMainColor(storageItem).orElse(-1)); + renderBlockEntity.getStorageWrapper().setAccentColor(tintableBlockItem.getAccentColor(storageItem).orElse(-1)); + } + if (renderBlockEntity instanceof WoodStorageBlockEntity woodStorage) { + WoodStorageBlockItem.getWoodType(storageItem).ifPresent(woodType -> { + if (woodStorage.getWoodType() != WoodStorageBlockItem.getWoodType(storageItem)) { + woodStorage.setWoodType(woodType); + } + }); + boolean isPacked = WoodStorageBlockItem.isPacked(storageItem); + if (woodStorage.isPacked() != isPacked) { + woodStorage.setPacked(isPacked); + } + } + if (renderBlockEntity instanceof BarrelBlockEntity barrel) { + Map materials = BarrelBlockItem.getMaterials(storageItem); + if (!barrel.getMaterials().equals(materials)) { + barrel.setMaterials(materials); + } + barrel.setDynamicRenderTracker(new IDynamicRenderTracker() { + @Override + public boolean isDynamicRenderer() { + return true; + } + + @Override + public boolean isFullyDynamicRenderer() { + return true; + } + + @Override + public void onRenderInfoUpdated(RenderInfo ri) { + //noop + } + }); + } + } + } + + if (renderBlockEntity == null) { + renderBlockEntity = new ChestBlockEntity(BlockPos.ZERO, ModBlocks.CHEST.get().defaultBlockState()); + } + setRenderBlockEntity(renderBlockEntity); + } + return renderBlockEntity; + } + + public void onStorageItemSynced() { + renderBlockEntity = null; + storageWrapper = NoopStorageWrapper.INSTANCE; + } + + public InteractionResult openContainerMenu(Player player, IMovingStorageEntity storageEntity) { + ItemStack storageItem = storageEntity.getStorageItem(); + + player.openMenu(new SophisticatedMenuProvider((w, p, pl) -> { + if (isLimitedBarrel(storageItem)) { + return new MovingLimitedBarrelContainerMenu(w, pl, storageEntity.getId()); + } else { + return new MovingStorageContainerMenu(w, pl, storageEntity.getId()); + } + }, storageItem.getDisplayName(), false), buffer -> buffer.writeInt(storageEntity.getId())); + return player.level().isClientSide ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } + + public static boolean isLimitedBarrel(ItemStack storageItem) { + return storageItem.getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof LimitedBarrelBlock; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/IMovingStorageEntity.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/IMovingStorageEntity.java new file mode 100644 index 0000000..14a45ef --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/IMovingStorageEntity.java @@ -0,0 +1,16 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.entity; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +public interface IMovingStorageEntity { + Vec3 position(); + + int getId(); + + ItemStack getStorageItem(); + + void setStorageItem(ItemStack storageItem); + + EntityStorageHolder getStorageHolder(); +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/MovingStorageWrapper.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/MovingStorageWrapper.java new file mode 100644 index 0000000..67b9736 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/MovingStorageWrapper.java @@ -0,0 +1,436 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.entity; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.p3pp3rf1y.sophisticatedcore.api.IStorageWrapper; +import net.p3pp3rf1y.sophisticatedcore.common.gui.SortBy; +import net.p3pp3rf1y.sophisticatedcore.init.ModCoreDataComponents; +import net.p3pp3rf1y.sophisticatedcore.inventory.*; +import net.p3pp3rf1y.sophisticatedcore.renderdata.RenderInfo; +import net.p3pp3rf1y.sophisticatedcore.settings.SettingsHandler; +import net.p3pp3rf1y.sophisticatedcore.settings.itemdisplay.ItemDisplaySettingsCategory; +import net.p3pp3rf1y.sophisticatedcore.settings.memory.MemorySettingsCategory; +import net.p3pp3rf1y.sophisticatedcore.settings.nosort.NoSortSettingsCategory; +import net.p3pp3rf1y.sophisticatedcore.upgrades.IUpgradeWrapper; +import net.p3pp3rf1y.sophisticatedcore.upgrades.UpgradeHandler; +import net.p3pp3rf1y.sophisticatedcore.upgrades.stack.StackUpgradeItem; +import net.p3pp3rf1y.sophisticatedcore.upgrades.voiding.VoidUpgradeWrapper; +import net.p3pp3rf1y.sophisticatedcore.util.BlockItemBase; +import net.p3pp3rf1y.sophisticatedcore.util.InventorySorter; +import net.p3pp3rf1y.sophisticatedcore.util.NoopStorageWrapper; +import net.p3pp3rf1y.sophisticatedstorage.Config; +import net.p3pp3rf1y.sophisticatedstorage.SophisticatedStorage; +import net.p3pp3rf1y.sophisticatedstorage.block.*; +import net.p3pp3rf1y.sophisticatedstorage.init.ModItems; +import net.p3pp3rf1y.sophisticatedstorage.item.BarrelBlockItem; +import net.p3pp3rf1y.sophisticatedstorage.item.ShulkerBoxItem; +import net.p3pp3rf1y.sophisticatedstorage.item.StorageBlockItem; +import net.p3pp3rf1y.sophisticatedstorage.settings.StorageSettingsHandler; +import net.p3pp3rf1y.sophisticatedstorageinmotion.data.MovingStorageData; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Consumer; + +public class MovingStorageWrapper implements IStorageWrapper { + public static final String SETTINGS_TAG = "settings"; + private final Runnable stackChangeHandler; + private final ItemStack storageStack; + private final Runnable contentsChangeHandler; + + @Nullable + private InventoryHandler inventoryHandler = null; + @Nullable + private InventoryIOHandler inventoryIOHandler = null; + @Nullable + private UpgradeHandler upgradeHandler = null; + + @Nullable + private SettingsHandler settingsHandler; + private final RenderInfo renderInfo; + + private final Map, Consumer> upgradeDefaultsHandlers = new HashMap<>(); + + + private MovingStorageWrapper(ItemStack storageStack, Runnable onContentsChanged, Runnable onStackChanged, Level level) { + this.storageStack = storageStack; + contentsChangeHandler = onContentsChanged; + stackChangeHandler = onStackChanged; + renderInfo = new MovingStorageRenderInfo(storageStack); + MovingStorageData.get(getContentsUuid().orElseGet(this::getNewUuid)); + + if (EntityStorageHolder.isLimitedBarrel(storageStack)) { + registerUpgradeDefaultsHandler(VoidUpgradeWrapper.class, LimitedBarrelBlockEntity.VOID_UPGRADE_VOIDING_OVERFLOW_OF_EVERYTHING_BY_DEFAULT); + } + } + + private static int getNumberOfDisplayItems(ItemStack stack) { + return stack.getItem() instanceof BarrelBlockItem ? 4 : 1; + } + + public static MovingStorageWrapper fromStack(ItemStack stack, Runnable onContentsChanged, Runnable onStackChanged, Level level) { + MovingStorageWrapper movingStorageWrapper = StorageWrapperRepository.getStorageWrapper(stack, MovingStorageWrapper.class, s -> new MovingStorageWrapper(s, onContentsChanged, onStackChanged, level)); + UUID uuid = stack.get(ModCoreDataComponents.STORAGE_UUID); + if (uuid != null) { + movingStorageWrapper.setContentsUuid(uuid); //setting here because client side the uuid isn't in contentsnbt before this data is synced from server and it would create a new one otherwise + } + + return movingStorageWrapper; + } + + private UUID getNewUuid() { + UUID newUuid = UUID.randomUUID(); + setContentsUuid(newUuid); + return newUuid; + } + + @Override + public void setContentsChangeHandler(Runnable contentsChangeHandler) { + //noop + } + + @Override + public int getNumberOfSlotRows() { + int itemInventorySlots = getNumberOfInventorySlots(); + return (int) Math.ceil(itemInventorySlots <= 81 ? (double) itemInventorySlots / 9 : (double) itemInventorySlots / 12); + } + + @Override + public ITrackedContentsItemHandler getInventoryForUpgradeProcessing() { + return getInventoryHandler(); + } + + @Override + public InventoryHandler getInventoryHandler() { + if (inventoryHandler == null) { + initInventoryHandler(); + } + return inventoryHandler; + } + + private void initInventoryHandler() { + inventoryHandler = new InventoryHandler(getNumberOfInventorySlots(), this, getContentsNbt(), contentsChangeHandler, StackUpgradeItem.getInventorySlotLimit(this), Config.SERVER.stackUpgrade) { + @Override + protected boolean isAllowed(ItemStack stack) { + return isAllowedInStorage(stack); + } + }; + inventoryHandler.addListener(getSettingsHandler().getTypeCategory(ItemDisplaySettingsCategory.class)::itemChanged); + inventoryHandler.setShouldInsertIntoEmpty(this::emptyInventorySlotsAcceptItems); + inventoryHandler.onInit(); + } + + private boolean emptyInventorySlotsAcceptItems() { + return !EntityStorageHolder.isLocked(storageStack) || allowsEmptySlotsMatchingItemInsertsWhenLocked(); + } + + private boolean allowsEmptySlotsMatchingItemInsertsWhenLocked() { + return true; //TODO add check for limited barrel and in that case return false + } + + public int getNumberOfInventorySlots() { + Integer numberOfInventorySlots = storageStack.get(ModCoreDataComponents.NUMBER_OF_INVENTORY_SLOTS); + if (numberOfInventorySlots != null) { + return numberOfInventorySlots; + } + numberOfInventorySlots = getDefaultNumberOfInventorySlots(); + storageStack.set(ModCoreDataComponents.NUMBER_OF_INVENTORY_SLOTS, numberOfInventorySlots); + stackChangeHandler.run(); + + return numberOfInventorySlots; + } + + @Override + public ITrackedContentsItemHandler getInventoryForInputOutput() { + if (inventoryIOHandler == null) { + inventoryIOHandler = new InventoryIOHandler(this); + } + return inventoryIOHandler.getFilteredItemHandler(); + } + + @Override + public SettingsHandler getSettingsHandler() { + if (settingsHandler == null) { + if (getContentsUuid().isPresent()) { + CompoundTag contentsNbt = getContentsNbt(); + if (!contentsNbt.contains(SETTINGS_TAG)) { + contentsNbt.put(SETTINGS_TAG, new CompoundTag()); + } + settingsHandler = new StorageSettingsHandler(contentsNbt.getCompound(SETTINGS_TAG), contentsChangeHandler, this::getInventoryHandler, () -> renderInfo) { + @Override + protected int getNumberOfDisplayItems() { + return MovingStorageWrapper.getNumberOfDisplayItems(storageStack); + } + + @Override + protected void saveCategoryNbt(CompoundTag settingsNbt, String categoryName, CompoundTag tag) { + super.saveCategoryNbt(settingsNbt, categoryName, tag); + contentsChangeHandler.run(); + if (categoryName.equals(ItemDisplaySettingsCategory.NAME)) { + stackChangeHandler.run(); + } + } + }; + } else { + settingsHandler = NoopStorageWrapper.INSTANCE.getSettingsHandler(); + } + } + return settingsHandler; + } + + @Override + public UpgradeHandler getUpgradeHandler() { + if (upgradeHandler == null) { + upgradeHandler = new UpgradeHandler(getNumberOfUpgradeSlots(), this, getContentsNbt(), contentsChangeHandler, () -> { + if (inventoryHandler != null) { + inventoryHandler.clearListeners(); + inventoryHandler.setBaseSlotLimit(StackUpgradeItem.getInventorySlotLimit(this)); + } + getInventoryHandler().addListener(getSettingsHandler().getTypeCategory(ItemDisplaySettingsCategory.class)::itemChanged); + inventoryIOHandler = null; + }) { + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return super.isItemValid(slot, stack) && (stack.isEmpty() || SophisticatedStorage.MOD_ID.equals(BuiltInRegistries.ITEM.getKey(stack.getItem()).getNamespace()) || stack.is(ModItems.STORAGE_UPGRADE_TAG)); + } + }; + upgradeDefaultsHandlers.forEach(this::registerUpgradeDefaultsHandlerInUpgradeHandler); + } + return upgradeHandler; + } + + private void registerUpgradeDefaultsHandlerInUpgradeHandler(Class wrapperClass, Consumer defaultsHandler) { + //noinspection DataFlowIssue, unchecked - only called after upgradeHandler is initialized + upgradeHandler.registerUpgradeDefaultsHandler(wrapperClass, (Consumer) defaultsHandler); + } + + public int getNumberOfUpgradeSlots() { + @Nullable Integer numberOfUpgradeSlots = storageStack.get(ModCoreDataComponents.NUMBER_OF_UPGRADE_SLOTS); + if (numberOfUpgradeSlots != null) { + return numberOfUpgradeSlots; + } + numberOfUpgradeSlots = getDefaultNumberOfUpgradeSlots(); + storageStack.set(ModCoreDataComponents.NUMBER_OF_UPGRADE_SLOTS, numberOfUpgradeSlots); + stackChangeHandler.run(); + + return numberOfUpgradeSlots; + } + + @Override + public Optional getContentsUuid() { + return Optional.ofNullable(storageStack.get(ModCoreDataComponents.STORAGE_UUID)); + } + + private CompoundTag getContentsNbt() { + return MovingStorageData.get(getContentsUuid().orElseGet(this::getNewUuid)).getContents(); + } + + @Override + public int getMainColor() { + return StorageBlockItem.getMainColorFromStack(storageStack).orElse(-1); + } + + @Override + public int getAccentColor() { + return StorageBlockItem.getAccentColorFromStack(storageStack).orElse(-1); + } + + @Override + public Optional getOpenTabId() { + return Optional.ofNullable(storageStack.get(ModCoreDataComponents.OPEN_TAB_ID)); + } + + @Override + public void setOpenTabId(int openTabId) { + storageStack.set(ModCoreDataComponents.OPEN_TAB_ID, openTabId); + stackChangeHandler.run(); + } + + @Override + public void removeOpenTabId() { + storageStack.remove(ModCoreDataComponents.OPEN_TAB_ID); + stackChangeHandler.run(); + } + + @Override + public void setColors(int mainColor, int accentColor) { + storageStack.set(ModCoreDataComponents.MAIN_COLOR, mainColor); + storageStack.set(ModCoreDataComponents.ACCENT_COLOR, accentColor); + stackChangeHandler.run(); + } + + @Override + public void setSortBy(SortBy sortBy) { + storageStack.set(ModCoreDataComponents.SORT_BY, sortBy); + stackChangeHandler.run(); + } + + @Override + public SortBy getSortBy() { + return storageStack.getOrDefault(ModCoreDataComponents.SORT_BY, SortBy.NAME); + } + + @Override + public void sort() { + Set slotIndexesExcludedFromSort = new HashSet<>(); + slotIndexesExcludedFromSort.addAll(getSettingsHandler().getTypeCategory(NoSortSettingsCategory.class).getNoSortSlots()); + slotIndexesExcludedFromSort.addAll(getSettingsHandler().getTypeCategory(MemorySettingsCategory.class).getSlotIndexes()); + slotIndexesExcludedFromSort.addAll(getInventoryHandler().getNoSortSlots()); + InventorySorter.sortHandler(getInventoryHandler(), getComparator(), slotIndexesExcludedFromSort); + } + + private Comparator> getComparator() { + return switch (getSortBy()) { + case COUNT -> InventorySorter.BY_COUNT; + case TAGS -> InventorySorter.BY_TAGS; + case NAME -> InventorySorter.BY_NAME; + case MOD -> InventorySorter.BY_MOD; + }; + } + + @Override + public void onContentsNbtUpdated() { + inventoryHandler = null; + upgradeHandler = null; + refreshInventoryForUpgradeProcessing(); + } + + @Override + public void refreshInventoryForUpgradeProcessing() { + refreshInventoryForInputOutput(); + } + + @Override + public void refreshInventoryForInputOutput() { + inventoryIOHandler = null; + } + + @Override + public void setPersistent(boolean persistent) { + //noop + } + + @Override + public void fillWithLoot(Player playerEntity) { + //noop + } + + @Override + public RenderInfo getRenderInfo() { + return renderInfo; + } + + @Override + public void setColumnsTaken(int columnsTaken, boolean hasChanged) { + //noop - would require a change if there ever was support for this in storage which is not a plan + } + + @Override + public int getColumnsTaken() { + return 0; + } + + public void setContentsUuid(UUID contentsUuid) { + storageStack.set(ModCoreDataComponents.STORAGE_UUID, contentsUuid); + onContentsNbtUpdated(); + } + + public int getDefaultNumberOfInventorySlots() { + return storageStack.getItem() instanceof BlockItemBase blockItem && blockItem.getBlock() instanceof IStorageBlock storageBlock ? storageBlock.getNumberOfInventorySlots() : 0; + } + + private int getDefaultNumberOfUpgradeSlots() { + return storageStack.getItem() instanceof BlockItemBase blockItem && blockItem.getBlock() instanceof IStorageBlock storageBlock ? storageBlock.getNumberOfUpgradeSlots() : 0; + } + + private boolean isAllowedInStorage(ItemStack stack) { + if (!(storageStack.getItem() instanceof ShulkerBoxItem)) { + return true; + } + + Block block = Block.byItem(stack.getItem()); + return !(block instanceof ShulkerBoxBlock) && !(block instanceof net.minecraft.world.level.block.ShulkerBoxBlock) && !Config.SERVER.shulkerBoxDisallowedItems.isItemDisallowed(stack.getItem()); + } + + @Override + public String getStorageType() { + Item storageItem = storageStack.getItem(); + if (!(storageItem instanceof BlockItem blockItem)) { + return "undefined"; + } + + if (blockItem.getBlock() instanceof ChestBlock) { + return ChestBlockEntity.STORAGE_TYPE; + } else if (blockItem.getBlock() instanceof ShulkerBoxBlock) { + return ShulkerBoxBlockEntity.STORAGE_TYPE; + } else if (blockItem.getBlock() instanceof BarrelBlock) { + return BarrelBlockEntity.STORAGE_TYPE; + } else if (blockItem.getBlock() instanceof LimitedBarrelBlock) { + return LimitedBarrelBlockEntity.STORAGE_TYPE; + } + + return "undefined"; + } + + @Override + public Component getDisplayName() { + return storageStack.getDisplayName(); + } + + public void changeSize(int additionalInventorySlots, int additionalUpgradeSlots) { + setNumberOfInventorySlots(getNumberOfInventorySlots() + additionalInventorySlots); + getInventoryHandler().changeSlots(additionalInventorySlots); + + setNumberOfUpgradeSlots(getNumberOfUpgradeSlots() + additionalUpgradeSlots); + getUpgradeHandler().increaseSize(additionalUpgradeSlots); + } + + public void setNumberOfInventorySlots(int numberOfInventorySlots) { + storageStack.set(ModCoreDataComponents.NUMBER_OF_INVENTORY_SLOTS, numberOfInventorySlots); + stackChangeHandler.run(); + } + + public void setNumberOfUpgradeSlots(int numberOfUpgradeSlots) { + storageStack.set(ModCoreDataComponents.NUMBER_OF_UPGRADE_SLOTS, numberOfUpgradeSlots); + stackChangeHandler.run(); + } + + //TODO need this to be called for limited barrels when initialized - probably check for item in fromStack method here? + public void registerUpgradeDefaultsHandler(Class upgradeClass, Consumer defaultsHandler) { + upgradeDefaultsHandlers.put(upgradeClass, defaultsHandler); + } + + @Override + public ItemStack getWrappedStorageStack() { + return storageStack; + } + + @Override + public int getBaseStackSizeMultiplier() { + return storageStack.getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof IStorageBlock storageBlock ? storageBlock.getBaseStackSizeMultiplier() : 1; + } + + private class MovingStorageRenderInfo extends RenderInfo { + public MovingStorageRenderInfo(ItemStack storageStack) { + super(() -> MovingStorageWrapper.this.stackChangeHandler, EntityStorageHolder.isLimitedBarrel(storageStack)); + deserialize(); + } + + @Override + protected void serializeRenderInfo(CompoundTag renderInfo) { + MovingStorageWrapper.this.storageStack.set(ModCoreDataComponents.RENDER_INFO_TAG, CustomData.of(renderInfo)); + } + + @Override + protected Optional getRenderInfoTag() { + return Optional.ofNullable(MovingStorageWrapper.this.storageStack.get(ModCoreDataComponents.RENDER_INFO_TAG.get())).map(CustomData::copyTag); } + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/StorageMinecart.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/StorageMinecart.java new file mode 100644 index 0000000..3e3fd03 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/StorageMinecart.java @@ -0,0 +1,131 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.entity; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.vehicle.MinecartChest; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.Level; +import net.p3pp3rf1y.sophisticatedcore.util.SimpleItemContent; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModDataComponents; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModEntities; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModItems; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class StorageMinecart extends MinecartChest implements IMovingStorageEntity { + private static final EntityDataAccessor> DATA_CUSTOM_NAME = SynchedEntityData.defineId(StorageMinecart.class, EntityDataSerializers.OPTIONAL_COMPONENT); + static final EntityDataAccessor DATA_STORAGE_ITEM = SynchedEntityData.defineId(StorageMinecart.class, EntityDataSerializers.ITEM_STACK); + + private final EntityStorageHolder entityStorageHolder; + + public StorageMinecart(EntityType entityType, Level level) { + super(entityType, level); + entityStorageHolder = new EntityStorageHolder<>(this); + } + + private StorageMinecart(Level level) { + this(ModEntities.STORAGE_MINECART.get(), level); + } + + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(DATA_STORAGE_ITEM, ItemStack.EMPTY); + builder.define(DATA_CUSTOM_NAME, Optional.empty()); + } + + @Override + public ItemStack getStorageItem() { + return this.entityData.get(DATA_STORAGE_ITEM); + } + + @Override + public void setStorageItem(ItemStack storageItem) { + this.entityData.set(DATA_STORAGE_ITEM, storageItem.copy()); + } + + @Override + public EntityStorageHolder getStorageHolder() { + return entityStorageHolder; + } + + public StorageMinecart(Level level, double x, double y, double z) { + this(level); + this.setPos(x, y, z); + this.xo = x; + this.yo = y; + this.zo = z; + } + + @Override + public void destroy(DamageSource source) { + this.kill(); + if (level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { + ItemStack drop = new ItemStack(ModItems.STORAGE_MINECART.get()); + drop.set(ModDataComponents.STORAGE_ITEM, SimpleItemContent.copyOf(getStorageItem())); + drop.set(DataComponents.CUSTOM_NAME, getCustomName()); + spawnAtLocation(drop); + entityStorageHolder.dropAllItems(); + } + } + + + @Override + protected void addAdditionalSaveData(CompoundTag tag) { + super.addAdditionalSaveData(tag); + tag.put("storageHolder", entityStorageHolder.saveData(level().registryAccess())); + } + + + @Override + protected void readAdditionalSaveData(CompoundTag tag) { + super.readAdditionalSaveData(tag); + entityStorageHolder.readData(level().registryAccess(), tag.getCompound("storageHolder")); + } + + @Override + public void tick() { + super.tick(); + entityStorageHolder.tick(); + } + + @Override + public void onSyncedDataUpdated(EntityDataAccessor key) { + super.onSyncedDataUpdated(key); + if (key == DATA_STORAGE_ITEM && level().isClientSide()) { + entityStorageHolder.onStorageItemSynced(); + } + } + + @Override + public void setCustomName(@Nullable Component customName) { + entityData.set(DATA_CUSTOM_NAME, Optional.ofNullable(customName)); + } + + @Override + public Component getCustomName() { + return entityData.get(DATA_CUSTOM_NAME).orElseGet(() -> getStorageItem().getHoverName()); + } + + @Override + public InteractionResult interact(Player player, InteractionHand hand) { + return getStorageHolder().openContainerMenu(player, this); + } + + @Override + public InteractionResult interactWithContainerVehicle(Player player) { + return super.interactWithContainerVehicle(player); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/package-info.java new file mode 100644 index 0000000..6977eca --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/entity/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.entity; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModDataComponents.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModDataComponents.java new file mode 100644 index 0000000..2f7cdc4 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModDataComponents.java @@ -0,0 +1,35 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.init; + +import com.mojang.serialization.Codec; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.codec.ByteBufCodecs; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.p3pp3rf1y.sophisticatedcore.util.SimpleItemContent; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; + +import java.util.function.Supplier; + +public class ModDataComponents { + private ModDataComponents() { + } + + private static final DeferredRegister> DATA_COMPONENT_TYPES = DeferredRegister.create(BuiltInRegistries.DATA_COMPONENT_TYPE, SophisticatedStorageInMotion.MOD_ID); + + public static final Supplier> STORAGE_ITEM = DATA_COMPONENT_TYPES.register("storage_item", + () -> new DataComponentType.Builder().persistent(SimpleItemContent.CODEC).networkSynchronized(SimpleItemContent.STREAM_CODEC).build()); + + public static final Supplier> LOCKED = DATA_COMPONENT_TYPES.register("locked", + () -> new DataComponentType.Builder().persistent(Codec.BOOL).networkSynchronized(ByteBufCodecs.BOOL).build()); + + public static final Supplier> LOCK_VISIBLE = DATA_COMPONENT_TYPES.register("lock_visible", + () -> new DataComponentType.Builder().persistent(Codec.BOOL).networkSynchronized(ByteBufCodecs.BOOL).build()); + + public static final Supplier> UPGRADES_VISIBLE = DATA_COMPONENT_TYPES.register("upgrades_visible", + () -> new DataComponentType.Builder().persistent(Codec.BOOL).networkSynchronized(ByteBufCodecs.BOOL).build()); + + public static void register(IEventBus modBus) { + DATA_COMPONENT_TYPES.register(modBus); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModEntities.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModEntities.java new file mode 100644 index 0000000..9c890e2 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModEntities.java @@ -0,0 +1,45 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.init; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.inventory.MenuType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.common.extensions.IMenuTypeExtension; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingLimitedBarrelContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingLimitedBarrelSettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.common.gui.MovingStorageSettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.StorageMinecart; + +import java.util.function.Supplier; + +public class ModEntities { + private ModEntities() { + } + + private static final DeferredRegister> MENU_TYPES = DeferredRegister.create(BuiltInRegistries.MENU, SophisticatedStorageInMotion.MOD_ID); + + public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create(BuiltInRegistries.ENTITY_TYPE, SophisticatedStorageInMotion.MOD_ID); + + public static final Supplier> STORAGE_MINECART = ENTITY_TYPES.register("storage_minecart", () -> EntityType.Builder.of((EntityType.EntityFactory) StorageMinecart::new, MobCategory.MISC).sized(0.98F, 0.7F).clientTrackingRange(8).passengerAttachments(0.1875F).build(SophisticatedStorageInMotion.MOD_ID + ":storage_minecart")); + + public static final Supplier> MOVING_STORAGE_CONTAINER_TYPE = MENU_TYPES.register("moving_storage", + () -> IMenuTypeExtension.create(MovingStorageContainerMenu::fromBuffer)); + + public static final Supplier> MOVING_STORAGE_SETTINGS_CONTAINER_TYPE = MENU_TYPES.register("moving_storage_settings", + () -> IMenuTypeExtension.create(MovingStorageSettingsContainerMenu::fromBuffer)); + + public static final Supplier> MOVING_LIMITED_BARREL_CONTAINER_TYPE = MENU_TYPES.register("moving_limited_barrel", + () -> IMenuTypeExtension.create(MovingLimitedBarrelContainerMenu::fromBuffer)); + + public static final Supplier> MOVING_LIMITED_BARREL_SETTINGS_CONTAINER_TYPE = MENU_TYPES.register("moving_limited_barrel_settings", + () -> IMenuTypeExtension.create(MovingLimitedBarrelSettingsContainerMenu::fromBuffer)); + + public static void registerHandlers(IEventBus modBus) { + ENTITY_TYPES.register(modBus); + MENU_TYPES.register(modBus); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModEntitiesClient.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModEntitiesClient.java new file mode 100644 index 0000000..cd3b85b --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModEntitiesClient.java @@ -0,0 +1,28 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.init; + +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent; +import net.p3pp3rf1y.sophisticatedstorageinmotion.client.StorageMinecartRenderer; +import net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui.MovingLimitedBarrelScreen; +import net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui.MovingLimitedBarrelSettingsScreen; +import net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui.MovingStorageScreen; +import net.p3pp3rf1y.sophisticatedstorageinmotion.client.gui.MovingStorageSettingsScreen; + +public class ModEntitiesClient { + public static void registerHandlers(IEventBus modBus) { + modBus.addListener(ModEntitiesClient::registerEntityRenderers); + modBus.addListener(ModEntitiesClient::onMenuScreenRegister); + } + + private static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) { + event.registerEntityRenderer(ModEntities.STORAGE_MINECART.get(), StorageMinecartRenderer::new); + } + + private static void onMenuScreenRegister(RegisterMenuScreensEvent event) { + event.register(ModEntities.MOVING_STORAGE_CONTAINER_TYPE.get(), MovingStorageScreen::constructScreen); + event.register(ModEntities.MOVING_STORAGE_SETTINGS_CONTAINER_TYPE.get(), MovingStorageSettingsScreen::constructScreen); + event.register(ModEntities.MOVING_LIMITED_BARREL_CONTAINER_TYPE.get(), MovingLimitedBarrelScreen::new); + event.register(ModEntities.MOVING_LIMITED_BARREL_SETTINGS_CONTAINER_TYPE.get(), MovingLimitedBarrelSettingsScreen::new); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModItems.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModItems.java new file mode 100644 index 0000000..8dc7628 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModItems.java @@ -0,0 +1,43 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.init; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.attachment.AttachmentType; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import net.p3pp3rf1y.sophisticatedcore.util.ItemBase; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; +import net.p3pp3rf1y.sophisticatedstorageinmotion.item.StorageMinecartItem; + +import java.util.function.Supplier; + +public class ModItems { + private ModItems() { + } + + public static final DeferredRegister ITEMS = DeferredRegister.create(BuiltInRegistries.ITEM, SophisticatedStorageInMotion.MOD_ID); + public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB.location(), SophisticatedStorageInMotion.MOD_ID); + + public static final Supplier STORAGE_MINECART = ITEMS.register("storage_minecart", StorageMinecartItem::new); + + private static final DeferredRegister> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.Keys.ATTACHMENT_TYPES, SophisticatedStorageInMotion.MOD_ID); + + public static Supplier CREATIVE_TAB = CREATIVE_MODE_TABS.register("main", () -> + CreativeModeTab.builder().icon(() -> new ItemStack(STORAGE_MINECART.get())) + .title(Component.translatable("itemGroup.sophisticatedstorageinmotion")) + .displayItems((featureFlags, output) -> { + ITEMS.getEntries().stream().filter(i -> i.get() instanceof ItemBase).forEach(i -> ((ItemBase) i.get()).addCreativeTabItems(output::accept)); + }) + .build()); + + public static void registerHandlers(IEventBus modBus) { + ITEMS.register(modBus); + CREATIVE_MODE_TABS.register(modBus); + ATTACHMENT_TYPES.register(modBus); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModPayloads.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModPayloads.java new file mode 100644 index 0000000..f22eb35 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/ModPayloads.java @@ -0,0 +1,18 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.init; + +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; +import net.p3pp3rf1y.sophisticatedstorageinmotion.network.MovingStorageContentsPayload; +import net.p3pp3rf1y.sophisticatedstorageinmotion.network.OpenMovingStorageInventoryPayload; + +public class ModPayloads { + private ModPayloads() { + } + + public static void registerPayloads(final RegisterPayloadHandlersEvent event) { + final PayloadRegistrar registrar = event.registrar(SophisticatedStorageInMotion.MOD_ID).versioned("1.0"); + registrar.playToServer(OpenMovingStorageInventoryPayload.TYPE, OpenMovingStorageInventoryPayload.STREAM_CODEC, OpenMovingStorageInventoryPayload::handlePayload); + registrar.playToClient(MovingStorageContentsPayload.TYPE, MovingStorageContentsPayload.STREAM_CODEC, MovingStorageContentsPayload::handlePayload); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/package-info.java new file mode 100644 index 0000000..7ab50e5 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/init/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.init; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/item/StorageMinecartItem.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/item/StorageMinecartItem.java new file mode 100644 index 0000000..3691724 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/item/StorageMinecartItem.java @@ -0,0 +1,86 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.item; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseRailBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.RailShape; +import net.minecraft.world.level.block.state.properties.WoodType; +import net.minecraft.world.level.gameevent.GameEvent; +import net.p3pp3rf1y.sophisticatedcore.Config; +import net.p3pp3rf1y.sophisticatedcore.util.ItemBase; +import net.p3pp3rf1y.sophisticatedcore.util.SimpleItemContent; +import net.p3pp3rf1y.sophisticatedstorage.block.ITintableBlockItem; +import net.p3pp3rf1y.sophisticatedstorage.init.ModBlocks; +import net.p3pp3rf1y.sophisticatedstorage.item.WoodStorageBlockItem; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.StorageMinecart; +import net.p3pp3rf1y.sophisticatedstorageinmotion.init.ModDataComponents; + +import java.util.function.Consumer; + +public class StorageMinecartItem extends ItemBase { + public StorageMinecartItem() { + super(new Properties().stacksTo(1)); + } + + @Override + public void addCreativeTabItems(Consumer itemConsumer) { + if (Config.COMMON.enabledItems.isItemEnabled(this)) { + itemConsumer.accept(createWithStorage(WoodStorageBlockItem.setWoodType(new ItemStack(ModBlocks.BARREL_ITEM.get()), WoodType.SPRUCE))); + ItemStack limitedIStack = new ItemStack(ModBlocks.LIMITED_GOLD_BARREL_1_ITEM.get()); + if (limitedIStack.getItem() instanceof ITintableBlockItem tintableBlockItem) { + tintableBlockItem.setAccentColor(limitedIStack, 0xFF_EEEEEE); + tintableBlockItem.setMainColor(limitedIStack, 0xFF_222222); + } + itemConsumer.accept(createWithStorage(limitedIStack)); + itemConsumer.accept(createWithStorage(WoodStorageBlockItem.setWoodType(new ItemStack(ModBlocks.LIMITED_COPPER_BARREL_2.get()), WoodType.BIRCH))); + itemConsumer.accept(createWithStorage(WoodStorageBlockItem.setWoodType(new ItemStack(ModBlocks.LIMITED_IRON_BARREL_3.get()), WoodType.ACACIA))); + itemConsumer.accept(createWithStorage(WoodStorageBlockItem.setWoodType(new ItemStack(ModBlocks.LIMITED_DIAMOND_BARREL_4.get()), WoodType.CRIMSON))); + itemConsumer.accept(createWithStorage(WoodStorageBlockItem.setWoodType(new ItemStack(ModBlocks.NETHERITE_CHEST_ITEM.get()), WoodType.BAMBOO))); + itemConsumer.accept(createWithStorage(new ItemStack(ModBlocks.IRON_SHULKER_BOX_ITEM.get()))); + } + } + + + private ItemStack createWithStorage(ItemStack storageStack) { + ItemStack stack = new ItemStack(this); + stack.set(ModDataComponents.STORAGE_ITEM, SimpleItemContent.copyOf(storageStack)); + return stack; + } + + @Override + public InteractionResult useOn(UseOnContext context) { + Level level = context.getLevel(); + BlockPos blockpos = context.getClickedPos(); + BlockState blockstate = level.getBlockState(blockpos); + if (!blockstate.is(BlockTags.RAILS)) { + return InteractionResult.FAIL; + } else { + ItemStack stack = context.getItemInHand(); + if (level instanceof ServerLevel serverlevel) { + RailShape railshape = blockstate.getBlock() instanceof BaseRailBlock baseRailBlock ? baseRailBlock.getRailDirection(blockstate, level, blockpos, null) : RailShape.NORTH_SOUTH; + double ascendingOffset = 0.0; + if (railshape.isAscending()) { + ascendingOffset = 0.5; + } + + StorageMinecart minecart = new StorageMinecart(level, blockpos.getX() + 0.5, blockpos.getY() + 0.0625 + ascendingOffset, blockpos.getZ() + 0.5); + minecart.getStorageHolder().setStorageItemFrom(stack); + EntityType.createDefaultStackConfig(serverlevel, stack, context.getPlayer()).accept(minecart); + + serverlevel.addFreshEntity(minecart); + serverlevel.gameEvent(GameEvent.ENTITY_PLACE, blockpos, GameEvent.Context.of(context.getPlayer(), serverlevel.getBlockState(blockpos.below()))); + } + + stack.shrink(1); + return InteractionResult.sidedSuccess(level.isClientSide); + } + } + +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/item/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/item/package-info.java new file mode 100644 index 0000000..2b36021 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/item/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.item; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/MovingStorageContentsPayload.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/MovingStorageContentsPayload.java new file mode 100644 index 0000000..b1a2e25 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/MovingStorageContentsPayload.java @@ -0,0 +1,32 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.network; + +import io.netty.buffer.ByteBuf; +import net.minecraft.core.UUIDUtil; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; +import net.p3pp3rf1y.sophisticatedstorageinmotion.data.MovingStorageData; + +import java.util.UUID; + +public record MovingStorageContentsPayload(UUID storageUuid, CompoundTag contents) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(SophisticatedStorageInMotion.getRL("storage_contents")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, + MovingStorageContentsPayload::storageUuid, + ByteBufCodecs.COMPOUND_TAG, + MovingStorageContentsPayload::contents, + MovingStorageContentsPayload::new); + + @Override + public Type type() { + return TYPE; + } + + public static void handlePayload(MovingStorageContentsPayload payload, IPayloadContext context) { + MovingStorageData.get(payload.storageUuid).setContents(payload.storageUuid, payload.contents); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/OpenMovingStorageInventoryPayload.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/OpenMovingStorageInventoryPayload.java new file mode 100644 index 0000000..04d5efc --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/OpenMovingStorageInventoryPayload.java @@ -0,0 +1,30 @@ +package net.p3pp3rf1y.sophisticatedstorageinmotion.network; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.entity.player.Player; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.p3pp3rf1y.sophisticatedstorageinmotion.SophisticatedStorageInMotion; +import net.p3pp3rf1y.sophisticatedstorageinmotion.entity.IMovingStorageEntity; + +public record OpenMovingStorageInventoryPayload(int entityId) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(SophisticatedStorageInMotion.getRL("open_storage_inventory")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, + OpenMovingStorageInventoryPayload::entityId, + OpenMovingStorageInventoryPayload::new); + + @Override + public Type type() { + return TYPE; + } + + public static void handlePayload(OpenMovingStorageInventoryPayload payload, IPayloadContext context) { + Player player = context.player(); + if (player.level().getEntity(payload.entityId()) instanceof IMovingStorageEntity storageEntity) { + storageEntity.getStorageHolder().openContainerMenu(player, storageEntity); + } + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/package-info.java new file mode 100644 index 0000000..735f7e2 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/network/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion.network; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/package-info.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/package-info.java new file mode 100644 index 0000000..c6232d4 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorageinmotion/package-info.java @@ -0,0 +1,8 @@ +// Auto generated package-info by MCP + +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package net.p3pp3rf1y.sophisticatedstorageinmotion; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/assets/sophisticatedstorageinmotion/lang/en_us.json b/src/main/resources/assets/sophisticatedstorageinmotion/lang/en_us.json new file mode 100644 index 0000000..46e4eb6 --- /dev/null +++ b/src/main/resources/assets/sophisticatedstorageinmotion/lang/en_us.json @@ -0,0 +1,5 @@ +{ + "itemGroup.sophisticatedstorageinmotion": "Sophisticated Storage In Motion", + "item.sophisticatedstorageinmotion.storage_minecart": "Storage Minecart", + "entity.sophisticatedstorageinmotion.storage_minecart": "Storage Minecart" +} \ No newline at end of file diff --git a/src/main/resources/assets/sophisticatedstorageinmotion/models/item/storage_minecart.json b/src/main/resources/assets/sophisticatedstorageinmotion/models/item/storage_minecart.json new file mode 100644 index 0000000..e3dda70 --- /dev/null +++ b/src/main/resources/assets/sophisticatedstorageinmotion/models/item/storage_minecart.json @@ -0,0 +1,35 @@ +{ + "parent": "builtin/entity", + "display": { + "gui": { + "rotation": [ 30, 45, 0 ], + "translation": [ 0, 0, 0], + "scale":[ 0.625, 0.625, 0.625 ] + }, + "ground": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 3, 0], + "scale":[ 0.25, 0.25, 0.25 ] + }, + "head": { + "rotation": [ 0, 180, 0 ], + "translation": [ 0, 0, 0], + "scale":[ 1, 1, 1] + }, + "fixed": { + "rotation": [ 0, 180, 0 ], + "translation": [ 0, 0, 0], + "scale":[ 0.5, 0.5, 0.5 ] + }, + "thirdperson_righthand": { + "rotation": [ 75, 315, 0 ], + "translation": [ 0, 2.5, 0], + "scale": [ 0.375, 0.375, 0.375 ] + }, + "firstperson_righthand": { + "rotation": [ 0, 315, 0 ], + "translation": [ 0, 0, 0], + "scale": [ 0.4, 0.4, 0.4 ] + } + } +} \ No newline at end of file diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..117bd7a --- /dev/null +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -0,0 +1,46 @@ +modLoader="javafml" #mandatory +loaderVersion="${loader_version_range}" #mandatory + +license="${mod_license}" +issueTrackerURL="${mod_issue_tracker_url}" + +[[mods]] +modId="${mod_id}" +version="${mod_version}" +displayName="${mod_name}" +displayURL="${mod_display_url}" +logoFile="${mod_logo_file}" +credits="${mod_credits}" +authors="${mod_authors}" +description='''${mod_description}''' + +[[accessTransformers]] +file="META-INF/accesstransformer.cfg" + +[[dependencies.${mod_id}]] +modId="sophisticatedstorage" +type="required" +versionRange="${ss_version}" +ordering="NONE" +side="BOTH" + +[[dependencies.${mod_id}]] +modId="jei" +type="optional" +versionRange="${jei_version_range}" +ordering="NONE" +side="CLIENT" + +[[dependencies.${mod_id}]] +modId="neoforge" +type="required" +versionRange="${neo_version_range}" +ordering="NONE" +side="BOTH" + +[[dependencies.${mod_id}]] +modId="minecraft" +type="required" +versionRange="${minecraft_version_range}" +ordering="NONE" +side="BOTH"