├── .editorconfig ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── config.yml │ └── issue.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs ├── GrandEconomy-1.12.2-2.0.0-api.jar └── Kiwi-1.12.2-0.5.3.32-deobf.jar ├── run └── scripts │ ├── grandeconomy.zs │ ├── itemstages.zs │ ├── layout-test.zs │ ├── reskillable.zs │ └── test.zs └── src └── main ├── java └── snownee │ └── researchtable │ ├── ModConfig.java │ ├── ResearchTable.java │ ├── ResearchTableModule.java │ ├── block │ ├── BlockTable.java │ └── TileTable.java │ ├── client │ ├── gui │ │ ├── ComponentButtonList.java │ │ ├── ComponentResearchDetail.java │ │ ├── ComponentResearchList.java │ │ ├── ComponentResearchProgress.java │ │ ├── GuiButtonStack.java │ │ ├── GuiControlSpecial.java │ │ └── GuiTable.java │ └── renderer │ │ ├── ConditionRenderer.java │ │ └── EventShowItemCondition.java │ ├── command │ └── CommandResearch.java │ ├── container │ └── ContainerTable.java │ ├── core │ ├── ConditionTypes.java │ ├── CriterionResearchCount.java │ ├── CriterionResearches.java │ ├── CriterionScore.java │ ├── DataStorage.java │ ├── EventOpenTable.java │ ├── ICondition.java │ ├── ICriterion.java │ ├── IReward.java │ ├── Research.java │ ├── ResearchCategory.java │ ├── ResearchList.java │ ├── RewardExecute.java │ ├── RewardItems.java │ └── team │ │ ├── TeamHelper.java │ │ └── TeamProvider.java │ ├── network │ ├── GuiHandler.java │ ├── NetworkChannel.java │ ├── PacketResearchChanged.java │ └── PacketSyncClient.java │ └── plugin │ ├── crafttweaker │ ├── ConditionCrTItem.java │ ├── ConditionCrTLiquid.java │ ├── CrTPlugin.java │ ├── RendererCrTItem.java │ ├── RendererCrTLiquid.java │ ├── ResearchBuilder.java │ └── ResearchCategoryWrapper.java │ ├── forge │ ├── ConditionForgeEnergy.java │ └── RendererForgeEnergy.java │ ├── gamestages │ ├── CrTGameStagesExpansion.java │ ├── CriterionStages.java │ └── RewardUnlockStages.java │ ├── grandeconomy │ ├── CrTGrandEconomyExpansion.java │ ├── CriterionMoneyGE.java │ ├── GrandEconomyPlugin.java │ └── RewardMoneyGE.java │ ├── hwyla │ ├── HWYLAPlugin.java │ └── TableInfoProvider.java │ ├── itemstages │ └── ItemStagesPlugin.java │ ├── jei │ └── JeiPlugin.java │ ├── reskillable │ ├── CrTReskillableExpansion.java │ ├── CriterionSkill.java │ ├── Helper.java │ ├── RewardSetSkillLevel.java │ └── RewardSkillLevelUp.java │ ├── togetherforever │ └── TeamProviderTF.java │ └── top │ ├── TOPPlugin.java │ └── TableInfoProvider.java └── resources ├── META-INF └── research_at.cfg ├── assets └── researchtable │ ├── blockstates │ └── table.json │ ├── lang │ ├── en_us.lang │ ├── pt_br.lang │ ├── ru_ru.lang │ └── zh_cn.lang │ ├── models │ └── block │ │ └── table.json │ ├── recipes │ └── reset.json │ └── textures │ ├── block │ ├── 0.png │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── screen.png │ └── screen.png.mcmeta │ └── gui │ ├── energy.png │ └── globe.png ├── mcmod.info └── pack.mcmeta /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | continuation_indent_size = 8 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.json] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [*.java] 18 | indent_style = tab 19 | ij_java_class_count_to_use_import_on_demand = 99 20 | ij_java_names_count_to_use_import_on_demand = 99 21 | ij_java_imports_layout = $*,|,java.**,|,javax.**,|,org.**,|,com.**,|,* -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.yml: -------------------------------------------------------------------------------- 1 | name: New Issue 2 | description: Do not write different problems/ideas in one issue. Separate them 3 | body: 4 | - type: dropdown 5 | id: modloader 6 | attributes: 7 | label: Mod loader 8 | options: 9 | - Forge 10 | - Fabric 11 | validations: 12 | required: true 13 | - type: input 14 | id: mc-version 15 | attributes: 16 | label: Minecraft version 17 | placeholder: eg. 1.17.1 18 | validations: 19 | required: true 20 | - type: input 21 | id: mod-version 22 | attributes: 23 | label: Mod version 24 | placeholder: eg. 1.0.0 25 | validations: 26 | required: true 27 | - type: input 28 | id: modloader-version 29 | attributes: 30 | label: Modloader version 31 | description: | 32 | List the version of the mod loader you are using. 33 | If on Fabric, post the versions of both Fabric Loader and Fabric API. 34 | placeholder: "eg. Forge: 36.2.9 / Fabric: Loader 0.10.6 + API 0.42.1" 35 | validations: 36 | required: true 37 | - type: input 38 | id: modpack 39 | attributes: 40 | label: Modpack info 41 | description: | 42 | If playing a modpack, post the link to it! 43 | - type: checkboxes 44 | id: reproducible 45 | attributes: 46 | label: "If bug:" 47 | options: 48 | - label: "Can you reproduce this issue with relevant mods only?" 49 | - type: input 50 | attributes: 51 | label: "If bug: The latest.log file" 52 | description: "Please use a paste site such as [gist](https://gist.github.com/) / [pastebin](https://pastebin.com/) / etc." 53 | - type: textarea 54 | attributes: 55 | label: Issue description 56 | placeholder: A description of the issue. 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | classes 12 | *.ipr 13 | *.iws 14 | *.iml 15 | .idea 16 | 17 | # gradle 18 | build 19 | .gradle 20 | 21 | # other 22 | eclipse 23 | run/* 24 | !run/scripts 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT - DO NOT BOTHER ME LICENSE 2 | 3 | Copyright (C) 2018 Snownee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | 1. The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 2. Permission is revoked for those who contact the original license holder in 15 | order to request any rights declared above, until it is explicitly stated 16 | to be recovered. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | Don't bother me. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ResearchTable 2 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | maven { 5 | name = "forge" 6 | url = "http://files.minecraftforge.net/maven" 7 | } 8 | } 9 | dependencies { 10 | classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' 11 | } 12 | } 13 | 14 | apply plugin: 'idea' 15 | apply plugin: 'net.minecraftforge.gradle.forge' 16 | 17 | version = "${version_major}.${version_minor}.${version_patch}" 18 | group = "snownee.research" 19 | archivesBaseName = "ResearchTable" 20 | 21 | if (System.getenv().BUILD_NUMBER != null) { 22 | version += "-build${System.getenv().BUILD_NUMBER}" 23 | } 24 | 25 | sourceCompatibility = targetCompatibility = '1.8' 26 | 27 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' 28 | 29 | repositories { 30 | maven { 31 | name = "jei" 32 | url = "https://dvs1.progwml6.com/files/maven" 33 | } 34 | maven { 35 | name = 'tterrag maven' 36 | url = "https://maven.tterrag.com/" 37 | } 38 | maven { 39 | name = 'stages' 40 | url = 'https://mmdmaven.blamejared.com/' 41 | //url = 'https://maven.mcmoddev.com' 42 | } 43 | maven { 44 | name = "jared" 45 | url = "https://maven.blamejared.com" 46 | } 47 | maven { 48 | name = "tehnut" 49 | url = "https://maven.tehnut.info" 50 | } 51 | maven { 52 | url = "https://www.cursemaven.com" 53 | } 54 | 55 | flatDir { 56 | dirs 'libs' 57 | } 58 | } 59 | 60 | minecraft { 61 | version = "${minecraft_version}-${forge_version}" 62 | runDir = "run" 63 | 64 | mappings = "${mapping_version}" 65 | useDepAts = true 66 | 67 | replace "@VERSION_INJECT@", project.version 68 | } 69 | 70 | dependencies { 71 | // Why not deobfCompile? Since JEI 4.13.1, JEI uses stable_39 mapping, so we are on the same MCP version now. 72 | compile "mezz.jei:jei_${minecraft_version}:${jei_version}" 73 | 74 | deobfCompile "CraftTweaker2:CraftTweaker2-MC1120-Main:1.12-${ct_version}" 75 | deobfCompile "CraftTweaker2:CraftTweaker2-API:${ct_version}" 76 | deobfCompile "CraftTweaker2:ZenScript:${ct_version}" 77 | compile "net.darkhax.bookshelf:Bookshelf-1.12.2:${bookshelf_version}" 78 | compile "net.darkhax.gamestages:GameStages-1.12.2:${gamestages_version}" 79 | compile "net.darkhax.itemstages:ItemStages-1.12.2:${itemstages_version}" 80 | deobfCompile "curse.maven:hwyla-253449:2568751" 81 | deobfCompile "codersafterdark.reskillable:Reskillable:1.12.2-1.12.5-PR-156.1" 82 | deobfCompile("curse.maven:the-one-probe-245211:2667280") { 83 | exclude group: 'cofh' 84 | } 85 | deobfCompile "curse.maven:together-forever-285968:2700901" 86 | compile files( 87 | 'libs/Kiwi-1.12.2-0.5.3.32-deobf.jar', 88 | 'libs/GrandEconomy-1.12.2-2.0.0-api.jar' 89 | ) 90 | //deobfCompile "curse.maven:grand-economy-312141:3139910" 91 | } 92 | 93 | processResources { 94 | inputs.property "version", project.version 95 | inputs.property "mcversion", project.minecraft.version 96 | 97 | from(sourceSets.main.resources.srcDirs) { 98 | include 'mcmod.info' 99 | expand 'version':project.version, 'mcversion':project.minecraft.version 100 | } 101 | 102 | from(sourceSets.main.resources.srcDirs) { 103 | exclude 'mcmod.info' 104 | } 105 | } 106 | 107 | jar { 108 | exclude "**/*.bat" 109 | exclude "**/*.psd" 110 | exclude "**/*.d" 111 | exclude "**/*.exe" 112 | exclude "**/*.e" 113 | exclude "**/*.txt" 114 | manifest { 115 | attributes 'FMLAT': 'research_at.cfg' 116 | attributes 'Maven-Artifact': "${project.group}:${project.archivesBaseName}:${project.version}" 117 | attributes 'Timestamp': System.currentTimeMillis() 118 | } 119 | } 120 | 121 | javadoc { 122 | options.encoding = "UTF-8" 123 | options.charSet = "UTF-8" 124 | options.links = [ 125 | 'https://docs.oracle.com/javase/8/docs/api/' 126 | ] 127 | options.tags = [ 128 | "implSpec:a:Implementation Specification", 129 | "implNote:a:Implementation Note" 130 | ] 131 | } 132 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_version=1.12.2 2 | forge_version=14.23.5.2772 3 | mapping_version=stable_39 4 | 5 | version_major=1 6 | version_minor=0 7 | version_patch=3 8 | 9 | jei_version=4.14.4.267 10 | top_version=1.4.28-17 11 | ct_version=4.1.9.488 12 | bookshelf_version=2.3.557 13 | gamestages_version=2.0.114 14 | itemstages_version=2.0.49 15 | 16 | org.gradle.jvmargs=-DsocksProxyHost=127.0.0.1 -DsocksProxyPort=1080 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 14 12:28:28 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /libs/GrandEconomy-1.12.2-2.0.0-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/libs/GrandEconomy-1.12.2-2.0.0-api.jar -------------------------------------------------------------------------------- /libs/Kiwi-1.12.2-0.5.3.32-deobf.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/libs/Kiwi-1.12.2-0.5.3.32-deobf.jar -------------------------------------------------------------------------------- /run/scripts/grandeconomy.zs: -------------------------------------------------------------------------------- 1 | import mods.ResearchTable; 2 | import ResearchTable.Category; 3 | import ResearchTable.Builder; 4 | 5 | var cat = ResearchTable.addCategory(, "hello"); //category icon and title (optional) 6 | 7 | // Grand Economy Integration 8 | ResearchTable.builder("testResearch6", cat) 9 | .setTitle("Click for Money") 10 | .setIcons() 11 | // .setRequiredMoneyGE(10000) 12 | // .setTriggerMoneyGE(-9999) 13 | .setNoMaxCount() 14 | // .setRewardMoneyGE(10000) 15 | .build(); 16 | -------------------------------------------------------------------------------- /run/scripts/itemstages.zs: -------------------------------------------------------------------------------- 1 | import mods.ResearchTable; 2 | import ResearchTable.Category; 3 | import ResearchTable.Builder; 4 | 5 | // ItemStages Integration 6 | mods.ItemStages.addItemStage("one", ); 7 | -------------------------------------------------------------------------------- /run/scripts/layout-test.zs: -------------------------------------------------------------------------------- 1 | import mods.ResearchTable; 2 | import ResearchTable.Category; 3 | import ResearchTable.Builder; 4 | 5 | var cat = ResearchTable.addCategory(, "hello"); //category icon and title (optional) 6 | 7 | cat = ResearchTable.addCategory(); 8 | ResearchTable.builder("research7", cat) 9 | .setTitle("research7") 10 | .setIcons() 11 | .build(); 12 | 13 | cat = ResearchTable.addCategory(); 14 | ResearchTable.builder("research8", cat) 15 | .setTitle("research8") 16 | .setIcons() 17 | .build(); 18 | 19 | cat = ResearchTable.addCategory(); 20 | ResearchTable.builder("research10", cat) 21 | .setTitle("research10") 22 | .setIcons() 23 | .build(); 24 | 25 | cat = ResearchTable.addCategory(); 26 | ResearchTable.builder("research11", cat) 27 | .setTitle("research11") 28 | .setIcons() 29 | .build(); 30 | 31 | cat = ResearchTable.addCategory(); 32 | ResearchTable.builder("research12", cat) 33 | .setTitle("research12") 34 | .setIcons() 35 | .build(); 36 | 37 | cat = ResearchTable.addCategory(); 38 | ResearchTable.builder("research13", cat) 39 | .setTitle("research13") 40 | .setIcons() 41 | .build(); 42 | 43 | cat = ResearchTable.addCategory(); 44 | ResearchTable.builder("research14", cat) 45 | .setTitle("research14") 46 | .setIcons() 47 | .build(); 48 | 49 | cat = ResearchTable.addCategory(); 50 | ResearchTable.builder("research15", cat) 51 | .setTitle("research15") 52 | .setIcons() 53 | .build(); 54 | 55 | cat = ResearchTable.addCategory(); 56 | ResearchTable.builder("research16", cat) 57 | .setTitle("research16") 58 | .setIcons() 59 | .build(); 60 | 61 | cat = ResearchTable.addCategory(); 62 | ResearchTable.builder("research17", cat) 63 | .setTitle("research17") 64 | .setIcons() 65 | .build(); 66 | 67 | ResearchTable.builder("research18", cat) 68 | .setTitle("research17") 69 | .setIcons() 70 | .build(); 71 | ResearchTable.builder("research19", cat) 72 | .setTitle("research17") 73 | .setIcons() 74 | .build(); 75 | ResearchTable.builder("research20", cat) 76 | .setTitle("research17") 77 | .setIcons() 78 | .build(); 79 | ResearchTable.builder("research21", cat) 80 | .setTitle("research17") 81 | .setIcons() 82 | .build(); 83 | ResearchTable.builder("research22", cat) 84 | .setTitle("research17") 85 | .setIcons() 86 | .build(); 87 | ResearchTable.builder("research23", cat) 88 | .setTitle("research17") 89 | .setIcons() 90 | .build(); 91 | ResearchTable.builder("research24", cat) 92 | .setTitle("research17") 93 | .setIcons() 94 | .build(); 95 | ResearchTable.builder("research25", cat) 96 | .setTitle("research17") 97 | .setIcons() 98 | .build(); 99 | ResearchTable.builder("research26", cat) 100 | .setTitle("research17") 101 | .setIcons() 102 | .build(); 103 | ResearchTable.builder("research27", cat) 104 | .setTitle("research17") 105 | .setIcons() 106 | .build(); 107 | ResearchTable.builder("research28", cat) 108 | .setTitle("research17") 109 | .setIcons() 110 | .build(); 111 | ResearchTable.builder("research29", cat) 112 | .setTitle("research17") 113 | .setIcons() 114 | .build(); 115 | ResearchTable.builder("research30", cat) 116 | .setTitle("research17") 117 | .setIcons() 118 | .build(); 119 | ResearchTable.builder("research31", cat) 120 | .setTitle("research17") 121 | .setIcons() 122 | .build(); 123 | ResearchTable.builder("research32", cat) 124 | .setTitle("research17") 125 | .setIcons() 126 | .build(); 127 | ResearchTable.builder("research33", cat) 128 | .setTitle("research17") 129 | .setIcons() 130 | .build(); 131 | ResearchTable.builder("research34", cat) 132 | .setTitle("research17") 133 | .setIcons() 134 | .build(); 135 | ResearchTable.builder("research35", cat) 136 | .setTitle("research17") 137 | .setIcons() 138 | .build(); -------------------------------------------------------------------------------- /run/scripts/reskillable.zs: -------------------------------------------------------------------------------- 1 | import mods.ResearchTable; 2 | import ResearchTable.Category; 3 | import ResearchTable.Builder; 4 | 5 | var cat = ResearchTable.addCategory(, "hello"); 6 | 7 | // Reskillable Integration 8 | ResearchTable.builder("testResearch5", cat) 9 | .setTitle("Reskillable Test") 10 | .setIcons() 11 | .setRequiredSkill("reskillable.building", 3) 12 | .setRewardSkill("reskillable.building") 13 | .build(); 14 | -------------------------------------------------------------------------------- /run/scripts/test.zs: -------------------------------------------------------------------------------- 1 | import mods.ResearchTable; 2 | import ResearchTable.Category; 3 | import ResearchTable.Builder; 4 | 5 | // more examples please see scripts folder 6 | // use `/researchtable @p all 0` to clear all progress 7 | 8 | var cat = ResearchTable.addCategory(, "hello"); //category icon and title (optional) 9 | var cat2 = ResearchTable.addCategory(); 10 | 11 | ResearchTable.builder("testResearch1", cat) 12 | .setIcons() 13 | .setTitle("Alchemy") // I18n support: use language key 14 | .setDescription("Input your description") 15 | .addCondition( * 8, * 2000) 16 | .setRewardStages("stage") 17 | .setRewardCommands("/tellraw @a {\"text\":\"wow, \",\"extra\":[{\"selector\":\"@s\"},{\"text\":\" has found a gold!\"}]}") 18 | .setRewardItems(, ) 19 | //.setNoMaxCount() 20 | .build(); 21 | 22 | ResearchTable.builder("testResearch2", cat2) 23 | .setTitle("Energetic Wool loooooooong") 24 | .setIcons() 25 | .addCondition(, 2048, "Any Wool") // language key is better 26 | .addEnergyCondition(123456) 27 | .setMaxCount(2) // How many times can a player do this research? 28 | .build(); 29 | 30 | ResearchTable.builder("testResearch3", cat2) 31 | .setTitle("Produce Seller") 32 | .setIcons() 33 | .setRequiredResearches("testResearch1") 34 | //.setRequiredStages("stage", "stageYouWillNeverGet") 35 | //.setOptionalStages(2, "stage", "stage2", "stage3") 36 | //.setOptionalResearches(1, "testResearch1", "testResearch2", "testResearch3") 37 | .addCondition( * 2147483647) 38 | .addCondition( * 2147483647) 39 | .addCondition( * 2147483647) 40 | // CraftTweaker cannot handle item size more than Integer.MAX_VALUE, so here is another method 41 | .addCondition(, 9223372036854775807) 42 | .addCondition(, 9223372036854775807) 43 | .addCondition(, 9223372036854775807) 44 | .build(); 45 | 46 | // Scoreboard 47 | // Run this before using: 48 | // /scoreboard objectives add points dummy 49 | // /scoreboard objectives setdisplay sidebar points 50 | // /scoreboard players add @p points 1 51 | 52 | ResearchTable.builder("testResearch4", cat) 53 | .setTitle("Scoreboard Test") 54 | .setIcons() 55 | .setRequiredScore("points", "your.language.key", 1, 3) // inclusive 56 | .setTriggerCommands("/scoreboard players remove @s points 1") 57 | .build(); 58 | 59 | ResearchTable.scoreIndicator("points: %d", "points"); 60 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/ModConfig.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable; 2 | 3 | import net.minecraft.util.BlockRenderLayer; 4 | import net.minecraftforge.common.config.Config; 5 | import net.minecraftforge.common.config.ConfigManager; 6 | import net.minecraftforge.fml.client.event.ConfigChangedEvent; 7 | import net.minecraftforge.fml.common.Mod; 8 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 9 | 10 | @Config(modid = ResearchTable.MODID) 11 | @Mod.EventBusSubscriber(modid = ResearchTable.MODID) 12 | public final class ModConfig { 13 | private ModConfig() { 14 | throw new UnsupportedOperationException("No instance for you"); 15 | } 16 | 17 | @SubscribeEvent 18 | public static void onConfigReload(ConfigChangedEvent.OnConfigChangedEvent event) { 19 | if (event.getModID().equals(ResearchTable.MODID)) { 20 | ConfigManager.sync(ResearchTable.MODID, Config.Type.INSTANCE); 21 | } 22 | } 23 | 24 | @Config.Name("RenderLayer") 25 | public static BlockRenderLayer renderLayer = BlockRenderLayer.CUTOUT_MIPPED; 26 | 27 | @Config.Name("GuiFullScreen") 28 | public static boolean guiFullScreen = true; 29 | 30 | @Config.Name("GuiHeight") 31 | public static int guiHeight = 158; 32 | 33 | @Config.Name("GuiListWidth") 34 | public static int guiListWidth = 100; 35 | 36 | @Config.Name("GuiListAutoWidth") 37 | public static boolean guiListAutoWidth = true; 38 | 39 | @Config.Name("GuiDetailWidth") 40 | public static int guiDetailWidth = 150; 41 | 42 | @Config.Name("HideUnavailableResearch") 43 | public static boolean hideUnavailableResearch = false; 44 | 45 | @Config.Name("HideCompletedResearch") 46 | public static boolean hideCompletedResearch = false; 47 | 48 | @Config.Comment( 49 | "If enabled, the player will execute the rewarded command as if he is executing the command on his own. " + "Use this option if you encountered issue with a certain permission management system." 50 | ) 51 | @Config.Name("NonPrivilegedCommandReward") 52 | public static boolean nonPrivilegedMode = false; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/ResearchTable.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable; 2 | 3 | import org.apache.logging.log4j.Logger; 4 | 5 | import net.minecraft.entity.player.EntityPlayer; 6 | import net.minecraft.scoreboard.Score; 7 | import net.minecraft.scoreboard.ScoreObjective; 8 | import net.minecraft.scoreboard.Scoreboard; 9 | import net.minecraftforge.fml.common.Loader; 10 | import net.minecraftforge.fml.common.Mod; 11 | import net.minecraftforge.fml.common.Mod.EventBusSubscriber; 12 | import net.minecraftforge.fml.common.event.FMLInitializationEvent; 13 | import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; 14 | import net.minecraftforge.fml.common.event.FMLServerStartingEvent; 15 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 16 | import net.minecraftforge.fml.relauncher.Side; 17 | import net.minecraftforge.fml.relauncher.SideOnly; 18 | import snownee.kiwi.util.NBTHelper; 19 | import snownee.researchtable.client.renderer.ConditionRenderer; 20 | import snownee.researchtable.command.CommandResearch; 21 | import snownee.researchtable.core.EventOpenTable; 22 | import snownee.researchtable.network.NetworkChannel; 23 | import snownee.researchtable.network.PacketResearchChanged; 24 | import snownee.researchtable.network.PacketSyncClient; 25 | import snownee.researchtable.plugin.crafttweaker.ConditionCrTItem; 26 | import snownee.researchtable.plugin.crafttweaker.ConditionCrTLiquid; 27 | import snownee.researchtable.plugin.crafttweaker.RendererCrTItem; 28 | import snownee.researchtable.plugin.crafttweaker.RendererCrTLiquid; 29 | 30 | @Mod( 31 | modid = ResearchTable.MODID, name = ResearchTable.NAME, version = "@VERSION_INJECT@", acceptedMinecraftVersions = "[1.12, 1.13)", useMetadata = true 32 | ) 33 | @EventBusSubscriber 34 | public class ResearchTable { 35 | public static final String MODID = "researchtable"; 36 | public static final String NAME = "ResearchTable"; 37 | 38 | private static final ResearchTable INSTANCE = new ResearchTable(); 39 | 40 | public static String scoreFormattingText; 41 | public static String scores[]; 42 | 43 | @Mod.InstanceFactory 44 | public static ResearchTable getInstance() { 45 | return INSTANCE; 46 | } 47 | 48 | public static Logger logger; 49 | 50 | @Mod.EventHandler 51 | public void preInit(FMLPreInitializationEvent event) { 52 | logger = event.getModLog(); 53 | } 54 | 55 | @Mod.EventHandler 56 | public void init(FMLInitializationEvent event) { 57 | NetworkChannel.INSTANCE.register(PacketResearchChanged.class); 58 | NetworkChannel.INSTANCE.register(PacketSyncClient.class); 59 | } 60 | 61 | @Mod.EventHandler 62 | @SideOnly(Side.CLIENT) 63 | public void clientPreInit(FMLPreInitializationEvent event) { 64 | if (Loader.isModLoaded("crafttweaker")) { 65 | ConditionRenderer.register(ConditionCrTItem.class, new RendererCrTItem.Factory()); 66 | ConditionRenderer.register(ConditionCrTLiquid.class, new RendererCrTLiquid.Factory()); 67 | } 68 | } 69 | 70 | @Mod.EventHandler 71 | public void serverStarting(FMLServerStartingEvent event) { 72 | event.registerServerCommand(new CommandResearch()); 73 | } 74 | 75 | @SubscribeEvent 76 | public static void onOpenTable(EventOpenTable event) { 77 | EntityPlayer player = event.getEntityPlayer(); 78 | if (scores == null || scores.length == 0 || player.world.isRemote) { 79 | return; 80 | } 81 | 82 | Scoreboard scoreboard = player.world.getScoreboard(); 83 | NBTHelper helper = NBTHelper.of(event.getTable().getData()); 84 | 85 | for (String s : scores) { 86 | ScoreObjective scoreobjective = scoreboard.getObjective(s); 87 | if (scoreobjective == null) { 88 | continue; 89 | } 90 | // String key = player instanceof EntityPlayerMP ? player.getName() : player.getCachedUniqueIdString(); 91 | String key = player.getName(); 92 | if (!scoreboard.entityHasObjective(key, scoreobjective)) { 93 | continue; 94 | } 95 | Score score = scoreboard.getOrCreateScore(key, scoreobjective); 96 | int i = score.getScorePoints(); 97 | helper.setInt("score." + s, i); 98 | } 99 | } 100 | 101 | // When current GUI is not null, you cannot receive event, I am not sure if it is a bug 102 | // @SubscribeEvent 103 | // @SideOnly(Side.CLIENT) 104 | // public static void onGameStageEvent(GameStageEvent event) 105 | // { 106 | // if (event.getClass() == GameStageEvent.Check.class || event.getClass() == GameStageEvent.Add.class || event.getClass() == GameStageEvent.Remove.class) 107 | // { 108 | // return; 109 | // } 110 | // GuiScreen gui = Minecraft.getMinecraft().currentScreen; 111 | // if (gui != null && gui.getClass() == GuiTable.class) 112 | // { 113 | // ((GuiTable) gui).resetProgress(); 114 | // } 115 | // } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/ResearchTableModule.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable; 2 | 3 | import net.minecraft.block.material.Material; 4 | import net.minecraft.util.ResourceLocation; 5 | import net.minecraftforge.fml.common.network.NetworkRegistry; 6 | import net.minecraftforge.fml.common.registry.GameRegistry; 7 | import snownee.kiwi.IModule; 8 | import snownee.kiwi.KiwiModule; 9 | import snownee.researchtable.block.BlockTable; 10 | import snownee.researchtable.block.TileTable; 11 | import snownee.researchtable.network.GuiHandler; 12 | 13 | @KiwiModule(modid = ResearchTable.MODID) 14 | public class ResearchTableModule implements IModule { 15 | public static final BlockTable TABLE = new BlockTable("table", Material.IRON); 16 | 17 | @Override 18 | public void preInit() { 19 | NetworkRegistry.INSTANCE.registerGuiHandler(ResearchTable.getInstance(), new GuiHandler()); 20 | } 21 | 22 | @Override 23 | public void init() { 24 | GameRegistry.registerTileEntity(TileTable.class, new ResourceLocation(ResearchTable.MODID, "table")); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/block/BlockTable.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.block; 2 | 3 | import java.util.List; 4 | 5 | import net.minecraft.block.Block; 6 | import net.minecraft.block.material.Material; 7 | import net.minecraft.block.state.BlockFaceShape; 8 | import net.minecraft.block.state.IBlockState; 9 | import net.minecraft.client.renderer.block.model.ModelResourceLocation; 10 | import net.minecraft.client.resources.I18n; 11 | import net.minecraft.client.util.ITooltipFlag; 12 | import net.minecraft.creativetab.CreativeTabs; 13 | import net.minecraft.entity.EntityLivingBase; 14 | import net.minecraft.entity.player.EntityPlayer; 15 | import net.minecraft.item.Item; 16 | import net.minecraft.item.ItemStack; 17 | import net.minecraft.nbt.NBTTagCompound; 18 | import net.minecraft.tileentity.TileEntity; 19 | import net.minecraft.util.BlockRenderLayer; 20 | import net.minecraft.util.EnumFacing; 21 | import net.minecraft.util.EnumHand; 22 | import net.minecraft.util.NonNullList; 23 | import net.minecraft.util.math.AxisAlignedBB; 24 | import net.minecraft.util.math.BlockPos; 25 | import net.minecraft.util.math.MathHelper; 26 | import net.minecraft.util.text.TextComponentTranslation; 27 | import net.minecraft.util.text.TextFormatting; 28 | import net.minecraft.world.IBlockAccess; 29 | import net.minecraft.world.World; 30 | import net.minecraftforge.client.model.ModelLoader; 31 | import net.minecraftforge.common.MinecraftForge; 32 | import net.minecraftforge.common.util.Constants; 33 | import net.minecraftforge.fluids.FluidStack; 34 | import net.minecraftforge.fluids.FluidUtil; 35 | import net.minecraftforge.fluids.capability.IFluidHandler; 36 | import net.minecraftforge.fluids.capability.IFluidHandlerItem; 37 | import net.minecraftforge.fml.relauncher.Side; 38 | import net.minecraftforge.fml.relauncher.SideOnly; 39 | import net.minecraftforge.items.ItemHandlerHelper; 40 | import snownee.kiwi.block.BlockModHorizontal; 41 | import snownee.kiwi.util.NBTHelper; 42 | import snownee.kiwi.util.Util; 43 | import snownee.researchtable.ModConfig; 44 | import snownee.researchtable.ResearchTable; 45 | import snownee.researchtable.core.EventOpenTable; 46 | import snownee.researchtable.core.Research; 47 | 48 | public class BlockTable extends BlockModHorizontal { 49 | private static final AxisAlignedBB AABB = new AxisAlignedBB(0.1, 0, 0.1, 0.9, 0.9, 0.9); 50 | 51 | public BlockTable(String name, Material blockMaterial) { 52 | super(name, blockMaterial); 53 | setCreativeTab(CreativeTabs.DECORATIONS); 54 | setLightLevel(0.5F); 55 | } 56 | 57 | @Override 58 | @SideOnly(Side.CLIENT) 59 | public void mapModel() { 60 | ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(this), 0, new ModelResourceLocation(getRegistryName(), "facing=north")); 61 | } 62 | 63 | @Override 64 | public boolean isOpaqueCube(IBlockState state) { 65 | return false; 66 | } 67 | 68 | @Override 69 | public boolean isFullCube(IBlockState state) { 70 | return false; 71 | } 72 | 73 | @Override 74 | public BlockFaceShape getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face) { 75 | return BlockFaceShape.UNDEFINED; 76 | } 77 | 78 | @Override 79 | public BlockRenderLayer getRenderLayer() { 80 | return ModConfig.renderLayer; 81 | } 82 | 83 | @Override 84 | public boolean hasTileEntity(IBlockState state) { 85 | return true; 86 | } 87 | 88 | @Override 89 | public TileEntity createTileEntity(World world, IBlockState state) { 90 | return new TileTable(); 91 | } 92 | 93 | @Override 94 | public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) { 95 | ItemStack stack = playerIn.getHeldItem(hand); 96 | ItemStack copy = ItemHandlerHelper.copyStackWithSize(stack, 1); 97 | IFluidHandlerItem fluidHandler = FluidUtil.getFluidHandler(copy); 98 | if (fluidHandler != null) { 99 | IFluidHandler fluidDestination = FluidUtil.getFluidHandler(worldIn, pos, facing); 100 | if (fluidDestination != null) { 101 | FluidStack transferred = FluidUtil.tryFluidTransfer(fluidDestination, fluidHandler, Integer.MAX_VALUE, true); 102 | if (transferred != null && !playerIn.isCreative()) { 103 | if (stack.getCount() > 1) { 104 | stack.shrink(1); 105 | ItemHandlerHelper.giveItemToPlayer(playerIn, fluidHandler.getContainer()); 106 | } else { 107 | playerIn.setHeldItem(hand, fluidHandler.getContainer()); 108 | } 109 | } 110 | } 111 | } else { 112 | TileEntity tile = worldIn.getTileEntity(pos); 113 | if (tile instanceof TileTable) { 114 | TileTable table = (TileTable) tile; 115 | if (!table.hasPermission(playerIn)) { 116 | playerIn.sendMessage(new TextComponentTranslation(ResearchTable.MODID + ".noPermission")); 117 | } else if (!worldIn.isRemote && !MinecraftForge.EVENT_BUS.post(new EventOpenTable(playerIn, table))) { 118 | table.putOwnerInfo(playerIn); 119 | playerIn.openGui(ResearchTable.getInstance(), 0, worldIn, pos.getX(), pos.getY(), pos.getZ()); 120 | } 121 | } 122 | } 123 | return true; 124 | } 125 | 126 | @Override 127 | @SideOnly(Side.CLIENT) 128 | public void addInformation(ItemStack stack, World worldIn, List tooltip, ITooltipFlag flagIn) { 129 | NBTTagCompound compound = stack.getTagCompound(); 130 | if (compound != null) { 131 | if (compound.hasKey("BlockEntityTag", Constants.NBT.TAG_COMPOUND)) { 132 | String ownerName = null; 133 | NBTTagCompound tileCompound = compound.getCompoundTag("BlockEntityTag"); 134 | if (tileCompound.hasKey("owner", Constants.NBT.TAG_COMPOUND)) { 135 | ownerName = NBTHelper.of(tileCompound).getString("owner.name"); 136 | } else if (tileCompound.hasKey("owner", Constants.NBT.TAG_STRING)) { 137 | ownerName = tileCompound.getString("owner"); 138 | } 139 | if (ownerName != null) { 140 | tooltip.add(I18n.format(ResearchTable.MODID + ".gui.owner", TextFormatting.RESET + ownerName + TextFormatting.GRAY)); 141 | } 142 | } 143 | if (compound.hasKey("title", Constants.NBT.TAG_STRING)) { 144 | String title = compound.getString("title"); 145 | if (I18n.hasKey(title)) { 146 | title = I18n.format(title); 147 | } 148 | tooltip.add(I18n.format(ResearchTable.MODID + ".gui.researching", TextFormatting.RESET + title + TextFormatting.GRAY)); 149 | if (compound.hasKey("progress", Constants.NBT.TAG_FLOAT)) { 150 | float progress = compound.getFloat("progress"); 151 | tooltip.add(I18n.format(ResearchTable.MODID + ".gui.progress", TextFormatting.RESET + Util.MESSAGE_FORMAT.format(new Float[] { progress }) + "%" + TextFormatting.GRAY)); 152 | } 153 | } 154 | } 155 | super.addInformation(stack, worldIn, tooltip, flagIn); 156 | } 157 | 158 | @Override 159 | public void breakBlock(World worldIn, BlockPos pos, IBlockState state) { 160 | ItemStack stack = new ItemStack(this); 161 | TileEntity tile = worldIn.getTileEntity(pos); 162 | if (tile instanceof TileTable) { 163 | TileTable table = ((TileTable) tile); 164 | NBTTagCompound compound = new NBTTagCompound(); 165 | NBTTagCompound tileCompound = table.writeToNBT(new NBTTagCompound()); 166 | tileCompound.removeTag("x"); 167 | tileCompound.removeTag("y"); 168 | tileCompound.removeTag("z"); 169 | tileCompound.removeTag("id"); 170 | compound.setTag("BlockEntityTag", tileCompound); 171 | Research research = table.getResearch(); 172 | if (research != null) { 173 | compound.setString("title", research.getTitleRaw()); 174 | compound.setFloat("progress", table.getProgress()); 175 | } 176 | stack.setTagCompound(compound); 177 | } 178 | spawnAsEntity(worldIn, pos, stack); 179 | if (tile != null) { 180 | worldIn.removeTileEntity(pos); 181 | } 182 | } 183 | 184 | @Override 185 | public void getDrops(NonNullList drops, IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { 186 | // NO-OP 187 | } 188 | 189 | @Override 190 | public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { 191 | if (!worldIn.isRemote) { 192 | TileEntity tile = worldIn.getTileEntity(pos); 193 | if (tile instanceof TileTable) { 194 | ((TileTable) tile).putOwnerInfo((EntityPlayer) placer); 195 | } 196 | } 197 | } 198 | 199 | @Override 200 | public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { 201 | return AABB; 202 | } 203 | 204 | @Override 205 | public boolean hasComparatorInputOverride(IBlockState state) { 206 | return true; 207 | } 208 | 209 | @Override 210 | public int getComparatorInputOverride(IBlockState blockState, World worldIn, BlockPos pos) { 211 | TileEntity tile = worldIn.getTileEntity(pos); 212 | if (tile instanceof TileTable) { 213 | TileTable table = (TileTable) tile; 214 | if (table.getResearch() == null) { 215 | return 0; 216 | } 217 | if (table.canComplete()) { 218 | return 15; 219 | } 220 | return 1 + MathHelper.ceil(table.getProgress() * 0.13f); 221 | } 222 | return 0; 223 | } 224 | 225 | @Override 226 | public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) { 227 | TileEntity tile = worldIn.getTileEntity(pos); 228 | if (tile instanceof TileTable) { 229 | TileTable table = (TileTable) tile; 230 | boolean powered = worldIn.isBlockPowered(pos) || worldIn.isBlockPowered(pos.up()); 231 | if (powered && !table.powered) { 232 | // TODO 233 | } 234 | table.powered = powered; 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/block/TileTable.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.block; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.UUID; 6 | import java.util.function.Supplier; 7 | 8 | import javax.annotation.Nonnull; 9 | import javax.annotation.Nullable; 10 | 11 | import com.google.common.base.Objects; 12 | 13 | import net.minecraft.entity.player.EntityPlayer; 14 | import net.minecraft.item.ItemStack; 15 | import net.minecraft.nbt.NBTTagCompound; 16 | import net.minecraft.nbt.NBTUtil; 17 | import net.minecraft.util.EnumFacing; 18 | import net.minecraftforge.common.UsernameCache; 19 | import net.minecraftforge.common.capabilities.Capability; 20 | import net.minecraftforge.common.util.Constants; 21 | import net.minecraftforge.common.util.FakePlayer; 22 | import net.minecraftforge.energy.CapabilityEnergy; 23 | import net.minecraftforge.energy.IEnergyStorage; 24 | import net.minecraftforge.fluids.FluidStack; 25 | import net.minecraftforge.fluids.capability.CapabilityFluidHandler; 26 | import net.minecraftforge.fluids.capability.IFluidHandler; 27 | import net.minecraftforge.fluids.capability.IFluidTankProperties; 28 | import net.minecraftforge.items.CapabilityItemHandler; 29 | import net.minecraftforge.items.IItemHandler; 30 | import net.minecraftforge.items.ItemHandlerHelper; 31 | import snownee.kiwi.tile.TileBase; 32 | import snownee.researchtable.ResearchTable; 33 | import snownee.researchtable.core.ConditionTypes; 34 | import snownee.researchtable.core.DataStorage; 35 | import snownee.researchtable.core.ICondition; 36 | import snownee.researchtable.core.Research; 37 | import snownee.researchtable.core.ResearchList; 38 | import snownee.researchtable.core.team.TeamHelper; 39 | 40 | public class TileTable extends TileBase { 41 | 42 | public class ResearchItemWrapper implements IItemHandler { 43 | 44 | ResearchItemWrapper() { 45 | } 46 | 47 | @Override 48 | public int getSlots() { 49 | return research != null && !canComplete ? 1 : 0; 50 | } 51 | 52 | @Override 53 | public ItemStack getStackInSlot(int slot) { 54 | return ItemStack.EMPTY; 55 | } 56 | 57 | @Override 58 | public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { 59 | if (slot == 0 && research != null && !stack.isEmpty() && !canComplete) { 60 | long matched = match(ConditionTypes.ITEM, stack, simulate); 61 | return ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - (int) matched); 62 | } 63 | return stack; 64 | } 65 | 66 | @Override 67 | public ItemStack extractItem(int slot, int amount, boolean simulate) { 68 | return ItemStack.EMPTY; 69 | } 70 | 71 | @Override 72 | public int getSlotLimit(int slot) { 73 | return Integer.MAX_VALUE; 74 | } 75 | } 76 | 77 | public class ResearchEnergyWrapper implements IEnergyStorage { 78 | 79 | @Override 80 | public int receiveEnergy(int maxReceive, boolean simulate) { 81 | if (canReceive()) { 82 | return (int) match(ConditionTypes.ENERGY, (long) maxReceive, simulate); 83 | } 84 | return 0; 85 | } 86 | 87 | @Override 88 | public int extractEnergy(int maxExtract, boolean simulate) { 89 | return 0; 90 | } 91 | 92 | @Override 93 | public int getEnergyStored() { 94 | return 0; 95 | } 96 | 97 | @Override 98 | public int getMaxEnergyStored() { 99 | return Integer.MAX_VALUE; 100 | } 101 | 102 | @Override 103 | public boolean canExtract() { 104 | return false; 105 | } 106 | 107 | @Override 108 | public boolean canReceive() { 109 | return research != null && !canComplete; 110 | } 111 | 112 | } 113 | 114 | public class ResearchFluidWrapper implements IFluidHandler { 115 | private final FluidTankProperties info; 116 | 117 | public ResearchFluidWrapper() { 118 | info = new FluidTankProperties(); 119 | } 120 | 121 | @Override 122 | public IFluidTankProperties[] getTankProperties() { 123 | return new IFluidTankProperties[] { info }; 124 | } 125 | 126 | @Override 127 | public int fill(FluidStack resource, boolean doFill) { 128 | if (research != null && !canComplete) { 129 | return (int) match(ConditionTypes.FLUID, resource, !doFill); 130 | } 131 | return 0; 132 | } 133 | 134 | @Override 135 | public FluidStack drain(FluidStack resource, boolean doDrain) { 136 | return null; 137 | } 138 | 139 | @Override 140 | public FluidStack drain(int maxDrain, boolean doDrain) { 141 | return null; 142 | } 143 | 144 | } 145 | 146 | private class FluidTankProperties implements IFluidTankProperties { 147 | 148 | @Override 149 | @Nullable 150 | public FluidStack getContents() { 151 | return null; 152 | } 153 | 154 | @Override 155 | public int getCapacity() { 156 | return Integer.MAX_VALUE; 157 | } 158 | 159 | @Override 160 | public boolean canFill() { 161 | return research != null && !canComplete; 162 | } 163 | 164 | @Override 165 | public boolean canDrain() { 166 | return false; 167 | } 168 | 169 | @Override 170 | public boolean canFillFluidType(FluidStack fluidStack) { 171 | return canFill() && match(ConditionTypes.FLUID, fluidStack, true) > 0; 172 | } 173 | 174 | @Override 175 | public boolean canDrainFluidType(FluidStack fluidStack) { 176 | return false; 177 | } 178 | 179 | } 180 | 181 | @Nullable 182 | private Research research; 183 | @Nullable 184 | private Research lastResearch; 185 | @Nullable 186 | private long[] progress; 187 | public boolean hasChanged; 188 | @Nonnull 189 | public String ownerName; 190 | @Nonnull 191 | private UUID ownerUUID; 192 | private ResearchItemWrapper itemHandler = new ResearchItemWrapper(); 193 | private ResearchEnergyWrapper energyHandler = new ResearchEnergyWrapper(); 194 | private ResearchFluidWrapper fluidHandler = new ResearchFluidWrapper(); 195 | private boolean canComplete; 196 | private NBTTagCompound data = new NBTTagCompound(); 197 | public boolean powered; 198 | 199 | @Nullable 200 | public Research getResearch() { 201 | return research; 202 | } 203 | 204 | @Nullable 205 | public Research getLastResearch() { 206 | return lastResearch; 207 | } 208 | 209 | public UUID getOwnerUUID() { 210 | return this.ownerUUID; 211 | } 212 | 213 | public void setOwnerUUID(UUID uuid) { 214 | if (this.ownerUUID == null) { 215 | this.ownerUUID = uuid; 216 | } else { 217 | ResearchTable.logger.debug("An attempt of re-setting research table owner uuid occurred. Action aborted."); 218 | } 219 | } 220 | 221 | public void setResearch(@Nullable Research research) { 222 | if (this.research == research) { 223 | return; 224 | } 225 | if (this.research != null) { 226 | lastResearch = this.research; 227 | } 228 | this.research = research; 229 | if (research == null) { 230 | progress = null; 231 | } else { 232 | progress = new long[research.getConditions().size()]; 233 | } 234 | refreshCanComplete(); 235 | } 236 | 237 | @Override 238 | protected void readPacketData(NBTTagCompound tag) { 239 | if (tag.hasKey("data", Constants.NBT.TAG_COMPOUND)) { 240 | data = tag.getCompoundTag("data"); 241 | } 242 | if (tag.hasKey("owner", Constants.NBT.TAG_COMPOUND)) { 243 | NBTTagCompound credential = tag.getCompoundTag("owner"); 244 | this.ownerName = credential.getString("name"); 245 | this.ownerUUID = NBTUtil.getUUIDFromTag(credential.getCompoundTag("uuid")); 246 | } else { 247 | ResearchTable.logger.error("Invalid table data: pos={} tag={}", pos, tag); 248 | invalidate(); 249 | // TODO Warn about missing owner info 250 | } 251 | if (tag.hasKey("research", Constants.NBT.TAG_STRING)) { 252 | String name = tag.getString("research"); 253 | Optional result = ResearchList.find(name); 254 | if (result.isPresent()) { 255 | setResearch(result.get()); 256 | for (int i = 0; i < progress.length; i++) { 257 | if (!tag.hasKey("progress" + i, Constants.NBT.TAG_LONG)) { 258 | continue; 259 | } 260 | progress[i] = tag.getLong("progress" + i); 261 | } 262 | refreshCanComplete(); 263 | } 264 | } else { 265 | setResearch(null); 266 | } 267 | hasChanged = true; // client 268 | } 269 | 270 | @Override 271 | public void readFromNBT(NBTTagCompound compound) { 272 | super.readFromNBT(compound); 273 | if (compound.hasKey("last", Constants.NBT.TAG_STRING)) { 274 | lastResearch = ResearchList.find(compound.getString("last")).orElse(null); 275 | } 276 | if (compound.hasKey("powered", Constants.NBT.TAG_BYTE)) { 277 | powered = compound.getBoolean("powered"); 278 | } 279 | readPacketData(compound); 280 | } 281 | 282 | @Override 283 | protected NBTTagCompound writePacketData(NBTTagCompound tag) { 284 | NBTTagCompound credential = new NBTTagCompound(); 285 | if (ownerName != null || ownerUUID != null) { 286 | if (ownerName != null) { 287 | credential.setString("name", ownerName); 288 | } 289 | if (ownerUUID != null) { 290 | credential.setTag("uuid", NBTUtil.createUUIDTag(this.ownerUUID)); 291 | } 292 | } 293 | tag.setTag("owner", credential); 294 | if (research != null) { 295 | tag.setString("research", research.getName()); 296 | for (int i = 0; i < progress.length; i++) { 297 | tag.setLong("progress" + i, progress[i]); 298 | } 299 | } 300 | tag.setTag("data", data); 301 | return tag; 302 | } 303 | 304 | @Override 305 | public NBTTagCompound writeToNBT(NBTTagCompound compound) { 306 | super.writeToNBT(compound); 307 | writePacketData(compound); 308 | if (lastResearch != null) { 309 | compound.setString("last", lastResearch.getName()); 310 | } 311 | compound.setBoolean("powered", powered); 312 | return compound; 313 | } 314 | 315 | public float getProgress() { 316 | if (research == null) { 317 | return 0; 318 | } 319 | List conditions = research.getConditions(); 320 | if (conditions.isEmpty()) { 321 | return 100; 322 | } 323 | double sum = 0; 324 | for (int i = 0; i < conditions.size(); i++) { 325 | if (conditions.get(i).getGoal() == 0) { 326 | continue; 327 | } 328 | sum += (double) progress[i] / conditions.get(i).getGoal(); 329 | } 330 | return (float) (sum / conditions.size()) * 100; 331 | } 332 | 333 | public long getProgress(int index) { 334 | if (progress != null && index >= 0 && index < progress.length) { 335 | return progress[index]; 336 | } 337 | return 0; 338 | } 339 | 340 | public NBTTagCompound getData() { 341 | return data; 342 | } 343 | 344 | public void setData(NBTTagCompound data) { 345 | this.data = data; 346 | } 347 | 348 | @Override 349 | public T getCapability(Capability capability, EnumFacing facing) { 350 | if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { 351 | return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast(itemHandler); 352 | } 353 | if (capability == CapabilityEnergy.ENERGY) { 354 | return CapabilityEnergy.ENERGY.cast(energyHandler); 355 | } 356 | if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { 357 | return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(fluidHandler); 358 | } 359 | return super.getCapability(capability, facing); 360 | } 361 | 362 | @Override 363 | public boolean hasCapability(Capability capability, EnumFacing facing) { 364 | return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || capability == CapabilityEnergy.ENERGY || capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY || super.hasCapability(capability, facing); 365 | } 366 | 367 | public boolean hasPermission(@Nullable EntityPlayer player) { 368 | if (player == null || player.world.isRemote) // Minecraft.player sometimes can be null 369 | { 370 | return true; 371 | } 372 | return player.getGameProfile().getId().equals(this.ownerUUID) || Objects.equal(TeamHelper.provider.getOwner(player.getGameProfile().getId()), ownerUUID); 373 | 374 | //ResearchTable.logger.warn("Player {} ('{}', UUID '{}') tried to access this table with owner of '{}' (UUID: '{}') but failed. This may be a bug.", player.getName(), player, player.getUniqueID(), this.ownerName, this.ownerUUID); 375 | } 376 | 377 | public boolean canComplete() { 378 | return canComplete; 379 | } 380 | 381 | private void refreshCanComplete() { 382 | if (research == null) { 383 | canComplete = false; 384 | markDirty(); 385 | return; 386 | } 387 | List conditions = research.getConditions(); 388 | for (int i = 0; i < progress.length; i++) { 389 | if (conditions.get(i).getGoal() > progress[i]) { 390 | canComplete = false; 391 | markDirty(); 392 | return; 393 | } 394 | } 395 | canComplete = true; 396 | markDirty(); 397 | } 398 | 399 | public void complete(EntityPlayer player) { 400 | if (research == null || world.isRemote) { 401 | return; 402 | } 403 | if (DataStorage.complete(ownerUUID, research) > 0) { 404 | research.complete(world, pos, player); 405 | hasChanged = true; // server 406 | } 407 | setResearch(null); 408 | } 409 | 410 | public void submit(EntityPlayer player) { 411 | // TODO: insert null NBT items first 412 | if (research == null || world.isRemote) { 413 | return; 414 | } 415 | for (int i = 0; i < player.inventory.mainInventory.size(); ++i) { 416 | ItemStack stack = player.inventory.mainInventory.get(i); 417 | ItemStack remain = itemHandler.insertItem(0, stack, false); 418 | if (remain != stack) { 419 | player.inventory.mainInventory.set(i, remain); 420 | } 421 | } 422 | } 423 | 424 | public long match(Supplier> type, T e, boolean simulate) { 425 | List conditions = research.getConditions(); 426 | long matched = 0; 427 | for (int i = 0; i < conditions.size(); ++i) { 428 | ICondition condition = conditions.get(i); 429 | if (condition.getMatchType() == type) { 430 | long matchedIn = condition.matches(e); 431 | if (matchedIn < 0) { 432 | matchedIn = 0; 433 | } 434 | if (matchedIn > condition.getGoal() - progress[i]) { 435 | matchedIn = condition.getGoal() - progress[i]; 436 | } 437 | if (matched + matchedIn < matched) { 438 | matchedIn = Long.MAX_VALUE - matched; 439 | } 440 | matched += matchedIn; 441 | if (matchedIn > 0 && !simulate) { 442 | progress[i] += matchedIn; 443 | } 444 | if (matched == Long.MAX_VALUE) { 445 | break; 446 | } 447 | } 448 | } 449 | if (matched > 0 && !simulate) { 450 | refreshCanComplete(); 451 | hasChanged = true; 452 | } 453 | return matched; 454 | } 455 | 456 | public void putOwnerInfo(EntityPlayer player) { 457 | if (player instanceof FakePlayer) { 458 | return; 459 | } 460 | UUID uuid = player.getGameProfile().getId(); 461 | UUID owner = TeamHelper.provider.getOwner(uuid); 462 | if (owner != null) { 463 | ownerName = TeamHelper.provider.getTeamName(owner); 464 | if (ownerName == null) { 465 | ownerName = UsernameCache.getLastKnownUsername(owner); 466 | } 467 | if (ownerName == null) { 468 | ownerName = player.getName(); 469 | } 470 | setOwnerUUID(owner); 471 | } else { 472 | ownerName = player.getName(); 473 | setOwnerUUID(uuid); 474 | } 475 | } 476 | 477 | } 478 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/ComponentButtonList.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import java.util.Collections; 4 | 5 | import org.lwjgl.input.Mouse; 6 | 7 | import net.minecraft.client.renderer.GlStateManager; 8 | import net.minecraft.client.renderer.Tessellator; 9 | import net.minecraft.client.resources.I18n; 10 | import net.minecraft.util.ResourceLocation; 11 | import net.minecraftforge.fml.relauncher.Side; 12 | import net.minecraftforge.fml.relauncher.SideOnly; 13 | import snownee.kiwi.client.AdvancedFontRenderer; 14 | import snownee.kiwi.client.gui.GuiControl; 15 | import snownee.kiwi.client.gui.component.Component; 16 | import snownee.kiwi.client.gui.element.DrawableNineSlice; 17 | import snownee.researchtable.ResearchTable; 18 | 19 | @SideOnly(Side.CLIENT) 20 | public class ComponentButtonList extends Component { 21 | private static final ResourceLocation TEXTURE = new ResourceLocation("textures/gui/container/beacon.png"); 22 | private static final DrawableNineSlice DRAWABLE_NORMAL; 23 | private static final DrawableNineSlice DRAWABLE_CLICKED; 24 | private static final DrawableNineSlice DRAWABLE_DISABLED; 25 | private static final DrawableNineSlice DRAWABLE_HOVERED; 26 | private static final DrawableNineSlice[] DRAWABLES; 27 | private State[] states = new State[] { State.INVISIBLE, State.NORMAL }; 28 | private String[] texts = new String[2]; 29 | private int[] widths = new int[2]; 30 | private boolean cancel; 31 | 32 | static { 33 | DRAWABLE_NORMAL = new DrawableNineSlice(TEXTURE, 0, 219, 22, 22, 1, 1, 1, 1); 34 | DRAWABLE_CLICKED = new DrawableNineSlice(TEXTURE, 22, 219, 22, 22, 1, 1, 1, 1); 35 | DRAWABLE_DISABLED = new DrawableNineSlice(TEXTURE, 44, 219, 22, 22, 1, 1, 1, 1); 36 | DRAWABLE_HOVERED = new DrawableNineSlice(TEXTURE, 66, 219, 22, 22, 1, 1, 1, 1); 37 | DRAWABLES = new DrawableNineSlice[] { DRAWABLE_NORMAL, DRAWABLE_CLICKED, DRAWABLE_DISABLED, DRAWABLE_HOVERED }; 38 | } 39 | 40 | public enum State { 41 | NORMAL, CLICKED, DISABLED, HOVERED, INVISIBLE 42 | } 43 | 44 | public ComponentButtonList(GuiControl parent, int width, int height) { 45 | super(parent, width, height); 46 | setText(0, "submit"); 47 | setText(1, "research"); 48 | } 49 | 50 | public void setText(int index, String key) { 51 | String text = I18n.format(ResearchTable.MODID + ".gui.button." + key); 52 | texts[index] = text; 53 | widths[index] = Math.max(AdvancedFontRenderer.INSTANCE.getStringWidth(text) + 4, 40); 54 | if (index == 1) { 55 | cancel = key.equals("cancel"); 56 | } 57 | } 58 | 59 | public void setState(int index, State state) { 60 | states[index] = state; 61 | } 62 | 63 | @Override 64 | public void drawScreen(int offsetX, int offsetY, int relMouseX, int relMouseY, float partialTicks) { 65 | offsetY += 4; 66 | int x = width; 67 | for (int i = states.length - 1; i >= 0; i--) { 68 | if (states[i] == State.INVISIBLE) { 69 | continue; 70 | } 71 | x -= widths[i]; 72 | if (states[i] != State.DISABLED) { 73 | if (GuiTable.isInRegion(x, 4, x + widths[i], 16, relMouseX, relMouseY)) { 74 | if (Mouse.isButtonDown(0)) { 75 | states[i] = State.CLICKED; 76 | } else { 77 | states[i] = State.HOVERED; 78 | if (i == 1 && cancel) { 79 | setTooltip(Collections.singletonList(I18n.format("researchtable.gui.button.shift")), AdvancedFontRenderer.INSTANCE); 80 | } 81 | } 82 | } else { 83 | states[i] = State.NORMAL; 84 | } 85 | } 86 | Tessellator.getInstance().getBuffer().setTranslation(0, 0, 0); 87 | GlStateManager.color(1, 1, 1, 1); 88 | DrawableNineSlice drawable = DRAWABLES[states[i].ordinal()]; 89 | drawable.setWidth(widths[i]); 90 | drawable.setHeight(12); 91 | drawable.draw(parent.mc, x + offsetX, offsetY); 92 | int stringWidth = AdvancedFontRenderer.INSTANCE.getStringWidth(texts[i]); 93 | AdvancedFontRenderer.INSTANCE.drawString(texts[i], x + offsetX + (widths[i] - stringWidth) / 2, offsetY + 2, states[i] == State.DISABLED ? 0x999999 : 0); 94 | x -= 5; 95 | } 96 | } 97 | 98 | @Override 99 | public void handleMouseInput(int relMouseX, int relMouseY) { 100 | int x = width; 101 | for (int i = states.length - 1; i >= 0; i--) { 102 | if (states[i] == State.INVISIBLE) { 103 | continue; 104 | } 105 | x -= widths[i]; 106 | if (states[i] != State.DISABLED && GuiTable.isInRegion(x, 4, x + widths[i], 16, relMouseX, relMouseY)) { 107 | sendMessage(i, states[i].ordinal()); 108 | } 109 | x -= 5; 110 | } 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/ComponentResearchDetail.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import javax.annotation.Nonnull; 4 | import javax.annotation.Nullable; 5 | 6 | import net.minecraft.client.renderer.Tessellator; 7 | import net.minecraft.util.text.TextFormatting; 8 | import net.minecraftforge.fml.relauncher.Side; 9 | import net.minecraftforge.fml.relauncher.SideOnly; 10 | import snownee.kiwi.client.gui.GuiControl; 11 | import snownee.kiwi.client.gui.component.Component; 12 | import snownee.kiwi.client.gui.component.ComponentList; 13 | import snownee.kiwi.client.gui.component.ComponentText; 14 | import snownee.researchtable.client.gui.ComponentButtonList.State; 15 | import snownee.researchtable.core.ICondition; 16 | import snownee.researchtable.core.ICriterion; 17 | import snownee.researchtable.core.Research; 18 | 19 | @SideOnly(Side.CLIENT) 20 | public class ComponentResearchDetail extends ComponentList { 21 | @Nullable 22 | private Research displaying; 23 | GuiControl control; 24 | private ComponentText text; 25 | private ComponentText info; 26 | private ComponentButtonList buttons; 27 | @Nullable 28 | Research researching; 29 | 30 | public ComponentResearchDetail(GuiControl control, int width, int height, int left, int top, int screenWidth, int screenHeight) { 31 | super(control, width, height, left, top, screenWidth, screenHeight); 32 | setDrawBackground(false); 33 | setDrawScrollBar(false); 34 | this.control = new GuiControlSpecial(control.mc, width, height, control); 35 | this.control.offsetX = left; 36 | this.control.offsetY = top; 37 | this.info = new ComponentText(this.control, width, 5, 5); 38 | this.control.addComponent(this.info); 39 | this.buttons = new ComponentButtonList(this.control, width - 8, 20); 40 | this.control.addComponent(this.buttons); 41 | this.text = new ComponentText(this.control, width, 5, 5); 42 | this.control.addComponent(this.text); 43 | } 44 | 45 | @Nullable 46 | public Research getResearch() { 47 | return displaying; 48 | } 49 | 50 | public void setResearch(@Nonnull Research displaying, boolean canComplete) { 51 | if (this.displaying != displaying) { 52 | this.displaying = displaying; 53 | for (int i = control.getComponentSize(null) - 4; i >= 0; --i) { 54 | // Last two components must be button list and text. remove others 55 | control.removeComponent(i); 56 | } 57 | text.setText(displaying.getDescription()); 58 | for (ICondition condition : displaying.getConditions()) { 59 | ComponentResearchProgress progress = new ComponentResearchProgress(control, width, condition); 60 | progress.setResearching(displaying == researching); 61 | control.addComponent(progress); 62 | } 63 | } 64 | updateResearching(canComplete); 65 | } 66 | 67 | @Override 68 | protected void elementClicked(int index, int mouseX, int mouseY, boolean doubleClick) { 69 | if (index >= 0 && index < control.getComponentSize(null)) { 70 | control.getComponent(index).handleMouseInput(mouseX, mouseY); 71 | } 72 | } 73 | 74 | @Override 75 | protected void drawBackground() { 76 | } 77 | 78 | @Override 79 | protected int getSize() { 80 | return control.getComponentSize(null); 81 | } 82 | 83 | @Override 84 | protected int getSlotHeight(int index) { 85 | if (index >= 0 && index < control.getComponentSize(null)) { 86 | Component component = control.getComponent(index); 87 | return component.visible ? component.height : 0; 88 | } 89 | return 0; 90 | } 91 | 92 | @Override 93 | protected void drawSlot(int slotIdx, int entryRight, int slotTop, int slotBuffer, Tessellator tess) { 94 | if (slotIdx >= 0 && slotIdx < control.getComponentSize(null)) { 95 | Component component = control.getComponent(slotIdx); 96 | if (component.visible) { 97 | component.drawScreen(offsetX, slotTop + offsetY, mouseX - left, mouseY - slotTop, control.mc.getRenderPartialTicks()); 98 | } 99 | } 100 | } 101 | 102 | @Override 103 | public void onDestroy() { 104 | control.onDestroy(); 105 | super.onDestroy(); 106 | } 107 | 108 | public void updateResearching(boolean canComplete) { 109 | visible = displaying != null; 110 | if (this.researching == this.displaying) { 111 | buttons.visible = true; 112 | if (this.displaying != null) // Researching 113 | { 114 | if (canComplete) { 115 | buttons.setState(0, State.INVISIBLE); 116 | buttons.setText(1, "complete"); 117 | } else { 118 | buttons.setState(0, State.NORMAL); 119 | buttons.setText(1, "cancel"); 120 | } 121 | } 122 | } else { 123 | buttons.visible = this.researching == null; 124 | if (buttons.visible) { 125 | buttons.setState(0, State.INVISIBLE); 126 | buttons.setState(1, displaying.canResearch(parent.mc.player, GuiTable.data) ? State.NORMAL : State.DISABLED); 127 | buttons.setText(1, "research"); 128 | } 129 | } 130 | 131 | if (displaying != null && researching != displaying && !displaying.canResearch(control.mc.player, GuiTable.data)) { 132 | String string = ""; 133 | boolean wrap = false; 134 | for (ICriterion criterion : displaying.getCriteria()) { 135 | if (criterion.matches(control.mc.player, GuiTable.data)) 136 | continue; 137 | if (wrap) 138 | string += "\n"; 139 | string += TextFormatting.RESET + criterion.getFailingText(control.mc.player, GuiTable.data); 140 | wrap = true; 141 | } 142 | info.setText(string); 143 | info.visible = true; 144 | } else { 145 | info.visible = false; 146 | } 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/ComponentResearchList.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | import org.lwjgl.input.Mouse; 7 | 8 | import com.google.common.collect.Lists; 9 | 10 | import net.minecraft.client.Minecraft; 11 | import net.minecraft.client.audio.PositionedSoundRecord; 12 | import net.minecraft.client.gui.Gui; 13 | import net.minecraft.client.renderer.GlStateManager; 14 | import net.minecraft.client.renderer.RenderHelper; 15 | import net.minecraft.client.renderer.RenderItem; 16 | import net.minecraft.client.renderer.Tessellator; 17 | import net.minecraft.client.resources.I18n; 18 | import net.minecraft.init.SoundEvents; 19 | import net.minecraft.util.math.MathHelper; 20 | import net.minecraftforge.fml.relauncher.Side; 21 | import net.minecraftforge.fml.relauncher.SideOnly; 22 | import snownee.kiwi.client.AdvancedFontRenderer; 23 | import snownee.kiwi.client.gui.GuiControl; 24 | import snownee.kiwi.client.gui.component.ComponentList; 25 | import snownee.kiwi.util.Util; 26 | import snownee.researchtable.ModConfig; 27 | import snownee.researchtable.core.DataStorage; 28 | import snownee.researchtable.core.Research; 29 | import snownee.researchtable.core.ResearchCategory; 30 | import snownee.researchtable.core.ResearchList; 31 | 32 | @SideOnly(Side.CLIENT) 33 | public class ComponentResearchList extends ComponentList { 34 | public static final int TAB_WIDTH = 28; 35 | 36 | final List researches = Lists.newLinkedList(); 37 | final List tabs = Lists.newLinkedList(); 38 | ResearchCategory category; 39 | int currentTabPage; 40 | int maxTabPage; 41 | 42 | private final int slotHeight; 43 | private final boolean showTabs; 44 | 45 | public ComponentResearchList(GuiControl parent, int width, int height, int left, int top, int entryHeight, int screenWidth, int screenHeight, boolean showTabs) { 46 | super(parent, width, height, showTabs ? left + TAB_WIDTH : left, top, screenWidth, screenHeight); 47 | this.slotHeight = entryHeight; 48 | this.showTabs = showTabs; 49 | if (showTabs) { 50 | int tabsPerPage = Math.max((height - 14) / TAB_WIDTH, 1); 51 | maxTabPage = MathHelper.ceil((double) ResearchList.CATEGORIES.size() / tabsPerPage); 52 | } 53 | } 54 | 55 | public void setCategory(ResearchCategory category) { 56 | if (category == null) { 57 | return; 58 | } 59 | this.category = category; 60 | researches.clear(); 61 | 62 | List researchesAvailable = Lists.newLinkedList(); 63 | List researchesUnavailable = Lists.newLinkedList(); 64 | List researchesCompleted = Lists.newLinkedList(); 65 | 66 | for (Research research : ResearchList.LIST.values()) { 67 | if (research.getCategory() != category) { 68 | continue; 69 | } 70 | if (research.canResearch(parent.mc.player, GuiTable.data)) { 71 | researchesAvailable.add(research); 72 | } else { 73 | if (DataStorage.count(parent.mc.player.getGameProfile().getId(), research) > 0) { 74 | if (!ModConfig.hideCompletedResearch) { 75 | researchesCompleted.add(research); 76 | } 77 | } else { 78 | if (!ModConfig.hideUnavailableResearch) { 79 | researchesUnavailable.add(research); 80 | } 81 | } 82 | } 83 | } 84 | researches.addAll(researchesAvailable); 85 | researches.addAll(researchesUnavailable); 86 | researches.addAll(researchesCompleted); 87 | updateTabs(); 88 | } 89 | 90 | private void updateTabs() { 91 | if (!showTabs) { 92 | return; 93 | } 94 | tabs.clear(); 95 | int btnLeft = left - TAB_WIDTH; 96 | int btnTop = top; 97 | int id = 114514; 98 | int tabsPerPage = Math.max((height - 14) / TAB_WIDTH, 1); 99 | int start = currentTabPage * tabsPerPage; 100 | for (int i = 0; i < tabsPerPage; i++) { 101 | if (start + i >= ResearchList.CATEGORIES.size()) { 102 | break; 103 | } 104 | ResearchCategory category2 = ResearchList.CATEGORIES.get(start + i); 105 | GuiButtonStack btn = new GuiButtonStack(id++, btnLeft, btnTop, category2.icon) { 106 | @Override 107 | public void onClick() { 108 | parent.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1.0F)); 109 | setCategory(category2); 110 | } 111 | 112 | @Override 113 | public boolean isSelected() { 114 | return ComponentResearchList.this.category == category2; 115 | } 116 | 117 | @Override 118 | public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) { 119 | super.drawButton(mc, mouseX, mouseY, partialTicks); 120 | if (category2.nameKey != null && visible && hovered) { 121 | String tooltip = category2.nameKey; 122 | if (I18n.hasKey(tooltip)) { 123 | tooltip = I18n.format(tooltip); 124 | } 125 | setTooltip(Collections.singletonList(tooltip), null); 126 | } 127 | } 128 | }; 129 | tabs.add(btn); 130 | btnTop += TAB_WIDTH; 131 | } 132 | } 133 | 134 | @Override 135 | protected int getSize() { 136 | return researches.size(); 137 | } 138 | 139 | @Override 140 | protected void elementClicked(int index, int mouseX, int mouseY, boolean doubleClick) { 141 | sendMessage(index, 0); 142 | } 143 | 144 | @Override 145 | protected void drawBackground() { 146 | } 147 | 148 | @Override 149 | protected void drawSlot(int slotIdx, int entryRight, int slotTop, int slotBuffer, Tessellator tess) { 150 | boolean hovering = slotIdx == hoveringIndex; 151 | Gui.drawRect(left, slotTop, left + width, slotTop + slotHeight - 1, hovering ? 0xFFDDDDDD : 0xFFEEEEEE); 152 | Research research = researches.get(slotIdx); 153 | RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); 154 | GlStateManager.disableLighting(); 155 | RenderHelper.enableGUIStandardItemLighting(); 156 | renderItem.renderItemAndEffectIntoGUI(research.getIcon(), offsetX + 6, offsetY + slotTop + 1); 157 | renderItem.renderItemOverlayIntoGUI(parent.mc.fontRenderer, research.getIcon(), offsetX + 6, offsetY + slotTop + 1, null); 158 | String title = research.getTitle(); 159 | if (!research.canResearch(Minecraft.getMinecraft().player, GuiTable.data)) { 160 | title = Util.color(0x808080) + title; 161 | } 162 | AdvancedFontRenderer.INSTANCE.drawString(title, offsetX + 32, offsetY + slotTop + 6, 0x000000); 163 | } 164 | 165 | @Override 166 | protected void drawGradientRect(int left, int top, int right, int bottom, int color1, int color2) { 167 | super.drawGradientRect(left, top, right, bottom, color1, color2); 168 | } 169 | 170 | @Override 171 | protected int getSlotHeight(int index) { 172 | return slotHeight; 173 | } 174 | 175 | @Override 176 | public void handleMouseInput(int mouseX, int mouseY) { 177 | if (showTabs && mouseX < left) { 178 | int scroll = Mouse.getEventDWheel(); 179 | if (scroll != 0) { 180 | scroll = scroll > 0 ? 1 : -1; 181 | currentTabPage = MathHelper.clamp(currentTabPage - scroll, 0, maxTabPage - 1); 182 | updateTabs(); 183 | } 184 | } else { 185 | super.handleMouseInput(mouseX, mouseY); 186 | } 187 | 188 | if (Mouse.isButtonDown(0) && Mouse.getEventButtonState()) { 189 | GuiButtonStack re = null; 190 | for (GuiButtonStack btn : tabs) { 191 | if (btn.isMouseOver()) { 192 | re = btn; 193 | break; 194 | } 195 | } 196 | if (re != null) { 197 | re.mousePressed(parent.mc, mouseX, mouseY); 198 | } 199 | } 200 | } 201 | 202 | @Override 203 | public void drawScreen(int x, int y, int mouseX, int mouseY, float arg4) { 204 | super.drawScreen(x, y, mouseX, mouseY, arg4); 205 | GlStateManager.pushMatrix(); 206 | GlStateManager.translate(x, y, 0); 207 | for (GuiButtonStack btn : tabs) { 208 | btn.drawButton(parent.mc, mouseX, mouseY, 0); 209 | } 210 | GlStateManager.popMatrix(); 211 | if (showTabs && maxTabPage > 1) { 212 | parent.mc.fontRenderer.drawString(currentTabPage + 1 + "/" + maxTabPage, 5, height - 13, 0); 213 | } 214 | } 215 | 216 | } 217 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/ComponentResearchProgress.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import java.util.List; 4 | 5 | import net.minecraft.client.gui.Gui; 6 | import net.minecraft.client.renderer.BufferBuilder; 7 | import net.minecraft.client.renderer.GlStateManager; 8 | import net.minecraft.client.renderer.Tessellator; 9 | import net.minecraft.client.util.ITooltipFlag; 10 | import net.minecraft.util.ResourceLocation; 11 | import net.minecraftforge.fml.relauncher.Side; 12 | import net.minecraftforge.fml.relauncher.SideOnly; 13 | import snownee.kiwi.client.AdvancedFontRenderer; 14 | import snownee.kiwi.client.gui.GuiControl; 15 | import snownee.kiwi.client.gui.component.Component; 16 | import snownee.kiwi.client.gui.element.DrawableResource; 17 | import snownee.kiwi.util.Util; 18 | import snownee.researchtable.client.renderer.ConditionRenderer; 19 | import snownee.researchtable.core.ICondition; 20 | 21 | @SideOnly(Side.CLIENT) 22 | public class ComponentResearchProgress extends Component { 23 | private static final DrawableResource SUCCESS_ICON = new DrawableResource(new ResourceLocation("textures/gui/container/beacon.png"), 91, 224, 14, 12); 24 | 25 | private final ICondition condition; 26 | private ConditionRenderer renderer; 27 | private boolean researching; 28 | private long total; 29 | private long target; 30 | private double current; 31 | 32 | public ComponentResearchProgress(GuiControl parent, int width, ICondition condition) { 33 | super(parent, width, 25); 34 | this.condition = condition; 35 | this.renderer = ConditionRenderer.get(condition); 36 | this.total = condition.getGoal(); 37 | if (total <= 0) { 38 | total = 1; 39 | } 40 | } 41 | 42 | public void resetRenderer() { 43 | this.renderer = ConditionRenderer.get(condition); 44 | } 45 | 46 | public void setResearching(boolean researching) { 47 | this.researching = researching; 48 | } 49 | 50 | public void setProgress(long progress) { 51 | this.target = progress; 52 | } 53 | 54 | @Override 55 | public void drawScreen(int offsetX, int offsetY, int relMouseX, int relMouseY, float partialTicks) { 56 | int left = offsetX; 57 | int right = left + width - 8; 58 | int top = offsetY; 59 | int bottom = top + height; 60 | 61 | if (researching) { 62 | Tessellator tessellator = Tessellator.getInstance(); 63 | BufferBuilder bufferbuilder = tessellator.getBuffer(); 64 | bufferbuilder.setTranslation(0, 0, 0); 65 | 66 | double progress = total == 0 ? 0 : target / (double) total; 67 | if (progress != current) { 68 | current += partialTicks * 0.03; 69 | current = Math.min(current, progress); 70 | } 71 | 72 | Gui.drawRect(left, top, left + (int) (width * current), bottom, 0x33339933); 73 | 74 | if (progress == 1) { 75 | GlStateManager.enableBlend(); 76 | GlStateManager.color(1, 1, 1, 1); 77 | SUCCESS_ICON.draw(parent.mc, right - 20, offsetY + 7); 78 | } else { 79 | AdvancedFontRenderer.INSTANCE.drawString((int) (progress * 100) + "%", right - 15, offsetY + 10, 0); 80 | } 81 | 82 | } else if (renderer != null) { 83 | String text = renderer.format(condition.getGoal()); 84 | AdvancedFontRenderer.INSTANCE.drawString(text, right - 10 - AdvancedFontRenderer.INSTANCE.getStringWidth(text), offsetY + 7, 0); 85 | } 86 | 87 | left = offsetX + 25; 88 | top = offsetY + 15; 89 | bottom = offsetY + 19; 90 | 91 | if (renderer != null) { 92 | Tessellator.getInstance().getBuffer().setTranslation(0, 0, 0); 93 | GlStateManager.color(1, 1, 1, 1); 94 | renderer.draw(parent.mc, offsetX + 5, offsetY + 4); 95 | String text = renderer.name(); 96 | if (researching) { 97 | text += " (" + Util.formatCompact(target) + "/" + Util.formatCompact(total) + ")"; 98 | } 99 | AdvancedFontRenderer.INSTANCE.drawString(text, left + 2, offsetY + 7, 0); 100 | if (GuiTable.isInRegion(5, 4, 21, 20, relMouseX, relMouseY)) { 101 | List tooltip = renderer.getTooltip(parent.mc.gameSettings.advancedItemTooltips ? ITooltipFlag.TooltipFlags.ADVANCED : ITooltipFlag.TooltipFlags.NORMAL); 102 | if (tooltip != null) { 103 | setTooltip(tooltip, renderer.getFont()); 104 | } 105 | } 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/GuiButtonStack.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.Gui; 5 | import net.minecraft.client.gui.GuiButton; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraftforge.fml.relauncher.Side; 8 | import net.minecraftforge.fml.relauncher.SideOnly; 9 | 10 | @SideOnly(Side.CLIENT) 11 | public class GuiButtonStack extends GuiButton { 12 | private final ItemStack stack; 13 | 14 | public GuiButtonStack(int buttonId, int x, int y, ItemStack stack) { 15 | super(buttonId, x, y, ComponentResearchList.TAB_WIDTH, ComponentResearchList.TAB_WIDTH, stack.getDisplayName()); 16 | this.stack = stack; 17 | } 18 | 19 | @Override 20 | public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) { 21 | if (!visible) 22 | return; 23 | this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; 24 | if (isSelected()) { 25 | Gui.drawRect(x + 2, y + 1, x + width, y + height - 1, 0xFFEEEEEE); 26 | } else if (isMouseOver()) { 27 | Gui.drawRect(x + 2, y + 1, x + width, y + height - 1, 0xFFDDDDDD); 28 | } 29 | mc.getRenderItem().renderItemIntoGUI(stack, x + width / 2 - 8, y + height / 2 - 8); 30 | } 31 | 32 | @Override 33 | public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { 34 | if (super.mousePressed(mc, mouseX, mouseY)) { 35 | onClick(); 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | public void onClick() { 42 | } 43 | 44 | public boolean isSelected() { 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/GuiControlSpecial.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraftforge.fml.relauncher.Side; 5 | import net.minecraftforge.fml.relauncher.SideOnly; 6 | import snownee.kiwi.client.gui.GuiControl; 7 | import snownee.kiwi.client.gui.IMessageHandler; 8 | import snownee.kiwi.client.gui.component.Component; 9 | 10 | @SideOnly(Side.CLIENT) 11 | public class GuiControlSpecial extends GuiControl { 12 | 13 | public GuiControlSpecial(Minecraft mc, int width, int height, IMessageHandler messageHandler) { 14 | super(mc, width, height, messageHandler); 15 | } 16 | 17 | @Override 18 | public void addComponent(Component component) { 19 | if (components.size() > 2) { 20 | components.add(components.size() - 3, component); 21 | } else { 22 | components.add(component); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/gui/GuiTable.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.gui; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | import java.util.IllegalFormatException; 6 | import java.util.List; 7 | 8 | import net.minecraft.client.audio.PositionedSoundRecord; 9 | import net.minecraft.client.gui.GuiScreen; 10 | import net.minecraft.client.renderer.GlStateManager; 11 | import net.minecraft.client.renderer.RenderHelper; 12 | import net.minecraft.client.resources.I18n; 13 | import net.minecraft.entity.player.InventoryPlayer; 14 | import net.minecraft.init.SoundEvents; 15 | import net.minecraft.nbt.NBTTagCompound; 16 | import net.minecraft.util.ResourceLocation; 17 | import net.minecraftforge.fml.relauncher.Side; 18 | import net.minecraftforge.fml.relauncher.SideOnly; 19 | import snownee.kiwi.client.AdvancedFontRenderer; 20 | import snownee.kiwi.client.gui.GuiContainerMod; 21 | import snownee.kiwi.client.gui.GuiControl; 22 | import snownee.kiwi.client.gui.component.Component; 23 | import snownee.kiwi.client.gui.component.ComponentPanel; 24 | import snownee.kiwi.client.gui.element.DrawableResource; 25 | import snownee.kiwi.util.NBTHelper; 26 | import snownee.researchtable.ModConfig; 27 | import snownee.researchtable.ResearchTable; 28 | import snownee.researchtable.block.TileTable; 29 | import snownee.researchtable.container.ContainerTable; 30 | import snownee.researchtable.core.Research; 31 | import snownee.researchtable.core.ResearchList; 32 | import snownee.researchtable.network.NetworkChannel; 33 | import snownee.researchtable.network.PacketResearchChanged; 34 | import snownee.researchtable.network.PacketResearchChanged.Action; 35 | 36 | @SideOnly(Side.CLIENT) 37 | public class GuiTable extends GuiContainerMod { 38 | public static float ticks; 39 | public static NBTTagCompound data; 40 | private final TileTable table; 41 | private ComponentResearchDetail detail; 42 | private ComponentResearchList researchList; 43 | private DrawableResource globe; 44 | private List scoreText; 45 | private int listWidth = ModConfig.guiListWidth; 46 | 47 | public GuiTable(TileTable tile, InventoryPlayer inventory) { 48 | super(new ContainerTable(tile, inventory)); 49 | this.table = tile; 50 | data = table.getData(); 51 | fontRenderer = AdvancedFontRenderer.INSTANCE; 52 | AdvancedFontRenderer.INSTANCE.setUnicodeFlag(true); 53 | if (ModConfig.guiListAutoWidth) { 54 | int titleWidth = ResearchList.LIST.values().stream().map(Research::getTitle).mapToInt(fontRenderer::getStringWidth).max().orElse(0); 55 | listWidth = Math.max(listWidth, 40 + titleWidth); 56 | } 57 | } 58 | 59 | @Override 60 | public void initGui() { 61 | int guiDetailWidth; 62 | if (ModConfig.guiFullScreen) { 63 | xSize = width + 8; 64 | ySize = height + 8; 65 | guiDetailWidth = width - listWidth; 66 | } else { 67 | guiDetailWidth = ModConfig.guiDetailWidth; 68 | xSize = listWidth + guiDetailWidth + 8; 69 | ySize = ModConfig.guiHeight; 70 | } 71 | 72 | data = table.getData(); 73 | super.initGui(); 74 | ComponentPanel panel = new ComponentPanel(control, xSize, ySize); 75 | boolean showTabs = ResearchList.CATEGORIES.size() > 1; 76 | researchList = new ComponentResearchList(panel.control, listWidth, ySize - 8, 0, 0, 20, width, height, showTabs); 77 | // ResearchList.LIST.clear(); 78 | // int r = new Random().nextInt(6) + 1; 79 | // List conditions = new ArrayList<>(8); 80 | // conditions.add(new ConditionCrTStack(CraftTweakerMC.getOreDict("blockGlass").amount(1000))); 81 | // for (int i = 0; i < r; i++) 82 | // { 83 | // conditions.add(new ConditionCrTStack(CraftTweakerMC.getIItemStack(new ItemStack(Items.CLAY_BALL, 256)))); 84 | // } 85 | // ResearchList.LIST.add(new Research("hello", ResearchCategory.GENERAL, "hello", "������", 86 | // ImmutableSet.of("stageA", "stageB"), Collections.EMPTY_LIST, conditions, null)); 87 | if (!ResearchList.CATEGORIES.isEmpty()) { 88 | researchList.setCategory(ResearchList.CATEGORIES.get(0)); 89 | } 90 | if (showTabs) { 91 | guiDetailWidth -= ComponentResearchList.TAB_WIDTH; 92 | } 93 | Research displaying = null; 94 | if (detail != null) { 95 | displaying = detail.getResearch(); 96 | } 97 | detail = new ComponentResearchDetail(panel.control, guiDetailWidth, ySize - 8, researchList.left + listWidth, 0, width, height); 98 | detail.visible = false; 99 | detail.researching = table.getResearch(); 100 | if (displaying != null) { 101 | detail.setResearch(displaying, table.canComplete()); 102 | table.hasChanged = true; 103 | } else if (detail.researching != null) { 104 | detail.setResearch(detail.researching, table.canComplete()); 105 | table.hasChanged = true; 106 | } 107 | control.addComponent(panel); 108 | panel.control.addComponent(researchList); 109 | panel.control.addComponent(detail); 110 | 111 | if (ResearchTable.scoreFormattingText != null) { 112 | boolean failed = false; 113 | Integer[] values = new Integer[ResearchTable.scores.length]; 114 | int i = 0; 115 | NBTHelper helper = NBTHelper.of(data); 116 | for (String s : ResearchTable.scores) { 117 | values[i] = helper.getInt("score." + s, 0); 118 | ++i; 119 | } 120 | if (!failed) { 121 | String string = ResearchTable.scoreFormattingText; 122 | if (I18n.hasKey(string)) { 123 | string = I18n.format(ResearchTable.scoreFormattingText, (Object[]) values); 124 | } else { 125 | try { 126 | string = String.format(ResearchTable.scoreFormattingText, (Object[]) values); 127 | } catch (IllegalFormatException var5) { 128 | string = "Format error: " + string; 129 | } 130 | } 131 | scoreText = Arrays.asList(string.split("\\n")); 132 | globe = new DrawableResource(new ResourceLocation(ResearchTable.MODID, "textures/gui/globe.png"), 0, 0, 11, 10, 0, 0, 0, 0, 11, 10); 133 | } 134 | } 135 | } 136 | 137 | @Override 138 | protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { 139 | super.mouseClicked(mouseX, mouseY, mouseButton); 140 | } 141 | 142 | @Override 143 | protected void mouseReleased(int mouseX, int mouseY, int state) { 144 | super.mouseReleased(mouseX, mouseY, state); 145 | } 146 | 147 | @Override 148 | protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { 149 | } 150 | 151 | @Override 152 | public void drawScreen(int mouseX, int mouseY, float partialTicks) { 153 | if (!GuiScreen.isCtrlKeyDown()) { 154 | ticks += partialTicks; 155 | } 156 | if (table.hasChanged) { 157 | data = table.getData(); 158 | if (detail != null) { 159 | detail.researching = table.getResearch(); 160 | detail.updateResearching(table.canComplete()); 161 | researchList.setCategory(researchList.category); 162 | if (detail.getResearch() != null) { 163 | List progresses = detail.control.getComponents(ComponentResearchProgress.class); 164 | boolean flag = table.getResearch() == detail.getResearch(); 165 | for (int i = 0; i < progresses.size(); ++i) { 166 | ComponentResearchProgress progress = progresses.get(i); 167 | progress.setProgress(flag ? table.getProgress(i) : 0); 168 | progress.setResearching(flag); 169 | } 170 | } 171 | } 172 | table.hasChanged = false; 173 | } 174 | drawScreenInternal(mouseX, mouseY, partialTicks); 175 | if (globe != null && scoreText != null) { 176 | GlStateManager.color(1, 1, 1, 1); 177 | RenderHelper.enableGUIStandardItemLighting(); 178 | int x = (width + xSize) / 2 - 18; 179 | int y = (height + ySize) / 2 - 18; 180 | globe.draw(mc, x, y); 181 | if (isInRegion(x, y, x + 11, y + 11, mouseX, mouseY)) { 182 | drawHoveringText(scoreText, mouseX, mouseY); 183 | } 184 | } 185 | } 186 | 187 | private void drawScreenInternal(int mouseX, int mouseY, float partialTicks) { 188 | this.drawDefaultBackground(); 189 | control.drawScreen(mouseX, mouseY, partialTicks); 190 | super.drawScreen(mouseX, mouseY, partialTicks); 191 | if (tooltip != null && !tooltip.isEmpty()) { 192 | if (tooltipFont == null) { 193 | tooltipFont = fontRenderer; 194 | } 195 | drawHoveringText(tooltip, mouseX, mouseY, tooltipFont); 196 | } 197 | this.tooltip = null; 198 | this.tooltipFont = null; 199 | } 200 | 201 | public static boolean isInRegion(int left, int top, int right, int bottom, int x, int y) { 202 | return x >= left && x < right && y >= top && y < bottom; 203 | } 204 | 205 | @Override 206 | public int messageReceived(GuiControl control, Component component, NBTTagCompound data) { 207 | return 0; 208 | } 209 | 210 | @Override 211 | public int messageReceived(GuiControl control, Component component, int param1, int param2) { 212 | if (component.getClass() == ComponentButtonList.class) { 213 | if (!table.hasPermission(mc.player)) { 214 | return 0; 215 | } 216 | mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1.0F)); 217 | if (param1 == 0) // param1 == button id 218 | { 219 | if (table.getResearch() == detail.getResearch()) { 220 | PacketResearchChanged packet = new PacketResearchChanged(table.getPos(), table.getResearch(), Action.SUBMIT); 221 | NetworkChannel.INSTANCE.sendToServer(packet); 222 | } 223 | } else if (param1 == 1) // param1 == button id 224 | { 225 | if (table.getResearch() == null) // no research doing 226 | { 227 | if (detail.getResearch() != null) { 228 | PacketResearchChanged packet = new PacketResearchChanged(table.getPos(), detail.getResearch(), Action.START); 229 | NetworkChannel.INSTANCE.sendToServer(packet); 230 | return 0; 231 | } 232 | } else { 233 | if (detail.getResearch() == table.getResearch()) { 234 | Action action = table.canComplete() ? Action.COMPLETE : Action.STOP; 235 | if (action == Action.STOP && !GuiScreen.isShiftKeyDown()) { 236 | return 0; 237 | } 238 | PacketResearchChanged packet = new PacketResearchChanged(table.getPos(), table.getResearch(), action); 239 | NetworkChannel.INSTANCE.sendToServer(packet); 240 | return 0; 241 | } 242 | } 243 | } 244 | } else if (component.getClass() == ComponentResearchList.class) { 245 | if (detail != null) { 246 | detail.setResearch(researchList.researches.get(param1), table.canComplete()); // param1 == index 247 | table.hasChanged = true; 248 | } 249 | } 250 | return 0; 251 | } 252 | 253 | public void resetProgress() { 254 | if (detail == null) 255 | return; 256 | List components = detail.control.getComponents(ComponentResearchProgress.class); 257 | for (ComponentResearchProgress component : components) { 258 | component.resetRenderer(); 259 | } 260 | } 261 | 262 | @Override 263 | public void onGuiClosed() { 264 | researchList = null; 265 | detail = null; 266 | data = null; 267 | super.onGuiClosed(); 268 | } 269 | 270 | } 271 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/renderer/ConditionRenderer.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.renderer; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import javax.annotation.Nullable; 8 | 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.client.gui.FontRenderer; 11 | import net.minecraft.client.util.ITooltipFlag; 12 | import net.minecraftforge.fml.relauncher.Side; 13 | import net.minecraftforge.fml.relauncher.SideOnly; 14 | import snownee.researchtable.core.ICondition; 15 | import snownee.researchtable.plugin.forge.ConditionForgeEnergy; 16 | import snownee.researchtable.plugin.forge.RendererForgeEnergy; 17 | 18 | @SideOnly(Side.CLIENT) 19 | public abstract class ConditionRenderer { 20 | private static final Map MAP = new HashMap<>(); 21 | 22 | static { 23 | ConditionRenderer.register(ConditionForgeEnergy.class, new RendererForgeEnergy.Factory()); 24 | } 25 | 26 | public static void register(Class clazz, ConditionRendererFactory renderer) { 27 | MAP.put(clazz, renderer); 28 | } 29 | 30 | @Nullable 31 | public static ConditionRenderer get(T condition) { 32 | ConditionRendererFactory factory = MAP.get(condition.getClass()); 33 | if (factory != null) { 34 | return factory.get(condition); 35 | } 36 | return null; 37 | } 38 | 39 | public abstract void draw(Minecraft mc, int x, int y); 40 | 41 | public abstract String name(); 42 | 43 | public abstract String format(long number); 44 | 45 | public abstract FontRenderer getFont(); 46 | 47 | public abstract List getTooltip(ITooltipFlag flag); 48 | 49 | public static interface ConditionRendererFactory { 50 | ConditionRenderer get(T condition); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/client/renderer/EventShowItemCondition.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.client.renderer; 2 | 3 | import net.minecraft.item.ItemStack; 4 | import net.minecraft.util.NonNullList; 5 | import net.minecraftforge.fml.common.eventhandler.Event; 6 | 7 | public class EventShowItemCondition extends Event { 8 | public final NonNullList stacks; 9 | 10 | public EventShowItemCondition(NonNullList stacks) { 11 | this.stacks = stacks; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/command/CommandResearch.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.command; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | import net.minecraft.command.CommandBase; 9 | import net.minecraft.command.CommandException; 10 | import net.minecraft.command.ICommandSender; 11 | import net.minecraft.command.WrongUsageException; 12 | import net.minecraft.entity.player.EntityPlayerMP; 13 | import net.minecraft.server.MinecraftServer; 14 | import net.minecraft.util.math.BlockPos; 15 | import snownee.researchtable.ResearchTable; 16 | import snownee.researchtable.core.DataStorage; 17 | import snownee.researchtable.core.Research; 18 | import snownee.researchtable.core.ResearchList; 19 | 20 | public class CommandResearch extends CommandBase { 21 | 22 | @Override 23 | public String getName() { 24 | return ResearchTable.MODID; 25 | } 26 | 27 | @Override 28 | public String getUsage(ICommandSender sender) { 29 | return "commands." + getName() + ".usage"; 30 | } 31 | 32 | @Override 33 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 34 | if (args.length != 2 && args.length != 3) { 35 | throw new WrongUsageException(getUsage(sender)); 36 | } 37 | EntityPlayerMP player = getPlayer(server, sender, args[0]); 38 | boolean all = false; 39 | Collection researchs; 40 | if (args[1].equals("all")) { 41 | researchs = ResearchList.LIST.values(); 42 | } else { 43 | Optional result = ResearchList.find(args[1]); 44 | if (!result.isPresent()) { 45 | throw new CommandException("commands." + getName() + ".researchNotFound", args[1]); 46 | } 47 | Research research = result.get(); 48 | researchs = Collections.singletonList(research); 49 | } 50 | if (args.length == 2) { 51 | for (Research research : researchs) { 52 | notifyCommandListener(sender, this, "commands." + getName() + ".get", player.getName(), DataStorage.count(player.getGameProfile().getId(), research)); 53 | } 54 | } else { 55 | for (Research research : researchs) { 56 | int count = parseInt(args[2], 0); 57 | DataStorage.setCount(player.getGameProfile().getId(), research, count); 58 | notifyCommandListener(sender, this, "commands." + getName() + ".set", player.getName()); 59 | } 60 | } 61 | } 62 | 63 | @Override 64 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) { 65 | if (args.length == 1) { 66 | return getListOfStringsMatchingLastWord(args, server.getOnlinePlayerNames()); 67 | } 68 | if (args.length == 2) { 69 | Collection names = ResearchList.LIST.keySet(); 70 | return getListOfStringsMatchingLastWord(args, names); 71 | } 72 | return super.getTabCompletions(server, sender, args, targetPos); 73 | } 74 | 75 | @Override 76 | public int getRequiredPermissionLevel() { 77 | return 2; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/container/ContainerTable.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.container; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.entity.player.EntityPlayerMP; 5 | import net.minecraft.entity.player.InventoryPlayer; 6 | import net.minecraft.inventory.Container; 7 | import net.minecraft.inventory.IContainerListener; 8 | import snownee.researchtable.block.TileTable; 9 | 10 | public class ContainerTable extends Container { 11 | private final TileTable tile; 12 | private final InventoryPlayer inventory; 13 | 14 | public ContainerTable(TileTable tile, InventoryPlayer inventory) { 15 | this.tile = tile; 16 | this.inventory = inventory; 17 | } 18 | 19 | @Override 20 | public boolean canInteractWith(EntityPlayer playerIn) { 21 | if (tile.hasWorld()) { 22 | return playerIn.getDistanceSq(tile.getPos().getX() + 0.5D, tile.getPos().getY() + 0.5D, tile.getPos().getZ() + 0.5D) <= 64.0D; 23 | } else { 24 | return false; 25 | } 26 | } 27 | 28 | @Override 29 | public void detectAndSendChanges() { 30 | if (tile.hasChanged) { 31 | for (IContainerListener listener : listeners) { 32 | if (listener instanceof EntityPlayerMP) { 33 | ((EntityPlayerMP) listener).connection.sendPacket(tile.getUpdatePacket()); 34 | } 35 | } 36 | tile.hasChanged = false; // server 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/ConditionTypes.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import java.util.function.Supplier; 4 | 5 | import net.minecraft.item.ItemStack; 6 | import net.minecraftforge.fluids.FluidStack; 7 | 8 | public class ConditionTypes { 9 | private ConditionTypes() { 10 | } 11 | 12 | public static final Supplier> ITEM = () -> ItemStack.class; 13 | public static final Supplier> FLUID = () -> FluidStack.class; 14 | public static final Supplier> ENERGY = () -> Long.class; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/CriterionResearchCount.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.client.resources.I18n; 4 | import net.minecraft.entity.player.EntityPlayer; 5 | import net.minecraft.nbt.NBTTagCompound; 6 | import net.minecraft.util.text.TextFormatting; 7 | import net.minecraftforge.fml.relauncher.Side; 8 | import net.minecraftforge.fml.relauncher.SideOnly; 9 | import snownee.kiwi.util.Util; 10 | import snownee.researchtable.ResearchTable; 11 | 12 | public class CriterionResearchCount implements ICriterion { 13 | private final String id; 14 | private final int c; 15 | 16 | public CriterionResearchCount(String id, int count) { 17 | this.id = id; 18 | this.c = count; 19 | } 20 | 21 | @Override 22 | public boolean matches(EntityPlayer player, NBTTagCompound data) { 23 | return DataStorage.count(player.getGameProfile().getId(), id) < c; 24 | } 25 | 26 | @Override 27 | @SideOnly(Side.CLIENT) 28 | public String getFailingText(EntityPlayer player, NBTTagCompound data) { 29 | return I18n.format(ResearchTable.MODID + ".gui.maxCount", c, Util.color(0xFFFF0000) + c + TextFormatting.RESET); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/CriterionResearches.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import java.util.Collection; 4 | import java.util.Optional; 5 | 6 | import net.minecraft.client.resources.I18n; 7 | import net.minecraft.entity.player.EntityPlayer; 8 | import net.minecraft.nbt.NBTTagCompound; 9 | import net.minecraft.util.text.TextFormatting; 10 | import net.minecraftforge.fml.relauncher.Side; 11 | import net.minecraftforge.fml.relauncher.SideOnly; 12 | import snownee.kiwi.util.Util; 13 | import snownee.researchtable.ResearchTable; 14 | 15 | public class CriterionResearches implements ICriterion { 16 | private final Collection researches; 17 | private final int r; 18 | 19 | public CriterionResearches(Collection researches, int requirement) { 20 | this.r = requirement > 0 ? requirement : researches.size(); 21 | this.researches = researches; 22 | } 23 | 24 | @Override 25 | public boolean matches(EntityPlayer player, NBTTagCompound data) { 26 | int c = 0; 27 | for (String research : researches) { 28 | if (DataStorage.count(player.getGameProfile().getId(), research) > 0) { 29 | ++c; 30 | } 31 | } 32 | return c >= r; 33 | } 34 | 35 | @Override 36 | @SideOnly(Side.CLIENT) 37 | public String getFailingText(EntityPlayer player, NBTTagCompound data) { 38 | String string = ""; 39 | boolean first = true; 40 | for (String research : researches) { 41 | Optional result = ResearchList.find(research); 42 | if (!result.isPresent()) 43 | continue; 44 | if (!first) { 45 | string += Util.color(0) + ", "; 46 | } 47 | first = false; 48 | if (DataStorage.count(player.getGameProfile().getId(), research) == 0) { 49 | string += Util.color(0xFFFF0000); 50 | } 51 | string += result.get().getTitle(); 52 | } 53 | string += TextFormatting.RESET; 54 | if (r == researches.size()) { 55 | string = I18n.format(ResearchTable.MODID + ".gui.requiredResearch", string); 56 | } else { 57 | string = I18n.format(ResearchTable.MODID + ".gui.optionalResearch", string); 58 | string += I18n.format(ResearchTable.MODID + ".gui.of", r, researches.size()); 59 | } 60 | return string; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/CriterionScore.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.client.resources.I18n; 4 | import net.minecraft.entity.player.EntityPlayer; 5 | import net.minecraft.nbt.NBTTagCompound; 6 | import net.minecraftforge.fml.relauncher.Side; 7 | import net.minecraftforge.fml.relauncher.SideOnly; 8 | import snownee.kiwi.util.NBTHelper; 9 | 10 | public class CriterionScore implements ICriterion { 11 | private final String s; 12 | private final int min; 13 | private final int max; 14 | private final String failingText; 15 | 16 | public CriterionScore(String score, int min, int max, String failingText) { 17 | this.min = min; 18 | this.max = max; 19 | this.s = score; 20 | this.failingText = failingText; 21 | } 22 | 23 | @Override 24 | public boolean matches(EntityPlayer player, NBTTagCompound data) { 25 | int i = NBTHelper.of(data).getInt("score." + s, 0); 26 | return i >= min && i <= max; 27 | } 28 | 29 | @Override 30 | @SideOnly(Side.CLIENT) 31 | public String getFailingText(EntityPlayer player, NBTTagCompound data) { 32 | return I18n.format(failingText); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/DataStorage.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.Collection; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Set; 12 | import java.util.UUID; 13 | 14 | import javax.annotation.Nullable; 15 | 16 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 17 | import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry; 18 | import it.unimi.dsi.fastutil.objects.Object2IntMaps; 19 | import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; 20 | import net.minecraft.entity.player.EntityPlayer; 21 | import net.minecraft.entity.player.EntityPlayerMP; 22 | import net.minecraft.nbt.CompressedStreamTools; 23 | import net.minecraft.nbt.NBTBase; 24 | import net.minecraft.nbt.NBTTagCompound; 25 | import net.minecraft.nbt.NBTTagList; 26 | import net.minecraft.world.WorldServer; 27 | import net.minecraft.world.storage.ThreadedFileIOBase; 28 | import net.minecraftforge.common.util.Constants; 29 | import net.minecraftforge.common.util.FakePlayer; 30 | import net.minecraftforge.event.world.WorldEvent; 31 | import net.minecraftforge.fml.common.FMLCommonHandler; 32 | import net.minecraftforge.fml.common.Mod.EventBusSubscriber; 33 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 34 | import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; 35 | import snownee.researchtable.ResearchTable; 36 | import snownee.researchtable.core.team.TeamHelper; 37 | import snownee.researchtable.network.NetworkChannel; 38 | import snownee.researchtable.network.PacketSyncClient; 39 | 40 | @EventBusSubscriber(modid = ResearchTable.MODID) 41 | public class DataStorage { 42 | private static DataStorage INSTANCE; 43 | private final WorldServer world; 44 | private static final Map> records = new HashMap<>(); 45 | private static final Map> players = new HashMap<>(); 46 | private static boolean changed = false; 47 | public static Object2IntMap clientData; 48 | 49 | public DataStorage(WorldServer world) { 50 | this.world = world; 51 | load(); 52 | } 53 | 54 | private void load() { 55 | records.clear(); 56 | players.clear(); 57 | changed = false; 58 | clientData = null; 59 | 60 | File folder = new File(world.getSaveHandler().getWorldDirectory(), "data/"); 61 | File file = new File(folder, ResearchTable.MODID + ".dat"); 62 | NBTTagCompound data = null; 63 | 64 | if (file.exists() && file.isFile()) { 65 | try (InputStream stream = new FileInputStream(file)) { 66 | data = CompressedStreamTools.readCompressed(stream); 67 | } catch (Exception ex1) { 68 | try { 69 | data = CompressedStreamTools.read(file); 70 | } catch (Exception ex2) { 71 | ex2.printStackTrace(); 72 | } 73 | } 74 | } 75 | if (data == null) { 76 | return; 77 | } 78 | 79 | int format = data.getInteger("__v"); 80 | if (format == 0) { 81 | for (String player : data.getKeySet()) { 82 | if (data.hasKey(player, Constants.NBT.TAG_COMPOUND)) { 83 | NBTTagCompound compound = data.getCompoundTag(player); 84 | Object2IntMap researches = readPlayerData(compound); 85 | if (!researches.isEmpty()) { 86 | players.put(player, researches); 87 | } 88 | } 89 | } 90 | } else if (format == 1) { 91 | NBTTagCompound playersData = data.getCompoundTag("oldRecords"); 92 | for (String player : playersData.getKeySet()) { 93 | if (data.hasKey(player, Constants.NBT.TAG_COMPOUND)) { 94 | NBTTagCompound compound = playersData.getCompoundTag(player); 95 | Object2IntMap researches = readPlayerData(compound); 96 | if (!researches.isEmpty()) { 97 | players.put(player, researches); 98 | } 99 | } 100 | } 101 | 102 | NBTTagList recordsData = data.getTagList("records", Constants.NBT.TAG_COMPOUND); 103 | for (NBTBase raw : recordsData) { 104 | NBTTagCompound recordData = (NBTTagCompound) raw; 105 | UUID k = recordData.getUniqueId("k"); 106 | Object2IntMap v = readPlayerData(recordData.getCompoundTag("v")); 107 | if (!v.isEmpty()) { 108 | records.put(k, v); 109 | } 110 | } 111 | } else { 112 | throw new RuntimeException("Unsupported format version"); 113 | } 114 | } 115 | 116 | private void save() { 117 | if (!changed) { 118 | return; 119 | } 120 | NBTTagCompound data = new NBTTagCompound(); 121 | data.setInteger("__v", 1); 122 | 123 | NBTTagList playersDataList = new NBTTagList(); 124 | players.forEach((player, researches) -> { 125 | if (!researches.isEmpty()) { 126 | NBTTagCompound playersData = new NBTTagCompound(); 127 | playersData.setTag(player, writePlayerData(researches)); 128 | playersDataList.appendTag(playersData); 129 | } 130 | }); 131 | if (!playersDataList.isEmpty()) { 132 | data.setTag("oldRecords", playersDataList); 133 | } 134 | 135 | NBTTagList recordsDataList = new NBTTagList(); 136 | records.forEach((k, v) -> { 137 | if (!v.isEmpty()) { 138 | NBTTagCompound recordsData = new NBTTagCompound(); 139 | recordsData.setUniqueId("k", k); 140 | recordsData.setTag("v", writePlayerData(v)); 141 | recordsDataList.appendTag(recordsData); 142 | } 143 | }); 144 | if (!recordsDataList.isEmpty()) { 145 | data.setTag("records", recordsDataList); 146 | } 147 | 148 | File folder = new File(world.getSaveHandler().getWorldDirectory(), "data/"); 149 | File file = new File(folder, ResearchTable.MODID + ".dat"); 150 | ThreadedFileIOBase.getThreadedIOInstance().queueIO(() -> { 151 | try { 152 | if (!file.exists()) { 153 | if (!folder.exists()) { 154 | folder.mkdirs(); 155 | } 156 | file.createNewFile(); 157 | } 158 | OutputStream stream = new FileOutputStream(file); 159 | CompressedStreamTools.writeCompressed(data, stream); 160 | changed = false; 161 | } catch (Exception e) { 162 | e.printStackTrace(); 163 | } 164 | return false; 165 | }); 166 | } 167 | 168 | public static boolean loaded() { 169 | return INSTANCE != null; 170 | } 171 | 172 | // TODO: register event 173 | public static int complete(UUID uuid, Research research) { 174 | return setCount(uuid, research, count(uuid, research) + 1); 175 | } 176 | 177 | public static int setCount(UUID uuid, Research research, int count) { 178 | if (!loaded()) { 179 | return -1; 180 | } 181 | Object2IntMap researches = getRecords(uuid); 182 | if (count > 0) { 183 | researches.put(research.getName(), count); 184 | } else { 185 | researches.remove(research.getName()); 186 | } 187 | changed = true; 188 | syncClientAllMembers(uuid); 189 | return count; 190 | } 191 | 192 | public static Object2IntMap getRecords(UUID uuid) { 193 | if (!loaded()) { 194 | return Object2IntMaps.EMPTY_MAP; 195 | } 196 | UUID owner = TeamHelper.provider.getOwner(uuid); 197 | if (owner != null) { 198 | return records.computeIfAbsent(owner, $ -> new Object2IntOpenHashMap<>()); 199 | } else { 200 | return records.computeIfAbsent(uuid, $ -> new Object2IntOpenHashMap<>()); 201 | } 202 | } 203 | 204 | public static int count(UUID uuid, String research) { 205 | if (loaded()) { 206 | return getRecords(uuid).getInt(research); 207 | } else if (clientData != null) { 208 | return clientData.getInt(research); 209 | } 210 | return 0; 211 | } 212 | 213 | public static int count(UUID uuid, Research research) { 214 | return count(uuid, research.getName()); 215 | } 216 | 217 | public static boolean hasAllOf(UUID uuid, Collection researches) { 218 | for (String research : researches) { 219 | if (count(uuid, research) == 0) 220 | return false; 221 | } 222 | return true; 223 | } 224 | 225 | @SubscribeEvent 226 | public static void onWorldLoaded(WorldEvent.Load event) { 227 | if (event.getWorld().provider.getDimension() == 0 && !event.getWorld().isRemote) { 228 | INSTANCE = new DataStorage((WorldServer) event.getWorld()); 229 | } 230 | } 231 | 232 | @SubscribeEvent 233 | public static void onWorldSaved(WorldEvent.Save event) { 234 | if (loaded() && event.getWorld() == INSTANCE.world) { 235 | INSTANCE.save(); 236 | } 237 | } 238 | 239 | @SubscribeEvent 240 | public static void onPlayerLoggedIn(PlayerLoggedInEvent event) { 241 | if (!loaded() || event.player instanceof FakePlayer) { 242 | return; 243 | } 244 | String name = event.player.getName(); 245 | UUID uuid = event.player.getGameProfile().getId(); 246 | if (players.containsKey(name)) { 247 | Object2IntMap data = players.get(name); 248 | players.remove(name); 249 | mergeProgress(data, uuid); 250 | syncClientAllMembers(uuid); 251 | } else { 252 | syncClient(uuid); 253 | } 254 | } 255 | 256 | public static void mergeProgress(Object2IntMap from, UUID uuid) { 257 | Object2IntMap to = getRecords(uuid); 258 | for (Entry entry : from.object2IntEntrySet()) { 259 | int fromInt = entry.getIntValue(); 260 | int toInt = to.getInt(entry.getKey()); 261 | if (fromInt > toInt) { 262 | to.put(entry.getKey(), fromInt); 263 | } 264 | } 265 | changed = true; 266 | } 267 | 268 | private static void syncClientAllMembers(UUID uuid) { 269 | TeamHelper.provider.getMembers(uuid).forEach(DataStorage::syncClient); 270 | } 271 | 272 | private static void syncClient(UUID uuid) { 273 | EntityPlayer player = getPlayer(uuid); 274 | if (player == null) { 275 | return; 276 | } 277 | if (player instanceof EntityPlayerMP && !(player instanceof FakePlayer)) { 278 | Object2IntMap data = getRecords(player.getGameProfile().getId()); 279 | if (!data.isEmpty()) { 280 | NetworkChannel.INSTANCE.sendToPlayer(new PacketSyncClient(data), (EntityPlayerMP) player); 281 | } 282 | } 283 | } 284 | 285 | public static Object2IntMap readPlayerData(NBTTagCompound data) { 286 | Set keySet = data.getKeySet(); 287 | Object2IntMap researches = new Object2IntOpenHashMap<>(keySet.size()); 288 | for (String research : keySet) { 289 | if (data.hasKey(research, Constants.NBT.TAG_INT)) { 290 | int count = data.getInteger(research); 291 | if (count > 0) { 292 | researches.put(research, count); 293 | } 294 | } 295 | } 296 | return researches; 297 | } 298 | 299 | public static NBTTagCompound writePlayerData(Object2IntMap map) { 300 | NBTTagCompound data = new NBTTagCompound(); 301 | map.forEach((research, count) -> { 302 | data.setInteger(research, count); 303 | }); 304 | return data; 305 | } 306 | 307 | @Nullable 308 | public static EntityPlayerMP getPlayer(UUID uuid) { 309 | return FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerByUUID(uuid); 310 | } 311 | 312 | public static void onPlayerAdd(UUID uuid, UUID owner) { 313 | mergeProgress(records.getOrDefault(uuid, Object2IntMaps.EMPTY_MAP), owner); 314 | records.remove(uuid); 315 | syncClientAllMembers(owner); 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/EventOpenTable.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraftforge.event.entity.player.PlayerEvent; 5 | import net.minecraftforge.fml.common.eventhandler.Cancelable; 6 | import snownee.researchtable.block.TileTable; 7 | 8 | @Cancelable 9 | public class EventOpenTable extends PlayerEvent { 10 | private final TileTable table; 11 | 12 | public EventOpenTable(EntityPlayer player, TileTable table) { 13 | super(player); 14 | this.table = table; 15 | } 16 | 17 | public TileTable getTable() { 18 | return table; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/ICondition.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import java.util.function.Supplier; 4 | 5 | public interface ICondition { 6 | Supplier> getMatchType(); 7 | 8 | long matches(T e); 9 | 10 | long getGoal(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/ICriterion.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.nbt.NBTTagCompound; 5 | import net.minecraftforge.fml.relauncher.Side; 6 | import net.minecraftforge.fml.relauncher.SideOnly; 7 | 8 | public interface ICriterion { 9 | boolean matches(EntityPlayer player, NBTTagCompound data); 10 | 11 | @SideOnly(Side.CLIENT) 12 | String getFailingText(EntityPlayer player, NBTTagCompound data); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/IReward.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.util.math.BlockPos; 5 | import net.minecraft.world.World; 6 | 7 | public interface IReward { 8 | void earn(World world, BlockPos pos, EntityPlayer player); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/Research.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import javax.annotation.Nullable; 8 | 9 | import net.minecraft.client.resources.I18n; 10 | import net.minecraft.entity.player.EntityPlayer; 11 | import net.minecraft.init.Blocks; 12 | import net.minecraft.item.ItemStack; 13 | import net.minecraft.nbt.NBTTagCompound; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.world.World; 16 | import net.minecraftforge.fml.relauncher.Side; 17 | import net.minecraftforge.fml.relauncher.SideOnly; 18 | 19 | public class Research { 20 | private static final ItemStack DEFAULT_ICON = new ItemStack(Blocks.GRASS); 21 | 22 | private final String name; 23 | private final ResearchCategory category; 24 | private final String title; 25 | private final String description; 26 | @Nullable 27 | private final List icons; 28 | private final List conditions; 29 | private final Collection criteria; 30 | private final Collection triggers; 31 | private final Collection rewards; 32 | 33 | public Research(String name, ResearchCategory category, String title, String description, Collection criteria, Collection triggers, Collection rewards, List conditions, @Nullable List icons) { 34 | this.name = name; 35 | this.category = category; 36 | this.title = title; 37 | this.description = description; 38 | this.criteria = criteria; 39 | this.triggers = triggers; 40 | this.rewards = rewards; 41 | this.conditions = conditions; 42 | this.icons = icons; 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public ResearchCategory getCategory() { 50 | return category; 51 | } 52 | 53 | public String getTitleRaw() { 54 | return title; 55 | } 56 | 57 | @SideOnly(Side.CLIENT) 58 | public String getTitle() { 59 | return I18n.hasKey(title) ? I18n.format(title) : title; 60 | } 61 | 62 | public String getDescriptionRaw() { 63 | return description; 64 | } 65 | 66 | @SideOnly(Side.CLIENT) 67 | public String getDescription() { 68 | return I18n.hasKey(description) ? I18n.format(description) : description; 69 | } 70 | 71 | public ItemStack getIcon() { 72 | if (icons == null || icons.isEmpty()) { 73 | return DEFAULT_ICON; 74 | } else { 75 | return icons.get(0); 76 | } 77 | } 78 | 79 | public List getConditions() { 80 | return Collections.unmodifiableList(conditions); 81 | } 82 | 83 | public boolean canResearch(EntityPlayer player, NBTTagCompound data) { 84 | return criteria.stream().allMatch(c -> c.matches(player, data)); 85 | } 86 | 87 | public Collection getCriteria() { 88 | return Collections.unmodifiableCollection(criteria); 89 | } 90 | 91 | public Collection getTriggers() { 92 | return Collections.unmodifiableCollection(triggers); 93 | } 94 | 95 | public void complete(World world, BlockPos pos, EntityPlayer player) { 96 | rewards.forEach(e -> e.earn(world, pos, player)); 97 | } 98 | 99 | @Override 100 | public String toString() { 101 | return "Research@" + getName(); 102 | } 103 | 104 | public void start(World world, BlockPos pos, EntityPlayer player) { 105 | triggers.forEach(r -> r.earn(world, pos, player)); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/ResearchCategory.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.item.ItemStack; 4 | 5 | public class ResearchCategory { 6 | public final ItemStack icon; 7 | public final String nameKey; 8 | 9 | public ResearchCategory(ItemStack icon, String nameKey) { 10 | this.icon = icon; 11 | this.nameKey = nameKey; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/ResearchList.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | 7 | import com.google.common.collect.Lists; 8 | import com.google.common.collect.Maps; 9 | 10 | public final class ResearchList { 11 | public static final List CATEGORIES = Lists.newArrayList(); 12 | public static final Map LIST = Maps.newLinkedHashMap(); 13 | 14 | private ResearchList() { 15 | } 16 | 17 | public static synchronized boolean add(Research research) { 18 | if (LIST.containsKey(research.getName())) { 19 | return false; 20 | } 21 | if (!CATEGORIES.contains(research.getCategory())) { 22 | CATEGORIES.add(research.getCategory()); 23 | } 24 | LIST.put(research.getName(), research); 25 | return true; 26 | } 27 | 28 | public static Optional find(String name) { 29 | return Optional.ofNullable(ResearchList.LIST.get(name)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/RewardExecute.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.command.ICommandSender; 4 | import net.minecraft.entity.Entity; 5 | import net.minecraft.entity.player.EntityPlayer; 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.Vec3d; 9 | import net.minecraft.world.World; 10 | import snownee.researchtable.ModConfig; 11 | 12 | import javax.annotation.Nullable; 13 | 14 | public class RewardExecute implements IReward { 15 | private final String[] commands; 16 | 17 | public RewardExecute(String... commands) { 18 | this.commands = commands; 19 | } 20 | 21 | @Override 22 | public void earn(World world, BlockPos pos, EntityPlayer player) { 23 | // Use player entity as ICommandSender directly if non-privileged mode is enabled. 24 | // Used for a slightly better compatibility with permission management systems like FTBUtils. 25 | ICommandSender sender = ModConfig.nonPrivilegedMode ? player : new PrivilegedPlayer(player); 26 | for (String command : commands) { 27 | player.getServer().getCommandManager().executeCommand(sender, command); 28 | } 29 | } 30 | 31 | static final class PrivilegedPlayer implements ICommandSender { 32 | private final EntityPlayer player; 33 | 34 | PrivilegedPlayer(EntityPlayer player) { 35 | this.player = player; 36 | } 37 | 38 | @Override 39 | public String getName() { 40 | return player.getName(); 41 | } 42 | 43 | @Override 44 | public boolean canUseCommand(int permLevel, String commandName) { 45 | return permLevel <= 2; 46 | } 47 | 48 | @Override 49 | public World getEntityWorld() { 50 | return player.getEntityWorld(); 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public MinecraftServer getServer() { 56 | return player.getServer(); 57 | } 58 | 59 | @Override 60 | public BlockPos getPosition() { 61 | return player.getPosition(); 62 | } 63 | 64 | @Override 65 | public Vec3d getPositionVector() { 66 | return player.getPositionVector(); 67 | } 68 | 69 | @Override 70 | public Entity getCommandSenderEntity() { 71 | return player; 72 | } 73 | 74 | @Override 75 | public boolean sendCommandFeedback() { 76 | return false; 77 | } 78 | 79 | /*@Override 80 | public void sendMessage(ITextComponent component) 81 | { 82 | // TODO Instead of spamming message in chat window, can we log it for debugging purpose? 83 | }*/ 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/RewardItems.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.util.NonNullList; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.world.World; 8 | import net.minecraftforge.items.ItemHandlerHelper; 9 | 10 | public class RewardItems implements IReward { 11 | private final NonNullList items; 12 | 13 | public RewardItems(NonNullList items) { 14 | this.items = items; 15 | } 16 | 17 | @Override 18 | public void earn(World world, BlockPos pos, EntityPlayer player) { 19 | for (ItemStack item : items) 20 | ItemHandlerHelper.giveItemToPlayer(player, item); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/team/TeamHelper.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core.team; 2 | 3 | import java.util.UUID; 4 | 5 | import javax.annotation.Nonnull; 6 | 7 | import net.minecraftforge.fml.common.Loader; 8 | import snownee.researchtable.core.DataStorage; 9 | import snownee.researchtable.plugin.togetherforever.TeamProviderTF; 10 | 11 | public class TeamHelper { 12 | static { 13 | if (Loader.isModLoaded("togetherforever")) { 14 | provider = TeamProviderTF.INSTANCE; 15 | } else { 16 | provider = TeamProvider.Stub.INSTANCE; 17 | } 18 | } 19 | 20 | @Nonnull 21 | public static TeamProvider provider; 22 | 23 | public static void onPlayerAdd(UUID uuid, UUID owner) { 24 | DataStorage.onPlayerAdd(owner, owner); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/core/team/TeamProvider.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.core.team; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.UUID; 6 | 7 | import javax.annotation.Nullable; 8 | 9 | public interface TeamProvider { 10 | @Nullable 11 | UUID getOwner(UUID player); 12 | 13 | Collection getMembers(UUID player); 14 | 15 | @Nullable 16 | String getTeamName(UUID player); 17 | 18 | public static enum Stub implements TeamProvider { 19 | INSTANCE; 20 | 21 | @Override 22 | public UUID getOwner(UUID player) { 23 | return null; 24 | } 25 | 26 | @Override 27 | public Collection getMembers(UUID player) { 28 | return Collections.singleton(player); 29 | } 30 | 31 | @Override 32 | public String getTeamName(UUID player) { 33 | return null; 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/network/GuiHandler.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.network; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.tileentity.TileEntity; 5 | import net.minecraft.util.math.BlockPos; 6 | import net.minecraft.world.World; 7 | import net.minecraftforge.fml.common.network.IGuiHandler; 8 | import net.minecraftforge.fml.relauncher.Side; 9 | import net.minecraftforge.fml.relauncher.SideOnly; 10 | import snownee.researchtable.block.TileTable; 11 | import snownee.researchtable.client.gui.GuiTable; 12 | import snownee.researchtable.container.ContainerTable; 13 | 14 | public class GuiHandler implements IGuiHandler { 15 | 16 | @Override 17 | public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { 18 | if (ID == 0) { 19 | TileEntity tile = world.getTileEntity(new BlockPos(x, y, z)); 20 | if (tile instanceof TileTable) { 21 | return new ContainerTable((TileTable) tile, player.inventory); 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | @Override 28 | @SideOnly(Side.CLIENT) 29 | public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { 30 | if (ID == 0) { 31 | TileEntity tile = world.getTileEntity(new BlockPos(x, y, z)); 32 | if (tile instanceof TileTable) { 33 | return new GuiTable((TileTable) tile, player.inventory); 34 | } 35 | } 36 | return null; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/network/NetworkChannel.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.network; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; 6 | import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 7 | import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; 8 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.client.entity.EntityPlayerSP; 11 | import net.minecraft.entity.player.EntityPlayerMP; 12 | import net.minecraft.network.NetHandlerPlayServer; 13 | import net.minecraft.network.PacketBuffer; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraftforge.fml.common.FMLCommonHandler; 16 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 17 | import net.minecraftforge.fml.common.network.FMLEventChannel; 18 | import net.minecraftforge.fml.common.network.FMLNetworkEvent; 19 | import net.minecraftforge.fml.common.network.NetworkRegistry; 20 | import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; 21 | import net.minecraftforge.fml.relauncher.Side; 22 | import net.minecraftforge.fml.relauncher.SideOnly; 23 | import snownee.kiwi.Kiwi; 24 | import snownee.kiwi.network.PacketMod; 25 | 26 | public final class NetworkChannel { 27 | public static final NetworkChannel INSTANCE = new NetworkChannel(); 28 | 29 | private final Object2IntMap> mapping = new Object2IntArrayMap<>(); 30 | private final Int2ObjectMap> mappingReverse = new Int2ObjectArrayMap<>(); 31 | private int nextIndex = 0; 32 | private final FMLEventChannel channel; 33 | 34 | private NetworkChannel() { 35 | (channel = NetworkRegistry.INSTANCE.newEventDrivenChannel(Kiwi.MODID)).register(this); 36 | } 37 | 38 | @SubscribeEvent 39 | public void onServerPacketIncoming(FMLNetworkEvent.ServerCustomPacketEvent event) { 40 | handleOnServer(decodeData(event.getPacket().payload()), ((NetHandlerPlayServer) event.getHandler()).player); 41 | } 42 | 43 | @SideOnly(Side.CLIENT) 44 | @SubscribeEvent 45 | public void onClientPacketIncoming(FMLNetworkEvent.ClientCustomPacketEvent event) { 46 | handleOnClient(decodeData(event.getPacket().payload()), Minecraft.getMinecraft().player); 47 | } 48 | 49 | public void sendToAll(PacketMod packet) { 50 | channel.sendToAll(new FMLProxyPacket(new PacketBuffer(unpack(packet)), Kiwi.MODID)); 51 | } 52 | 53 | public void sendToAllTracking(PacketMod packet, int dim, BlockPos pos) { 54 | channel.sendToAllTracking(new FMLProxyPacket(new PacketBuffer(unpack(packet)), Kiwi.MODID), new NetworkRegistry.TargetPoint(dim, pos.getX(), pos.getY(), pos.getZ(), 4)); 55 | } 56 | 57 | public void sendToAllAround(PacketMod packet, int dim, BlockPos pos) { 58 | sendToAllAround(packet, dim, pos.getX(), pos.getY(), pos.getZ(), 16D); 59 | } 60 | 61 | public void sendToAllAround(PacketMod packet, int dim, double x, double y, double z, double range) { 62 | channel.sendToAllAround(new FMLProxyPacket(new PacketBuffer(unpack(packet)), Kiwi.MODID), new NetworkRegistry.TargetPoint(dim, x, y, z, range)); 63 | } 64 | 65 | public void sendToDimension(PacketMod packet, int dim) { 66 | channel.sendToDimension(new FMLProxyPacket(new PacketBuffer(unpack(packet)), Kiwi.MODID), dim); 67 | } 68 | 69 | public void sendToPlayer(PacketMod packet, EntityPlayerMP player) { 70 | channel.sendTo(new FMLProxyPacket(new PacketBuffer(unpack(packet)), Kiwi.MODID), player); 71 | } 72 | 73 | public void sendToServer(PacketMod packet) { 74 | channel.sendToServer(new FMLProxyPacket(new PacketBuffer(unpack(packet)), Kiwi.MODID)); 75 | } 76 | 77 | public void register(Class klass) { 78 | mapping.put(klass, nextIndex); 79 | mappingReverse.put(nextIndex, klass); 80 | nextIndex++; 81 | } 82 | 83 | private int getPacketIndex(Class klass) { 84 | return mapping.getInt(klass); 85 | } 86 | 87 | private PacketMod getByIndex(int index) { 88 | try { 89 | return mappingReverse.get(index).newInstance(); 90 | } catch (Exception e) { 91 | return null; 92 | } 93 | } 94 | 95 | private PacketMod decodeData(ByteBuf buffer) { 96 | final int index = buffer.readInt(); 97 | PacketMod packet = this.getByIndex(index); 98 | if (packet == null) { 99 | Kiwi.logger.error("Receiving malformed packet"); 100 | return null; 101 | } 102 | packet.readDataFrom(buffer); 103 | return packet; 104 | } 105 | 106 | @SideOnly(Side.CLIENT) 107 | private void handleOnClient(PacketMod packet, EntityPlayerSP player) { 108 | Minecraft.getMinecraft().addScheduledTask(() -> { 109 | try { 110 | packet.handleClient(player); 111 | } catch (Exception e) { 112 | Kiwi.logger.catching(e); 113 | } 114 | }); 115 | } 116 | 117 | private void handleOnServer(PacketMod packet, EntityPlayerMP player) { 118 | FMLCommonHandler.instance().getMinecraftServerInstance().addScheduledTask(() -> { 119 | try { 120 | packet.handleServer(player); 121 | } catch (Exception e) { 122 | Kiwi.logger.catching(e); 123 | } 124 | }); 125 | } 126 | 127 | private ByteBuf unpack(PacketMod packet) { 128 | ByteBuf buffer = Unpooled.buffer(); 129 | buffer.writeInt(this.getPacketIndex(packet.getClass())); 130 | try { 131 | packet.writeDataTo(buffer); 132 | } catch (Exception e) { 133 | Kiwi.logger.catching(e); 134 | } 135 | return buffer; 136 | } 137 | } -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/network/PacketResearchChanged.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.network; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import net.minecraft.client.entity.EntityPlayerSP; 5 | import net.minecraft.entity.player.EntityPlayerMP; 6 | import net.minecraft.tileentity.TileEntity; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraftforge.fml.common.network.ByteBufUtils; 9 | import net.minecraftforge.fml.relauncher.Side; 10 | import net.minecraftforge.fml.relauncher.SideOnly; 11 | import snownee.kiwi.network.PacketMod; 12 | import snownee.researchtable.block.TileTable; 13 | import snownee.researchtable.core.Research; 14 | import snownee.researchtable.core.ResearchList; 15 | 16 | public class PacketResearchChanged implements PacketMod { 17 | private BlockPos pos; 18 | private Research research; 19 | private Action action; 20 | 21 | public PacketResearchChanged() { 22 | } 23 | 24 | public PacketResearchChanged(BlockPos pos, Research research, Action action) { 25 | this.pos = pos; 26 | this.research = research; 27 | this.action = action; 28 | } 29 | 30 | @Override 31 | @SideOnly(Side.CLIENT) 32 | public void handleClient(EntityPlayerSP player) { 33 | } 34 | 35 | @Override 36 | public void handleServer(EntityPlayerMP player) { 37 | if (player.getDistanceSq(pos) > 100 || player.world.isBlockLoaded(pos)) 38 | return; 39 | TileEntity tile = player.world.getTileEntity(pos); 40 | if (tile instanceof TileTable) { 41 | TileTable table = (TileTable) tile; 42 | if (!table.hasPermission(player)) { 43 | return; 44 | } 45 | switch (action) { 46 | case START: 47 | if (!research.canResearch(player, table.getData())) { 48 | return; 49 | } 50 | if (table.getResearch() == null && research != null) { 51 | research.start(player.world, pos, player); 52 | table.setResearch(research); 53 | } 54 | break; 55 | case STOP: 56 | if (table.getResearch() == research && !table.canComplete()) { 57 | table.setResearch(null); 58 | } 59 | break; 60 | case COMPLETE: 61 | if (table.getResearch() == research && table.canComplete()) { 62 | table.complete(player); 63 | } 64 | break; 65 | case SUBMIT: 66 | if (table.getResearch() == research && !table.canComplete()) { 67 | table.submit(player); 68 | } 69 | break; 70 | } 71 | table.hasChanged = true; // server 72 | } 73 | } 74 | 75 | @Override 76 | public void readDataFrom(ByteBuf buf) { 77 | int x = buf.readInt(); 78 | int y = buf.readInt(); 79 | int z = buf.readInt(); 80 | pos = new BlockPos(x, y, z); 81 | research = ResearchList.find(ByteBufUtils.readUTF8String(buf)).orElseGet(() -> null); 82 | action = Action.values()[buf.readByte() % 4]; 83 | } 84 | 85 | @Override 86 | public void writeDataTo(ByteBuf buf) { 87 | buf.writeInt(pos.getX()); 88 | buf.writeInt(pos.getY()); 89 | buf.writeInt(pos.getZ()); 90 | ByteBufUtils.writeUTF8String(buf, research.getName()); 91 | buf.writeByte(action.ordinal()); 92 | } 93 | 94 | public enum Action { 95 | START, STOP, COMPLETE, SUBMIT 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/network/PacketSyncClient.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.network; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 5 | import net.minecraft.client.entity.EntityPlayerSP; 6 | import net.minecraft.entity.player.EntityPlayerMP; 7 | import net.minecraftforge.fml.common.network.ByteBufUtils; 8 | import net.minecraftforge.fml.relauncher.Side; 9 | import net.minecraftforge.fml.relauncher.SideOnly; 10 | import snownee.kiwi.network.PacketMod; 11 | import snownee.researchtable.core.DataStorage; 12 | 13 | public class PacketSyncClient implements PacketMod { 14 | private Object2IntMap map; 15 | 16 | public PacketSyncClient() { 17 | } 18 | 19 | public PacketSyncClient(Object2IntMap map) { 20 | this.map = map; 21 | } 22 | 23 | @Override 24 | @SideOnly(Side.CLIENT) 25 | public void handleClient(EntityPlayerSP player) { 26 | DataStorage.clientData = map; 27 | } 28 | 29 | @Override 30 | public void handleServer(EntityPlayerMP player) { 31 | } 32 | 33 | @Override 34 | public void readDataFrom(ByteBuf buf) { 35 | map = DataStorage.readPlayerData(ByteBufUtils.readTag(buf)); 36 | } 37 | 38 | @Override 39 | public void writeDataTo(ByteBuf buf) { 40 | ByteBufUtils.writeTag(buf, DataStorage.writePlayerData(map)); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/ConditionCrTItem.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import java.util.function.Supplier; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | import crafttweaker.api.item.IIngredient; 8 | import crafttweaker.api.minecraft.CraftTweakerMC; 9 | import net.minecraft.item.ItemStack; 10 | import snownee.researchtable.core.ConditionTypes; 11 | import snownee.researchtable.core.ICondition; 12 | 13 | public class ConditionCrTItem implements ICondition { 14 | final IIngredient ingredient; 15 | final long count; 16 | @Nullable 17 | String customName; 18 | 19 | public ConditionCrTItem(IIngredient ingredient) { 20 | this(ingredient, ingredient.getAmount()); 21 | } 22 | 23 | public ConditionCrTItem(IIngredient ingredient, long count) { 24 | this.count = count; 25 | this.ingredient = ingredient.amount(1); 26 | } 27 | 28 | @Override 29 | public long matches(ItemStack e) { 30 | if (!e.isEmpty() && ingredient.matches(CraftTweakerMC.getIItemStack(e).amount(1))) { 31 | return e.getCount(); 32 | } 33 | return 0; 34 | } 35 | 36 | @Override 37 | public long getGoal() { 38 | return count; 39 | } 40 | 41 | @Override 42 | public Supplier> getMatchType() { 43 | return ConditionTypes.ITEM; 44 | } 45 | 46 | public ConditionCrTItem setCustomName(String name) { 47 | customName = name; 48 | return this; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/ConditionCrTLiquid.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import java.util.function.Supplier; 4 | 5 | import crafttweaker.api.liquid.ILiquidStack; 6 | import net.minecraftforge.fluids.FluidStack; 7 | import snownee.researchtable.core.ConditionTypes; 8 | import snownee.researchtable.core.ICondition; 9 | 10 | public class ConditionCrTLiquid implements ICondition { 11 | final FluidStack fluid; 12 | final long count; 13 | 14 | public ConditionCrTLiquid(ILiquidStack ingredient) { 15 | this(ingredient, ingredient.getAmount()); 16 | } 17 | 18 | public ConditionCrTLiquid(ILiquidStack ingredient, long count) { 19 | this.count = count; 20 | Object raw = ingredient.withAmount(1).getInternal(); 21 | if (!(raw instanceof FluidStack)) // FluidStack does not have final! 22 | { 23 | throw new IllegalArgumentException("Ingredient is not liquid: " + ingredient); 24 | } 25 | this.fluid = (FluidStack) raw; 26 | } 27 | 28 | @Override 29 | public long matches(FluidStack e) { 30 | if (fluid.isFluidEqual(e)) { 31 | return e.amount; 32 | } 33 | return 0; 34 | } 35 | 36 | @Override 37 | public long getGoal() { 38 | return count; 39 | } 40 | 41 | @Override 42 | public Supplier> getMatchType() { 43 | return ConditionTypes.FLUID; 44 | } 45 | 46 | public FluidStack getFluid() { 47 | return fluid; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/CrTPlugin.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import crafttweaker.annotations.ZenRegister; 6 | import crafttweaker.api.item.IItemStack; 7 | import crafttweaker.api.minecraft.CraftTweakerMC; 8 | import snownee.researchtable.ResearchTable; 9 | import snownee.researchtable.core.ResearchCategory; 10 | import snownee.researchtable.core.ResearchList; 11 | import stanhebben.zenscript.annotations.Optional; 12 | import stanhebben.zenscript.annotations.ZenClass; 13 | import stanhebben.zenscript.annotations.ZenMethod; 14 | 15 | @ZenClass("mods.ResearchTable") 16 | @ZenRegister 17 | public class CrTPlugin { 18 | @ZenMethod 19 | public static ResearchBuilder builder(@Nonnull String name, @Nonnull ResearchCategoryWrapper category) { 20 | return new ResearchBuilder(name, category); 21 | } 22 | 23 | @ZenMethod 24 | public static ResearchCategoryWrapper addCategory(@Nonnull IItemStack stack, @Optional String name) { 25 | return new ResearchCategoryWrapper(new ResearchCategory(CraftTweakerMC.getItemStack(stack), name)); 26 | } 27 | 28 | @ZenMethod 29 | public static boolean remove(@Nonnull String name) { 30 | return ResearchList.LIST.remove(name) != null; 31 | } 32 | 33 | @ZenMethod 34 | public static void removeAll() { 35 | ResearchList.LIST.clear(); 36 | } 37 | 38 | @ZenMethod 39 | public static void scoreIndicator(String formattingText, String... scores) { 40 | ResearchTable.scoreFormattingText = formattingText; 41 | ResearchTable.scores = scores; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/RendererCrTItem.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | import crafttweaker.api.item.IItemStack; 9 | import crafttweaker.api.minecraft.CraftTweakerMC; 10 | import net.minecraft.client.Minecraft; 11 | import net.minecraft.client.gui.FontRenderer; 12 | import net.minecraft.client.resources.I18n; 13 | import net.minecraft.client.util.ITooltipFlag; 14 | import net.minecraft.item.Item; 15 | import net.minecraft.item.ItemStack; 16 | import net.minecraft.util.NonNullList; 17 | import net.minecraftforge.common.MinecraftForge; 18 | import net.minecraftforge.fml.relauncher.Side; 19 | import net.minecraftforge.fml.relauncher.SideOnly; 20 | import net.minecraftforge.oredict.OreDictionary; 21 | import snownee.kiwi.util.Util; 22 | import snownee.researchtable.client.gui.GuiTable; 23 | import snownee.researchtable.client.renderer.ConditionRenderer; 24 | import snownee.researchtable.client.renderer.EventShowItemCondition; 25 | 26 | @SideOnly(Side.CLIENT) 27 | public class RendererCrTItem extends ConditionRenderer { 28 | private final NonNullList stacks; 29 | @Nullable 30 | private final String name; 31 | 32 | public RendererCrTItem(ConditionCrTItem condition) { 33 | stacks = NonNullList.create(); 34 | List items = condition.ingredient.getItems(); 35 | for (IItemStack stack : items) { 36 | if (stack.getMetadata() == OreDictionary.WILDCARD_VALUE) { 37 | Item item = CraftTweakerMC.getItemStack(stack).getItem(); 38 | item.getSubItems(item.getCreativeTab(), stacks); 39 | } else if (!stack.isEmpty()) { 40 | stacks.add(CraftTweakerMC.getItemStack(stack)); 41 | } 42 | } 43 | MinecraftForge.EVENT_BUS.post(new EventShowItemCondition(stacks)); 44 | name = condition.customName; 45 | } 46 | 47 | private ItemStack getStack() { 48 | return stacks.get((int) ((GuiTable.ticks / 30) % stacks.size())); 49 | } 50 | 51 | @Override 52 | public void draw(Minecraft mc, int x, int y) { 53 | if (!stacks.isEmpty()) { 54 | mc.getRenderItem().renderItemAndEffectIntoGUI(getStack(), x, y); 55 | } 56 | } 57 | 58 | @Override 59 | public String name() { 60 | if (name != null) { 61 | return I18n.format(name); 62 | } 63 | if (!stacks.isEmpty()) { 64 | return getStack().getDisplayName(); 65 | } 66 | return I18n.format("researchtable.gui.unknown_item"); 67 | } 68 | 69 | @Override 70 | public String format(long number) { 71 | return Util.formatComma(number); 72 | } 73 | 74 | public static class Factory implements ConditionRendererFactory { 75 | 76 | @Override 77 | public ConditionRenderer get(ConditionCrTItem condition) { 78 | return new RendererCrTItem(condition); 79 | } 80 | 81 | } 82 | 83 | @Override 84 | public FontRenderer getFont() { 85 | FontRenderer font = null; 86 | if (!stacks.isEmpty()) { 87 | ItemStack stack = getStack(); 88 | font = stack.getItem().getFontRenderer(stack); 89 | } 90 | if (font == null) { 91 | font = Minecraft.getMinecraft().fontRenderer; 92 | } 93 | // font.setUnicodeFlag(true); 94 | return font; 95 | } 96 | 97 | @Override 98 | public List getTooltip(ITooltipFlag flag) { 99 | if (!stacks.isEmpty()) { 100 | return getStack().getTooltip(null, flag); 101 | } else { 102 | return Collections.EMPTY_LIST; 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/RendererCrTLiquid.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import java.util.List; 4 | 5 | import com.google.common.collect.Lists; 6 | 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.FontRenderer; 9 | import net.minecraft.client.renderer.BufferBuilder; 10 | import net.minecraft.client.renderer.GlStateManager; 11 | import net.minecraft.client.renderer.Tessellator; 12 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; 13 | import net.minecraft.client.renderer.texture.TextureMap; 14 | import net.minecraft.client.renderer.vertex.DefaultVertexFormats; 15 | import net.minecraft.client.util.ITooltipFlag; 16 | import net.minecraft.util.ResourceLocation; 17 | import net.minecraft.util.text.TextFormatting; 18 | import net.minecraftforge.fluids.FluidStack; 19 | import net.minecraftforge.fml.relauncher.Side; 20 | import net.minecraftforge.fml.relauncher.SideOnly; 21 | import snownee.kiwi.client.AdvancedFontRenderer; 22 | import snownee.kiwi.util.Util; 23 | import snownee.researchtable.client.renderer.ConditionRenderer; 24 | 25 | @SideOnly(Side.CLIENT) 26 | public class RendererCrTLiquid extends ConditionRenderer { 27 | private final FluidStack fluid; 28 | 29 | public RendererCrTLiquid(ConditionCrTLiquid condition) { 30 | this.fluid = condition.getFluid(); 31 | } 32 | 33 | @Override 34 | public void draw(Minecraft mc, int x, int y) { 35 | TextureMap textureMapBlocks = mc.getTextureMapBlocks(); 36 | ResourceLocation still = fluid.getFluid().getStill(fluid); 37 | TextureAtlasSprite sprite = null; 38 | if (still != null) { 39 | sprite = textureMapBlocks.getTextureExtry(still.toString()); 40 | } 41 | if (sprite == null) { 42 | sprite = textureMapBlocks.getMissingSprite(); 43 | } 44 | 45 | int color = fluid.getFluid().getColor(fluid); 46 | float red = (color >> 16 & 0xFF) / 255.0F; 47 | float green = (color >> 8 & 0xFF) / 255.0F; 48 | float blue = (color & 0xFF) / 255.0F; 49 | GlStateManager.color(red, green, blue, 1.0F); 50 | 51 | mc.renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); 52 | double uMin = sprite.getMinU(); 53 | double uMax = sprite.getMaxU(); 54 | double vMin = sprite.getMinV(); 55 | double vMax = sprite.getMaxV(); 56 | 57 | Tessellator tessellator = Tessellator.getInstance(); 58 | BufferBuilder bufferBuilder = tessellator.getBuffer(); 59 | bufferBuilder.begin(7, DefaultVertexFormats.POSITION_TEX); 60 | bufferBuilder.pos(x, y + 16, 0).tex(uMin, vMax).endVertex(); 61 | bufferBuilder.pos(x + 16, y + 16, 0).tex(uMax, vMax).endVertex(); 62 | bufferBuilder.pos(x + 16, y, 0).tex(uMax, vMin).endVertex(); 63 | bufferBuilder.pos(x, y, 0).tex(uMin, vMin).endVertex(); 64 | tessellator.draw(); 65 | 66 | GlStateManager.color(1, 1, 1, 1); 67 | } 68 | 69 | @Override 70 | public String name() { 71 | return fluid.getLocalizedName(); 72 | } 73 | 74 | @Override 75 | public String format(long number) { 76 | if (number >= 10000) { 77 | return Util.formatComma(number / 1000) + "B"; 78 | } else { 79 | return Util.formatComma(number) + "mB"; 80 | } 81 | } 82 | 83 | public static class Factory implements ConditionRendererFactory { 84 | 85 | @Override 86 | public ConditionRenderer get(ConditionCrTLiquid condition) { 87 | return new RendererCrTLiquid(condition); 88 | } 89 | 90 | } 91 | 92 | @Override 93 | public FontRenderer getFont() { 94 | return AdvancedFontRenderer.INSTANCE; 95 | } 96 | 97 | @Override 98 | public List getTooltip(ITooltipFlag flag) { 99 | List tooltip = Lists.newArrayList(fluid.getLocalizedName()); 100 | if (flag.isAdvanced()) { 101 | String s = TextFormatting.GRAY + fluid.getFluid().getName(); 102 | if (fluid.tag != null) { 103 | s += fluid.tag; 104 | } 105 | tooltip.add(s); 106 | } 107 | return tooltip; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/ResearchBuilder.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import javax.annotation.Nonnull; 9 | 10 | import com.google.common.collect.ImmutableList; 11 | import com.google.common.collect.ImmutableSet; 12 | 13 | import crafttweaker.annotations.ZenRegister; 14 | import crafttweaker.api.item.IIngredient; 15 | import crafttweaker.api.item.IItemStack; 16 | import crafttweaker.api.liquid.ILiquidStack; 17 | import crafttweaker.api.minecraft.CraftTweakerMC; 18 | import net.minecraft.item.ItemStack; 19 | import net.minecraft.util.NonNullList; 20 | import net.minecraftforge.oredict.OreDictionary; 21 | import snownee.researchtable.ResearchTable; 22 | import snownee.researchtable.core.CriterionResearchCount; 23 | import snownee.researchtable.core.CriterionResearches; 24 | import snownee.researchtable.core.CriterionScore; 25 | import snownee.researchtable.core.ICondition; 26 | import snownee.researchtable.core.ICriterion; 27 | import snownee.researchtable.core.IReward; 28 | import snownee.researchtable.core.Research; 29 | import snownee.researchtable.core.ResearchCategory; 30 | import snownee.researchtable.core.ResearchList; 31 | import snownee.researchtable.core.RewardExecute; 32 | import snownee.researchtable.core.RewardItems; 33 | import snownee.researchtable.plugin.forge.ConditionForgeEnergy; 34 | import stanhebben.zenscript.annotations.Optional; 35 | import stanhebben.zenscript.annotations.ZenClass; 36 | import stanhebben.zenscript.annotations.ZenMethod; 37 | 38 | @ZenClass("ResearchTable.Builder") 39 | @ZenRegister 40 | public class ResearchBuilder { 41 | private static final String KEY_NO_TITLE = ResearchTable.MODID + ".title.missing"; 42 | private static final String KEY_NO_DESCRIPTION = ResearchTable.MODID + ".description.missing"; 43 | 44 | private final String name; 45 | private final ResearchCategory category; 46 | public List criteria = new LinkedList<>(); 47 | public List triggers = new LinkedList<>(); 48 | public List rewards = new LinkedList<>(); 49 | public List conditions = new ArrayList<>(4); 50 | public List icons; 51 | private String title; 52 | private String description; 53 | private int maxCount = 1; 54 | 55 | public ResearchBuilder(@Nonnull String name, @Nonnull ResearchCategoryWrapper category) { 56 | this.name = name; 57 | this.category = category.category; 58 | } 59 | 60 | @ZenMethod 61 | public ResearchBuilder setIcons(@Nonnull IIngredient... items) { 62 | NonNullList actualItems = NonNullList.create(); 63 | for (IIngredient item : items) { 64 | for (IItemStack iItemStack : item.getItems()) { 65 | if (iItemStack != null) { 66 | ItemStack stack = CraftTweakerMC.getItemStack(iItemStack); 67 | if (stack.getMetadata() == OreDictionary.WILDCARD_VALUE) { 68 | stack.getItem().getSubItems(stack.getItem().getCreativeTab(), actualItems); 69 | } else { 70 | actualItems.add(stack); 71 | } 72 | } 73 | } 74 | } 75 | icons = ImmutableList.copyOf(actualItems); 76 | return this; 77 | } 78 | 79 | @ZenMethod 80 | public ResearchBuilder setRequiredResearches(@Nonnull String... researches) { 81 | Set set = ImmutableSet.copyOf(researches); 82 | criteria.add(new CriterionResearches(set, set.size())); 83 | return this; 84 | } 85 | 86 | @ZenMethod 87 | public ResearchBuilder setOptionalResearches(int amount, @Nonnull String... researches) { 88 | Set set = ImmutableSet.copyOf(researches); 89 | criteria.add(new CriterionResearches(set, amount)); 90 | return this; 91 | } 92 | 93 | @ZenMethod 94 | public ResearchBuilder setRequiredScore(String score, String failingText, int min, @Optional int max) { 95 | if (max < min) 96 | max = min; 97 | criteria.add(new CriterionScore(score, min, max, failingText)); 98 | return this; 99 | } 100 | 101 | @ZenMethod 102 | public ResearchBuilder setRewardCommands(@Nonnull String... commands) { 103 | rewards.add(new RewardExecute(commands)); 104 | return this; 105 | } 106 | 107 | @ZenMethod 108 | public ResearchBuilder setRewardItems(@Nonnull IItemStack... items) { 109 | NonNullList rawItems = NonNullList.from(ItemStack.EMPTY, CraftTweakerMC.getItemStacks(items)); 110 | rewards.add(new RewardItems(rawItems)); 111 | return this; 112 | } 113 | 114 | @ZenMethod 115 | public ResearchBuilder setTriggerCommands(@Nonnull String... commands) { 116 | triggers.add(new RewardExecute(commands)); 117 | return this; 118 | } 119 | 120 | @ZenMethod 121 | public ResearchBuilder setTriggerItems(@Nonnull IItemStack... items) { 122 | NonNullList rawItems = NonNullList.from(ItemStack.EMPTY, CraftTweakerMC.getItemStacks(items)); 123 | triggers.add(new RewardItems(rawItems)); 124 | return this; 125 | } 126 | 127 | @ZenMethod 128 | public ResearchBuilder setTitle(@Nonnull String title) { 129 | this.title = title; 130 | return this; 131 | } 132 | 133 | @ZenMethod 134 | public ResearchBuilder setDescription(@Nonnull String description) { 135 | this.description = description; 136 | return this; 137 | } 138 | 139 | @ZenMethod 140 | public ResearchBuilder addCondition(@Nonnull IIngredient... ingredients) { 141 | for (IIngredient ingredient : ingredients) { 142 | if (ingredient instanceof ILiquidStack) { 143 | conditions.add(new ConditionCrTLiquid((ILiquidStack) ingredient)); 144 | } else { 145 | conditions.add(new ConditionCrTItem(ingredient)); 146 | } 147 | } 148 | return this; 149 | } 150 | 151 | @ZenMethod 152 | public ResearchBuilder addCondition(@Nonnull IIngredient ingredient, long amount, @Optional String customName) { 153 | conditions.add(new ConditionCrTItem(ingredient, amount).setCustomName(customName)); 154 | return this; 155 | } 156 | 157 | @ZenMethod 158 | public ResearchBuilder addCondition(@Nonnull ILiquidStack ingredient, long amount) { 159 | conditions.add(new ConditionCrTLiquid(ingredient, amount)); 160 | return this; 161 | } 162 | 163 | @ZenMethod 164 | public ResearchBuilder addEnergyCondition(long amount) { 165 | conditions.add(new ConditionForgeEnergy(amount)); 166 | return this; 167 | } 168 | 169 | @ZenMethod 170 | public ResearchBuilder setMaxCount(int count) { 171 | this.maxCount = count; 172 | return this; 173 | } 174 | 175 | @ZenMethod 176 | public ResearchBuilder setNoMaxCount() { 177 | return setMaxCount(0); 178 | } 179 | 180 | @ZenMethod 181 | public boolean build() { 182 | if (title == null) { 183 | title = KEY_NO_TITLE; 184 | } 185 | if (description == null) { 186 | description = KEY_NO_DESCRIPTION; 187 | } 188 | if (maxCount > 0) { 189 | criteria.add(new CriterionResearchCount(name, maxCount)); 190 | } 191 | Research research = new Research(name, category, title, description, criteria, triggers, rewards, conditions, icons); 192 | return ResearchList.add(research); 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/crafttweaker/ResearchCategoryWrapper.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.crafttweaker; 2 | 3 | import crafttweaker.annotations.ZenRegister; 4 | import snownee.researchtable.core.ResearchCategory; 5 | import stanhebben.zenscript.annotations.ZenClass; 6 | 7 | @ZenClass("ResearchTable.Category") 8 | @ZenRegister 9 | public class ResearchCategoryWrapper { 10 | protected final ResearchCategory category; 11 | 12 | public ResearchCategoryWrapper(ResearchCategory category) { 13 | this.category = category; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/forge/ConditionForgeEnergy.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.forge; 2 | 3 | import java.util.function.Supplier; 4 | 5 | import snownee.researchtable.core.ConditionTypes; 6 | import snownee.researchtable.core.ICondition; 7 | 8 | public class ConditionForgeEnergy implements ICondition { 9 | private final long count; 10 | 11 | public ConditionForgeEnergy(long count) { 12 | this.count = count; 13 | } 14 | 15 | @Override 16 | public long matches(Long e) { 17 | return e; 18 | } 19 | 20 | @Override 21 | public long getGoal() { 22 | return count; 23 | } 24 | 25 | @Override 26 | public Supplier> getMatchType() { 27 | return ConditionTypes.ENERGY; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/forge/RendererForgeEnergy.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.forge; 2 | 3 | import java.util.List; 4 | 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.FontRenderer; 7 | import net.minecraft.client.resources.I18n; 8 | import net.minecraft.client.util.ITooltipFlag; 9 | import net.minecraft.util.ResourceLocation; 10 | import net.minecraftforge.fml.relauncher.Side; 11 | import net.minecraftforge.fml.relauncher.SideOnly; 12 | import snownee.kiwi.client.AdvancedFontRenderer; 13 | import snownee.kiwi.client.gui.element.DrawableResource; 14 | import snownee.kiwi.util.Util; 15 | import snownee.researchtable.ResearchTable; 16 | import snownee.researchtable.client.renderer.ConditionRenderer; 17 | 18 | @SideOnly(Side.CLIENT) 19 | public class RendererForgeEnergy extends ConditionRenderer { 20 | private static final RendererForgeEnergy INSTANCE = new RendererForgeEnergy(); 21 | private static final DrawableResource ICON = new DrawableResource(new ResourceLocation(ResearchTable.MODID, "textures/gui/energy.png"), 0, 0, 16, 16, 0, 0, 0, 0, 16, 16); 22 | 23 | private RendererForgeEnergy() { 24 | } 25 | 26 | @Override 27 | public void draw(Minecraft mc, int x, int y) { 28 | ICON.draw(mc, x, y); 29 | } 30 | 31 | @Override 32 | public String name() { 33 | return I18n.format(ResearchTable.MODID + ".gui.fe"); 34 | } 35 | 36 | @Override 37 | public String format(long number) { 38 | return Util.formatComma(number); 39 | } 40 | 41 | public static class Factory implements ConditionRendererFactory { 42 | 43 | @Override 44 | public ConditionRenderer get(ConditionForgeEnergy condition) { 45 | return RendererForgeEnergy.INSTANCE; 46 | } 47 | 48 | } 49 | 50 | @Override 51 | public FontRenderer getFont() { 52 | return AdvancedFontRenderer.INSTANCE; 53 | } 54 | 55 | @Override 56 | public List getTooltip(ITooltipFlag flag) { 57 | return null; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/gamestages/CrTGameStagesExpansion.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.gamestages; 2 | 3 | import java.util.Set; 4 | 5 | import javax.annotation.Nonnull; 6 | 7 | import com.google.common.collect.ImmutableSet; 8 | 9 | import crafttweaker.annotations.ModOnly; 10 | import crafttweaker.annotations.ZenRegister; 11 | import snownee.researchtable.plugin.crafttweaker.ResearchBuilder; 12 | import stanhebben.zenscript.annotations.ZenExpansion; 13 | import stanhebben.zenscript.annotations.ZenMethod; 14 | 15 | @ModOnly("gamestages") 16 | @ZenRegister 17 | @ZenExpansion("ResearchTable.Builder") 18 | public class CrTGameStagesExpansion { 19 | @ZenMethod 20 | public static ResearchBuilder setRewardStages(ResearchBuilder builder, @Nonnull String... stages) { 21 | builder.rewards.add(new RewardUnlockStages(stages)); 22 | return builder; 23 | } 24 | 25 | @ZenMethod 26 | public static ResearchBuilder setTriggerStages(ResearchBuilder builder, @Nonnull String... stages) { 27 | builder.triggers.add(new RewardUnlockStages(stages)); 28 | return builder; 29 | } 30 | 31 | @ZenMethod 32 | public static ResearchBuilder setRequiredStages(ResearchBuilder builder, @Nonnull String... stages) { 33 | Set set = ImmutableSet.copyOf(stages); 34 | builder.criteria.add(new CriterionStages(set, set.size())); 35 | return builder; 36 | } 37 | 38 | @ZenMethod 39 | public static ResearchBuilder setOptionalStages(ResearchBuilder builder, int amount, @Nonnull String... stages) { 40 | Set set = ImmutableSet.copyOf(stages); 41 | builder.criteria.add(new CriterionStages(set, amount)); 42 | return builder; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/gamestages/CriterionStages.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.gamestages; 2 | 3 | import java.util.Collection; 4 | 5 | import net.darkhax.gamestages.GameStageHelper; 6 | import net.minecraft.client.resources.I18n; 7 | import net.minecraft.entity.player.EntityPlayer; 8 | import net.minecraft.nbt.NBTTagCompound; 9 | import net.minecraft.util.text.TextFormatting; 10 | import net.minecraftforge.fml.relauncher.Side; 11 | import net.minecraftforge.fml.relauncher.SideOnly; 12 | import snownee.kiwi.util.Util; 13 | import snownee.researchtable.ResearchTable; 14 | import snownee.researchtable.core.ICriterion; 15 | 16 | public class CriterionStages implements ICriterion { 17 | private final Collection stages; 18 | private final int r; 19 | 20 | public CriterionStages(Collection stages, int requirement) { 21 | this.r = requirement > 0 ? requirement : stages.size(); 22 | this.stages = stages; 23 | } 24 | 25 | @Override 26 | public boolean matches(EntityPlayer player, NBTTagCompound data) { 27 | int c = 0; 28 | for (String stage : stages) { 29 | if (GameStageHelper.hasStage(player, stage)) { 30 | ++c; 31 | } 32 | } 33 | return c >= r; 34 | } 35 | 36 | @Override 37 | @SideOnly(Side.CLIENT) 38 | public String getFailingText(EntityPlayer player, NBTTagCompound data) { 39 | String string = ""; 40 | boolean first = true; 41 | for (String stage : stages) { 42 | if (!first) { 43 | string += Util.color(0) + ", "; 44 | } 45 | first = false; 46 | if (!GameStageHelper.hasStage(player, stage)) { 47 | string += Util.color(0xFFFF0000); 48 | } 49 | string += stage; 50 | } 51 | string += TextFormatting.RESET; 52 | if (r == stages.size()) { 53 | string = I18n.format(ResearchTable.MODID + ".gui.requiredStage", string); 54 | } else { 55 | string = I18n.format(ResearchTable.MODID + ".gui.optionalStage", string); 56 | string += I18n.format(ResearchTable.MODID + ".gui.of", r, stages.size()); 57 | } 58 | return string; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/gamestages/RewardUnlockStages.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.gamestages; 2 | 3 | import java.util.Set; 4 | 5 | import com.google.common.collect.ImmutableSet; 6 | 7 | import net.darkhax.gamestages.GameStageHelper; 8 | import net.minecraft.entity.player.EntityPlayer; 9 | import net.minecraft.util.math.BlockPos; 10 | import net.minecraft.world.World; 11 | import snownee.researchtable.core.IReward; 12 | 13 | public class RewardUnlockStages implements IReward { 14 | private final Set stages; 15 | 16 | public RewardUnlockStages(String... stages) { 17 | this.stages = ImmutableSet.copyOf(stages); 18 | } 19 | 20 | @Override 21 | public void earn(World world, BlockPos pos, EntityPlayer player) { 22 | stages.forEach(e -> GameStageHelper.addStage(player, e)); 23 | GameStageHelper.syncPlayer(player); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/grandeconomy/CrTGrandEconomyExpansion.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.grandeconomy; 2 | 3 | import crafttweaker.annotations.ModOnly; 4 | import crafttweaker.annotations.ZenRegister; 5 | import snownee.researchtable.plugin.crafttweaker.ResearchBuilder; 6 | import stanhebben.zenscript.annotations.ZenExpansion; 7 | import stanhebben.zenscript.annotations.ZenMethod; 8 | 9 | @ModOnly("grandeconomy") 10 | @ZenRegister 11 | @ZenExpansion("ResearchTable.Builder") 12 | public class CrTGrandEconomyExpansion { 13 | @ZenMethod 14 | public static ResearchBuilder setRewardMoneyGE(ResearchBuilder builder, double money) { 15 | builder.rewards.add(new RewardMoneyGE(money)); 16 | return builder; 17 | } 18 | 19 | @ZenMethod 20 | public static ResearchBuilder setTriggerMoneyGE(ResearchBuilder builder, double money) { 21 | builder.triggers.add(new RewardMoneyGE(money)); 22 | return builder; 23 | } 24 | 25 | @ZenMethod 26 | public static ResearchBuilder setRequiredMoneyGE(ResearchBuilder builder, double money) { 27 | builder.criteria.add(new CriterionMoneyGE(money)); 28 | return builder; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/grandeconomy/CriterionMoneyGE.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.grandeconomy; 2 | 3 | import net.minecraft.client.resources.I18n; 4 | import net.minecraft.entity.player.EntityPlayer; 5 | import net.minecraft.nbt.NBTTagCompound; 6 | import net.minecraftforge.fml.relauncher.Side; 7 | import net.minecraftforge.fml.relauncher.SideOnly; 8 | import snownee.kiwi.util.NBTHelper; 9 | import snownee.kiwi.util.Util; 10 | import snownee.researchtable.ResearchTable; 11 | import snownee.researchtable.core.ICriterion; 12 | 13 | public class CriterionMoneyGE implements ICriterion { 14 | private final double money; 15 | 16 | public CriterionMoneyGE(double money) { 17 | this.money = money; 18 | } 19 | 20 | @Override 21 | public boolean matches(EntityPlayer player, NBTTagCompound data) { 22 | NBTHelper helper = NBTHelper.of(data); 23 | double balance = helper.getDouble("grandeconomy.money"); 24 | return balance >= money; 25 | } 26 | 27 | @Override 28 | @SideOnly(Side.CLIENT) 29 | public String getFailingText(EntityPlayer player, NBTTagCompound data) { 30 | NBTHelper helper = NBTHelper.of(data); 31 | return I18n.format(ResearchTable.MODID + ".gui.needMoney", money(money, helper), Util.color(0xFF0000) + I18n.format(ResearchTable.MODID + ".gui.youHave", money(helper.getDouble("grandeconomy.money"), helper))); 32 | } 33 | 34 | @SideOnly(Side.CLIENT) 35 | public String money(double amount, NBTHelper helper) { 36 | String key = "grandeconomy." + (amount == 1 ? "singular" : "multiple"); 37 | return I18n.format(ResearchTable.MODID + ".gui.moneyFormat", amount, helper.getString(key, "")); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/grandeconomy/GrandEconomyPlugin.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.grandeconomy; 2 | 3 | import net.minecraft.nbt.NBTTagCompound; 4 | import net.minecraftforge.common.MinecraftForge; 5 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 6 | import snownee.kiwi.IModule; 7 | import snownee.kiwi.KiwiModule; 8 | import snownee.researchtable.ResearchTable; 9 | import snownee.researchtable.core.EventOpenTable; 10 | import the_fireplace.grandeconomy.api.GrandEconomyApi; 11 | 12 | @KiwiModule(modid = ResearchTable.MODID, name = "grandeconomy", dependency = "grandeconomy") 13 | public class GrandEconomyPlugin implements IModule { 14 | @Override 15 | public void init() { 16 | MinecraftForge.EVENT_BUS.register(this); 17 | } 18 | 19 | @SubscribeEvent 20 | public void onOpen(EventOpenTable event) { 21 | if (!event.getEntityPlayer().world.isRemote) { 22 | NBTTagCompound tag = new NBTTagCompound(); 23 | tag.setDouble("money", GrandEconomyApi.getBalance(event.getEntityPlayer().getUniqueID(), true)); 24 | tag.setString("singular", GrandEconomyApi.getCurrencyName(1)); 25 | tag.setString("multiple", GrandEconomyApi.getCurrencyName(99)); 26 | event.getTable().getData().setTag("grandeconomy", tag); 27 | event.getTable().hasChanged = true; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/grandeconomy/RewardMoneyGE.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.grandeconomy; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.util.math.BlockPos; 5 | import net.minecraft.world.World; 6 | import snownee.researchtable.core.IReward; 7 | import the_fireplace.grandeconomy.api.GrandEconomyApi; 8 | 9 | public class RewardMoneyGE implements IReward { 10 | private final double money; 11 | 12 | public RewardMoneyGE(double money) { 13 | this.money = money; 14 | } 15 | 16 | @Override 17 | public void earn(World world, BlockPos pos, EntityPlayer player) { 18 | if (money >= 0) { 19 | GrandEconomyApi.addToBalance(player.getUniqueID(), money, true); 20 | } else { 21 | GrandEconomyApi.takeFromBalance(player.getUniqueID(), -money, true); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/hwyla/HWYLAPlugin.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.hwyla; 2 | 3 | import mcp.mobius.waila.api.IWailaPlugin; 4 | import mcp.mobius.waila.api.IWailaRegistrar; 5 | import mcp.mobius.waila.api.WailaPlugin; 6 | import snownee.researchtable.block.BlockTable; 7 | 8 | @WailaPlugin 9 | public class HWYLAPlugin implements IWailaPlugin { 10 | 11 | @Override 12 | public void register(IWailaRegistrar registrar) { 13 | TableInfoProvider provider = new TableInfoProvider(); 14 | registrar.registerBodyProvider(provider, BlockTable.class); 15 | registrar.registerNBTProvider(provider, BlockTable.class); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/hwyla/TableInfoProvider.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.hwyla; 2 | 3 | import java.util.List; 4 | 5 | import mcp.mobius.waila.api.IWailaConfigHandler; 6 | import mcp.mobius.waila.api.IWailaDataAccessor; 7 | import mcp.mobius.waila.api.IWailaDataProvider; 8 | import net.minecraft.client.resources.I18n; 9 | import net.minecraft.entity.player.EntityPlayerMP; 10 | import net.minecraft.item.ItemStack; 11 | import net.minecraft.nbt.NBTTagCompound; 12 | import net.minecraft.tileentity.TileEntity; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.text.TextFormatting; 15 | import net.minecraft.world.World; 16 | import net.minecraftforge.fml.relauncher.Side; 17 | import net.minecraftforge.fml.relauncher.SideOnly; 18 | import snownee.kiwi.util.NBTHelper.Tag; 19 | import snownee.kiwi.util.Util; 20 | import snownee.researchtable.ResearchTable; 21 | import snownee.researchtable.block.TileTable; 22 | 23 | public class TableInfoProvider implements IWailaDataProvider { 24 | @Override 25 | @SideOnly(Side.CLIENT) 26 | public List getWailaBody(ItemStack itemStack, List tooltip, IWailaDataAccessor accessor, IWailaConfigHandler config) { 27 | if (accessor.getTileEntity() instanceof TileTable && accessor.getNBTData() != null) { 28 | NBTTagCompound tag = accessor.getNBTData(); 29 | if (tag.hasKey("owner", Tag.STRING)) { 30 | tooltip.add(I18n.format(ResearchTable.MODID + ".gui.owner", TextFormatting.WHITE + tag.getString("owner"))); 31 | } 32 | if (tag.hasKey("research", Tag.STRING)) { 33 | String title = tag.getString("research"); 34 | title = I18n.hasKey(title) ? I18n.format(title) : title; 35 | tooltip.add(I18n.format(ResearchTable.MODID + ".gui.researching", TextFormatting.WHITE + title)); 36 | } 37 | if (tag.hasKey("progress", Tag.FLOAT)) { 38 | float progress = tag.getFloat("progress"); 39 | tooltip.add(I18n.format(ResearchTable.MODID + ".gui.progress", TextFormatting.WHITE + Util.MESSAGE_FORMAT.format(new Float[] { progress }) + "%")); 40 | } 41 | } 42 | return tooltip; 43 | } 44 | 45 | @Override 46 | public NBTTagCompound getNBTData(EntityPlayerMP player, TileEntity te, NBTTagCompound tag, World world, BlockPos pos) { 47 | if (te instanceof TileTable) { 48 | TileTable table = (TileTable) te; 49 | if (table.ownerName != null && !table.ownerName.isEmpty()) { 50 | tag.setString("owner", table.ownerName); 51 | } 52 | if (table.getResearch() != null) { 53 | tag.setString("research", table.getResearch().getTitleRaw()); 54 | tag.setFloat("progress", table.getProgress()); 55 | } 56 | } 57 | return tag; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/itemstages/ItemStagesPlugin.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.itemstages; 2 | 3 | import net.darkhax.gamestages.GameStageHelper; 4 | import net.darkhax.itemstages.ItemStages; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraftforge.common.MinecraftForge; 7 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 8 | import net.minecraftforge.fml.relauncher.Side; 9 | import net.minecraftforge.fml.relauncher.SideOnly; 10 | import snownee.kiwi.IModule; 11 | import snownee.kiwi.KiwiModule; 12 | import snownee.researchtable.ResearchTable; 13 | import snownee.researchtable.client.renderer.EventShowItemCondition; 14 | 15 | @KiwiModule(modid = ResearchTable.MODID, name = "itemstages", dependency = "itemstages", optional = true) 16 | public class ItemStagesPlugin implements IModule { 17 | @Override 18 | @SideOnly(Side.CLIENT) 19 | public void init() { 20 | MinecraftForge.EVENT_BUS.register(this); 21 | } 22 | 23 | @SideOnly(Side.CLIENT) 24 | @SubscribeEvent 25 | public void onCondition(EventShowItemCondition event) { 26 | event.stacks.removeIf(stack -> { 27 | String itemsStage = ItemStages.getStage(stack); 28 | if (itemsStage != null) { 29 | return !GameStageHelper.hasStage(Minecraft.getMinecraft().player, itemsStage); 30 | } 31 | return false; 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/jei/JeiPlugin.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.jei; 2 | 3 | import mezz.jei.api.IModPlugin; 4 | import mezz.jei.api.IModRegistry; 5 | import mezz.jei.api.JEIPlugin; 6 | import snownee.researchtable.client.gui.GuiTable; 7 | 8 | @JEIPlugin 9 | public class JeiPlugin implements IModPlugin { 10 | 11 | @Override 12 | public void register(IModRegistry registry) { 13 | registry.addGuiScreenHandler(GuiTable.class, $ -> null); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/reskillable/CrTReskillableExpansion.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.reskillable; 2 | 3 | import crafttweaker.annotations.ModOnly; 4 | import crafttweaker.annotations.ZenRegister; 5 | import snownee.researchtable.plugin.crafttweaker.ResearchBuilder; 6 | import stanhebben.zenscript.annotations.ZenExpansion; 7 | import stanhebben.zenscript.annotations.ZenMethod; 8 | 9 | @ModOnly("reskillable") 10 | @ZenRegister 11 | @ZenExpansion("ResearchTable.Builder") 12 | public class CrTReskillableExpansion { 13 | @ZenMethod 14 | public static ResearchBuilder setRewardSkill(ResearchBuilder builder, String skillName) { 15 | builder.rewards.add(new RewardSkillLevelUp(skillName)); 16 | return builder; 17 | } 18 | 19 | @ZenMethod 20 | public static ResearchBuilder setTriggerSkill(ResearchBuilder builder, String skillName) { 21 | builder.triggers.add(new RewardSkillLevelUp(skillName)); 22 | return builder; 23 | } 24 | 25 | @ZenMethod 26 | public static ResearchBuilder setRewardSkill(ResearchBuilder builder, String skillName, int newLevel) { 27 | builder.rewards.add(new RewardSetSkillLevel(skillName, newLevel)); 28 | return builder; 29 | } 30 | 31 | @ZenMethod 32 | public static ResearchBuilder setTriggerSkill(ResearchBuilder builder, String skillName, int newLevel) { 33 | builder.triggers.add(new RewardSetSkillLevel(skillName, newLevel)); 34 | return builder; 35 | } 36 | 37 | @ZenMethod 38 | public static ResearchBuilder setRequiredSkill(ResearchBuilder builder, String skill, int level) { 39 | builder.criteria.add(new CriterionSkill(skill, level)); 40 | return builder; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/reskillable/CriterionSkill.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.reskillable; 2 | 3 | import codersafterdark.reskillable.api.skill.Skill; 4 | import net.minecraft.client.resources.I18n; 5 | import net.minecraft.entity.player.EntityPlayer; 6 | import net.minecraft.nbt.NBTTagCompound; 7 | import net.minecraftforge.fml.relauncher.Side; 8 | import net.minecraftforge.fml.relauncher.SideOnly; 9 | import snownee.kiwi.util.Util; 10 | import snownee.researchtable.ResearchTable; 11 | import snownee.researchtable.core.ICriterion; 12 | 13 | public class CriterionSkill implements ICriterion { 14 | private final Skill skill; 15 | private final int r; 16 | 17 | public CriterionSkill(String skillName, int requirementLevel) { 18 | this.r = requirementLevel; 19 | skill = Helper.getSkill(skillName); 20 | if (skill == null) { 21 | throw new NullPointerException("Unknown skill name " + skillName); 22 | } 23 | } 24 | 25 | @Override 26 | public boolean matches(EntityPlayer player, NBTTagCompound data) { 27 | int lv = Helper.getLevel(player, skill); 28 | return lv >= r; 29 | } 30 | 31 | @Override 32 | @SideOnly(Side.CLIENT) 33 | public String getFailingText(EntityPlayer player, NBTTagCompound data) { 34 | return I18n.format(ResearchTable.MODID + ".gui.needSkill", skill.getName(), r, Util.color(0xFF0000) + I18n.format(ResearchTable.MODID + ".gui.youHave", Helper.getLevel(player, skill))); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/reskillable/Helper.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.reskillable; 2 | 3 | import codersafterdark.reskillable.api.ReskillableRegistries; 4 | import codersafterdark.reskillable.api.data.PlayerData; 5 | import codersafterdark.reskillable.api.data.PlayerDataHandler; 6 | import codersafterdark.reskillable.api.data.PlayerSkillInfo; 7 | import codersafterdark.reskillable.api.skill.Skill; 8 | import net.minecraft.entity.player.EntityPlayer; 9 | import net.minecraft.util.ResourceLocation; 10 | 11 | public class Helper { 12 | public static Skill getSkill(String skillName) { 13 | skillName = skillName.replaceAll(":", "."); 14 | String[] parts = skillName.split("\\."); 15 | ResourceLocation rl = parts.length > 1 ? new ResourceLocation(parts[0], skillName.substring(parts[0].length() + 1)) : new ResourceLocation(skillName); 16 | return ReskillableRegistries.SKILLS.getValue(rl); 17 | } 18 | 19 | public static int getLevel(EntityPlayer player, Skill skill) { 20 | PlayerData data = PlayerDataHandler.get(player); 21 | PlayerSkillInfo skillInfo = data.getSkillInfo(skill); 22 | return skillInfo.getLevel(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/reskillable/RewardSetSkillLevel.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.reskillable; 2 | 3 | import codersafterdark.reskillable.api.data.PlayerData; 4 | import codersafterdark.reskillable.api.data.PlayerDataHandler; 5 | import codersafterdark.reskillable.api.data.PlayerSkillInfo; 6 | import codersafterdark.reskillable.api.event.LevelUpEvent; 7 | import codersafterdark.reskillable.api.toast.ToastHelper; 8 | import net.minecraft.entity.player.EntityPlayer; 9 | import net.minecraft.entity.player.EntityPlayerMP; 10 | import net.minecraft.util.math.BlockPos; 11 | import net.minecraft.world.World; 12 | import net.minecraftforge.common.MinecraftForge; 13 | 14 | public class RewardSetSkillLevel extends RewardSkillLevelUp { 15 | private final int newLevel; 16 | 17 | public RewardSetSkillLevel(String skillName, int newLevel) { 18 | super(skillName); 19 | this.newLevel = newLevel; 20 | } 21 | 22 | @Override 23 | public void earn(World world, BlockPos pos, EntityPlayer player) { 24 | PlayerData data = PlayerDataHandler.get(player); 25 | PlayerSkillInfo skillInfo = data.getSkillInfo(skill); 26 | int oldLevel = skillInfo.getLevel(); 27 | if (!MinecraftForge.EVENT_BUS.post(new LevelUpEvent.Pre(player, skill, newLevel, oldLevel))) { 28 | skillInfo.setLevel(newLevel); 29 | data.saveAndSync(); 30 | MinecraftForge.EVENT_BUS.post(new LevelUpEvent.Post(player, skill, newLevel, oldLevel)); 31 | if (player instanceof EntityPlayerMP) { 32 | ToastHelper.sendSkillToast((EntityPlayerMP) player, skill, newLevel); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/reskillable/RewardSkillLevelUp.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.reskillable; 2 | 3 | import codersafterdark.reskillable.api.data.PlayerData; 4 | import codersafterdark.reskillable.api.data.PlayerDataHandler; 5 | import codersafterdark.reskillable.api.data.PlayerSkillInfo; 6 | import codersafterdark.reskillable.api.event.LevelUpEvent; 7 | import codersafterdark.reskillable.api.skill.Skill; 8 | import codersafterdark.reskillable.api.toast.ToastHelper; 9 | import net.minecraft.entity.player.EntityPlayer; 10 | import net.minecraft.entity.player.EntityPlayerMP; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.world.World; 13 | import net.minecraftforge.common.MinecraftForge; 14 | import snownee.researchtable.core.IReward; 15 | 16 | public class RewardSkillLevelUp implements IReward { 17 | protected final Skill skill; 18 | 19 | public RewardSkillLevelUp(String skillName) { 20 | skill = Helper.getSkill(skillName); 21 | if (skill == null) { 22 | throw new NullPointerException("Unknown skill name " + skillName); 23 | } 24 | } 25 | 26 | @Override 27 | public void earn(World world, BlockPos pos, EntityPlayer player) { 28 | PlayerData data = PlayerDataHandler.get(player); 29 | PlayerSkillInfo skillInfo = data.getSkillInfo(skill); 30 | int oldLevel = skillInfo.getLevel(); 31 | if (!MinecraftForge.EVENT_BUS.post(new LevelUpEvent.Pre(player, skill, oldLevel + 1, oldLevel))) { 32 | skillInfo.levelUp(); 33 | data.saveAndSync(); 34 | MinecraftForge.EVENT_BUS.post(new LevelUpEvent.Post(player, skill, skillInfo.getLevel(), oldLevel)); 35 | if (player instanceof EntityPlayerMP) { 36 | ToastHelper.sendSkillToast((EntityPlayerMP) player, skill, skillInfo.getLevel()); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/togetherforever/TeamProviderTF.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.togetherforever; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.UUID; 6 | import java.util.stream.Collectors; 7 | 8 | import com.buuz135.togetherforever.api.IPlayerInformation; 9 | import com.buuz135.togetherforever.api.ITogetherTeam; 10 | import com.buuz135.togetherforever.api.TogetherForeverAPI; 11 | import com.buuz135.togetherforever.api.event.TeamEvent; 12 | 13 | import net.minecraftforge.common.MinecraftForge; 14 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 15 | import snownee.researchtable.core.team.TeamHelper; 16 | import snownee.researchtable.core.team.TeamProvider; 17 | 18 | public enum TeamProviderTF implements TeamProvider { 19 | INSTANCE; 20 | 21 | private TeamProviderTF() { 22 | MinecraftForge.EVENT_BUS.register(this); 23 | } 24 | 25 | @SubscribeEvent 26 | public void onPlayerAdd(TeamEvent.PlayerAdd event) { 27 | if (TeamHelper.provider == this) { 28 | TeamHelper.onPlayerAdd(event.getPlayerInformation().getUUID(), event.getTogetherTeam().getOwner()); 29 | } 30 | } 31 | 32 | @Override 33 | public UUID getOwner(UUID player) { 34 | ITogetherTeam team = TogetherForeverAPI.getInstance().getPlayerTeam(player); 35 | return team == null ? null : team.getOwner(); 36 | } 37 | 38 | @Override 39 | public Collection getMembers(UUID player) { 40 | ITogetherTeam team = TogetherForeverAPI.getInstance().getPlayerTeam(player); 41 | if (team == null) { 42 | return Collections.singleton(player); 43 | } 44 | return team.getPlayers().stream().map(IPlayerInformation::getUUID).collect(Collectors.toSet()); 45 | } 46 | 47 | @Override 48 | public String getTeamName(UUID player) { 49 | ITogetherTeam team = TogetherForeverAPI.getInstance().getPlayerTeam(player); 50 | return team == null ? null : team.getTeamName(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/top/TOPPlugin.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.top; 2 | 3 | import java.util.function.Function; 4 | 5 | import mcjty.theoneprobe.api.ITheOneProbe; 6 | import net.minecraftforge.fml.common.event.FMLInterModComms; 7 | import snownee.kiwi.IModule; 8 | import snownee.kiwi.KiwiModule; 9 | import snownee.researchtable.ResearchTable; 10 | 11 | @KiwiModule(modid = ResearchTable.MODID, name = "theoneprobe", dependency = "theoneprobe", optional = true) 12 | public class TOPPlugin implements IModule { 13 | 14 | @Override 15 | public void preInit() { 16 | FMLInterModComms.sendFunctionMessage("theoneprobe", "getTheOneProbe", "snownee.researchtable.plugin.top.TOPPlugin$GetTheOneProbe"); 17 | } 18 | 19 | public static class GetTheOneProbe implements Function { 20 | 21 | @Override 22 | public Void apply(ITheOneProbe probe) { 23 | probe.registerProvider(new TableInfoProvider()); 24 | return null; 25 | } 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/snownee/researchtable/plugin/top/TableInfoProvider.java: -------------------------------------------------------------------------------- 1 | package snownee.researchtable.plugin.top; 2 | 3 | import mcjty.theoneprobe.api.IProbeHitData; 4 | import mcjty.theoneprobe.api.IProbeInfo; 5 | import mcjty.theoneprobe.api.IProbeInfoProvider; 6 | import mcjty.theoneprobe.api.ProbeMode; 7 | import mcjty.theoneprobe.apiimpl.styles.ProgressStyle; 8 | import net.minecraft.block.state.IBlockState; 9 | import net.minecraft.entity.player.EntityPlayer; 10 | import net.minecraft.tileentity.TileEntity; 11 | import net.minecraft.util.text.TextFormatting; 12 | import net.minecraft.util.text.translation.I18n; 13 | import net.minecraft.world.World; 14 | import snownee.researchtable.ResearchTable; 15 | import snownee.researchtable.ResearchTableModule; 16 | import snownee.researchtable.block.TileTable; 17 | import snownee.researchtable.core.Research; 18 | 19 | public class TableInfoProvider implements IProbeInfoProvider { 20 | 21 | @Override 22 | public String getID() { 23 | return ResearchTable.MODID; 24 | } 25 | 26 | @Override 27 | public void addProbeInfo(ProbeMode mode, IProbeInfo probeInfo, EntityPlayer player, World world, IBlockState blockState, IProbeHitData data) { 28 | if (mode == ProbeMode.EXTENDED || mode == ProbeMode.DEBUG) { 29 | if (blockState.getBlock() == ResearchTableModule.TABLE) { 30 | TileEntity tile = world.getTileEntity(data.getPos()); 31 | if (tile instanceof TileTable) { 32 | TileTable table = (TileTable) tile; 33 | if (table.ownerName != null && !table.ownerName.isEmpty()) { 34 | probeInfo.text(I18n.translateToLocalFormatted(ResearchTable.MODID + ".gui.owner", TextFormatting.WHITE + table.ownerName)); 35 | } 36 | Research research = table.getResearch(); 37 | if (research != null) { 38 | String title = research.getTitleRaw(); 39 | if (I18n.canTranslate(title)) { 40 | title = I18n.translateToLocalFormatted(title); 41 | } 42 | probeInfo.text(I18n.translateToLocalFormatted(ResearchTable.MODID + ".gui.researching", TextFormatting.WHITE + title)); 43 | probeInfo.progress((int) (table.getProgress()), 100, new ProgressStyle().filledColor(0xFF00CC33).alternateFilledColor(0xFF00CC33).backgroundColor(0).suffix("%")); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/research_at.cfg: -------------------------------------------------------------------------------- 1 | # Used by AdvancedFontRenderer for extentded formatting code 2 | protected net.minecraft.client.gui.FontRenderer field_78303_s #randomStyle 3 | protected net.minecraft.client.gui.FontRenderer field_78302_t #boldStyle 4 | protected net.minecraft.client.gui.FontRenderer field_78301_u #italicStyle 5 | protected net.minecraft.client.gui.FontRenderer field_78300_v #underlineStyle 6 | protected net.minecraft.client.gui.FontRenderer field_78299_w #strikethroughStyle 7 | protected net.minecraft.client.gui.FontRenderer field_78304_r #textColor 8 | protected net.minecraft.client.gui.FontRenderer field_78285_g #colorCode 9 | protected net.minecraft.client.gui.FontRenderer field_78291_n #red 10 | protected net.minecraft.client.gui.FontRenderer field_78306_p #green 11 | protected net.minecraft.client.gui.FontRenderer field_78292_o #blue 12 | protected net.minecraft.client.gui.FontRenderer field_78305_q #alpha 13 | 14 | public net.minecraft.client.gui.FontRenderer func_78265_b()V #resetStyles 15 | protected net.minecraft.client.gui.FontRenderer func_78255_a(Ljava/lang/String;Z)V #renderStringAtPos 16 | protected net.minecraft.client.gui.FontRenderer func_181559_a(CZ)F #renderChar 17 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/blockstates/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "forge_marker": 1, 3 | "defaults": { 4 | "model": "researchtable:table" 5 | }, 6 | "variants": { 7 | "facing": { 8 | "north": { "y": 0 }, 9 | "south": { "y": 180 }, 10 | "west": { "y": 270 }, 11 | "east": { "y": 90 } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/lang/en_us.lang: -------------------------------------------------------------------------------- 1 | tile.researchtable.table.name=Research Table 2 | tile.researchtable.table.tip=Keeps progress if broken 3 | 4 | researchtable.title.missing=Untitled 5 | researchtable.description.missing=No description. 6 | researchtable.noPermission=Access denied. 7 | 8 | researchtable.gui.owner=Owner: %s 9 | researchtable.gui.researching=Researching: %s 10 | researchtable.gui.progress=Progress: %s 11 | researchtable.gui.requiredStage=Required stages: %s 12 | researchtable.gui.optionalStage=Optional stages: %s 13 | researchtable.gui.requiredResearch=Required researches: %s 14 | researchtable.gui.optionalResearch=Optional researches: %s 15 | researchtable.gui.needSkill=Need skill: %s Lv. %d %s 16 | researchtable.gui.needMoney=Need money:%s %s 17 | researchtable.gui.moneyFormat=%d %s 18 | researchtable.gui.maxCount=This research can only be done %s time(s)! 19 | researchtable.gui.researchNoFound=Cannot find research %s. 20 | researchtable.gui.youHave=(you have %s) 21 | researchtable.gui.of=(%d of %d) 22 | researchtable.gui.fe=Energy 23 | researchtable.gui.button.research=Research 24 | researchtable.gui.button.submit=Submit 25 | researchtable.gui.button.complete=Complete 26 | researchtable.gui.button.cancel=Cancel 27 | researchtable.gui.button.shift=Press Shift 28 | researchtable.gui.unknown_item=Unknown Item 29 | 30 | commands.researchtable.usage=/researchtable [count] 31 | commands.researchtable.researchNotFound=Research not found. 32 | commands.researchtable.get=%s: %s 33 | commands.researchtable.set=%s: successful 34 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/lang/pt_br.lang: -------------------------------------------------------------------------------- 1 | tile.researchtable.table.name=Mesa de Pesquisa 2 | tile.researchtable.table.tip=Mantém o progresso mesmo depois de quebrar 3 | 4 | researchtable.title.missing=Sem título 5 | researchtable.description.missing=Sem descrição. 6 | researchtable.noPermission=Acesso negado. 7 | 8 | researchtable.gui.owner=Dono: %s 9 | researchtable.gui.researching=Pesquisando: %s 10 | researchtable.gui.progress=Progresso: %s 11 | researchtable.gui.needStages=Etapas necessárias: %s 12 | researchtable.gui.needResearches=Pesquisas necessárias: %s 13 | researchtable.gui.needSkill=Habilidades necessárias: %s Nv. %d %s 14 | researchtable.gui.needMoney=Dinheiro necessário:%s %s 15 | researchtable.gui.moneyFormat=%d %s 16 | researchtable.gui.maxCount=This research can only be done %s time(s)! 17 | researchtable.gui.researchNoFound=Não foi possível encontrar a pesquisa %s. 18 | researchtable.gui.youHave=(você tem %s) 19 | researchtable.gui.of=(%d de %d) 20 | researchtable.gui.fe=Energia 21 | researchtable.gui.button.research=Pesquisar 22 | researchtable.gui.button.submit=Enviar 23 | researchtable.gui.button.complete=Completar 24 | researchtable.gui.button.cancel=Cancelar 25 | researchtable.gui.button.shift=Segure Shift 26 | researchtable.gui.unknown_item=Item desconhecido 27 | 28 | commands.researchtable.usage=/researchtable [contagem] 29 | commands.researchtable.researchNotFound=Pesquisa não encontrada. 30 | commands.researchtable.get=%s: %s 31 | commands.researchtable.set=%s: bem-sucedido 32 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/lang/ru_ru.lang: -------------------------------------------------------------------------------- 1 | tile.researchtable.table.name=Исследовательский стол 2 | tile.researchtable.table.tip=Сохраняет прогресс после разрушения 3 | 4 | researchtable.title.missing=Без названия 5 | researchtable.description.missing=Без описания. 6 | researchtable.noPermission=Доступ запрещён. 7 | 8 | researchtable.gui.owner=Владелец: %s 9 | researchtable.gui.researching=Исследование: %s 10 | researchtable.gui.progress=Прогресс: %s 11 | researchtable.gui.needStages=Необходимы этапы: %s 12 | researchtable.gui.needResearches=Необходимы исследования: %s 13 | researchtable.gui.needSkill=Необходим навык: %s Ур. %d %s 14 | researchtable.gui.needMoney=Требуется денег:%s %s 15 | researchtable.gui.moneyFormat=%d %s 16 | researchtable.gui.maxCount=Это исследование может быть проведено только %s раз(а)! 17 | researchtable.gui.researchNoFound=Невозможно найти исследование %s. 18 | researchtable.gui.youHave=(у вас %s) 19 | researchtable.gui.of=(%d из %d) 20 | researchtable.gui.fe=Энергия 21 | researchtable.gui.button.research=Исследовать 22 | researchtable.gui.button.submit=Передать 23 | researchtable.gui.button.complete=Завершить 24 | researchtable.gui.button.cancel=Отмена 25 | researchtable.gui.button.shift=Нажмите Shift 26 | researchtable.gui.unknown_item=Неизвестный предмет 27 | 28 | commands.researchtable.usage=/researchtable <Игрок> <Исследование> [количество] 29 | commands.researchtable.researchNotFound=Исследование не найдено. 30 | commands.researchtable.get=%s: %s 31 | commands.researchtable.set=%s: успешно -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/lang/zh_cn.lang: -------------------------------------------------------------------------------- 1 | tile.researchtable.table.name=研究台 2 | tile.researchtable.table.tip=破坏后保留进度 3 | 4 | researchtable.title.missing=无标题 5 | researchtable.description.missing=无描述。 6 | researchtable.noPermission=拒绝访问。 7 | 8 | researchtable.gui.owner=所有者:%s 9 | researchtable.gui.researching=正在研究%s 10 | researchtable.gui.progress=进度:%s 11 | researchtable.gui.requiredStage=需要阶段:%s 12 | researchtable.gui.optionalStage=需要阶段:%s 13 | researchtable.gui.requiredResearch=需要研究:%s 14 | researchtable.gui.optionalResearch=需要研究:%s 15 | researchtable.gui.needSkill=需要技能:%s Lv. %d %s 16 | researchtable.gui.needMoney=需要金钱:%s %s 17 | researchtable.gui.moneyFormat=%d %s 18 | researchtable.gui.maxCount=研究限完成%s次! 19 | researchtable.gui.researchNoFound=未找到研究 %s。 20 | researchtable.gui.youHave=(你拥有%s) 21 | researchtable.gui.of=(%2$d选%1$d) 22 | researchtable.gui.fe=能量 23 | researchtable.gui.button.research=研究 24 | researchtable.gui.button.submit=提交 25 | researchtable.gui.button.complete=完成 26 | researchtable.gui.button.cancel=取消 27 | researchtable.gui.button.shift=按住Shift 28 | researchtable.gui.unknown_item=未知物品 29 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/models/block/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "credit": "Made with Blockbench", 3 | "parent": "block/block", 4 | "textures": { 5 | "0": "researchtable:block/0", 6 | "1": "researchtable:block/1", 7 | "2": "researchtable:block/2", 8 | "3": "researchtable:block/3", 9 | "4": "researchtable:block/screen", 10 | "particle": "researchtable:block/0" 11 | }, 12 | "elements": [ 13 | { 14 | "from": [4, 2, 5], 15 | "to": [12, 13, 11], 16 | "faces": { 17 | "north": {"uv": [0, 0, 8, 11], "texture": "#2"}, 18 | "east": {"uv": [0, 10, 11, 16], "rotation": 90, "texture": "#3"}, 19 | "south": {"uv": [8, 0, 16, 11], "texture": "#2"}, 20 | "west": {"uv": [0, 16, 11, 10], "rotation": 90, "texture": "#3"} 21 | } 22 | }, 23 | { 24 | "from": [2, 0, 3], 25 | "to": [14, 2, 13], 26 | "faces": { 27 | "north": {"uv": [0, 11, 12, 13], "texture": "#2"}, 28 | "east": {"uv": [14, 0, 16, 10], "rotation": 90, "texture": "#0"}, 29 | "south": {"uv": [0, 11, 12, 13], "texture": "#2"}, 30 | "west": {"uv": [14, 0, 16, 10], "rotation": 90, "texture": "#0"}, 31 | "up": {"uv": [0, 0, 12, 10], "rotation": 180, "texture": "#3"}, 32 | "down": {"uv": [0, 0, 12, 10], "rotation": 180, "texture": "#3"} 33 | } 34 | }, 35 | { 36 | "from": [0, 11, 1], 37 | "to": [16, 14, 17], 38 | "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 10, 8]}, 39 | "faces": { 40 | "north": {"uv": [0, 13, 16, 16], "texture": "#0"}, 41 | "east": {"uv": [0, 13, 16, 16], "texture": "#0"}, 42 | "south": {"uv": [0, 13, 16, 16], "texture": "#0"}, 43 | "west": {"uv": [0, 13, 16, 16], "texture": "#0"}, 44 | "up": {"uv": [0, 0, 16, 16], "rotation": 180, "texture": "#1"}, 45 | "down": {"uv": [0, 2, 16, 5], "rotation": 180, "texture": "#1"} 46 | } 47 | }, 48 | { 49 | "from": [2, 15, 3], 50 | "to": [14, 15, 15], 51 | "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 10, 8]}, 52 | "faces": { 53 | "up": {"uv": [0, 0, 12, 12], "rotation": 180, "texture": "#4"}, 54 | "down": {"uv": [0, 0, 12, 12], "rotation": 180, "texture": "#4"} 55 | } 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/recipes/reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "forge:ore_shaped", 3 | "result": { 4 | "item": "researchtable:table" 5 | }, 6 | "pattern": [ 7 | "*" 8 | ], 9 | "key": { 10 | "*": { 11 | "item": "researchtable:table" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/block/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/block/0.png -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/block/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/block/1.png -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/block/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/block/2.png -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/block/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/block/3.png -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/block/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/block/screen.png -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/block/screen.png.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "animation": { 3 | "frametime": 2, 4 | "frames": [ 5 | 0, 6 | 0, 7 | 0, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 1, 14 | 2, 15 | 3, 16 | 4, 17 | 5, 18 | 6, 19 | 7, 20 | 7, 21 | 8, 22 | 9, 23 | 14, 24 | 15, 25 | 15, 26 | 15, 27 | 15, 28 | 15, 29 | 15, 30 | 15, 31 | 15, 32 | 15, 33 | 15, 34 | 15, 35 | 15, 36 | 14, 37 | 15, 38 | 15, 39 | 15, 40 | 15, 41 | 15, 42 | 15, 43 | 15, 44 | 15, 45 | 10, 46 | 11, 47 | 12, 48 | 12, 49 | 12, 50 | 12, 51 | 12, 52 | 12, 53 | 12, 54 | 12, 55 | 12, 56 | 12, 57 | 12, 58 | 12, 59 | 12, 60 | 12, 61 | 12, 62 | 13, 63 | 7, 64 | 7, 65 | 6, 66 | 5, 67 | 4, 68 | 3, 69 | 2, 70 | 1 71 | ] 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/gui/energy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/gui/energy.png -------------------------------------------------------------------------------- /src/main/resources/assets/researchtable/textures/gui/globe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZengineeringTeam/ResearchTable/44053a34e9ea0866e8385c9d876c50835b5dbef9/src/main/resources/assets/researchtable/textures/gui/globe.png -------------------------------------------------------------------------------- /src/main/resources/mcmod.info: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "modid": "researchtable", 4 | "name": "ResearchTable", 5 | "description": "", 6 | "version": "1.0.1", 7 | "mcversion": "1.12.2", 8 | "authorList": ["Snownee"], 9 | "useDependencyInformation": true, 10 | "requiredMods": ["forge@[14.23.4.2772,)", "kiwi@[0.5, 0.7)"], 11 | "dependencies": ["forge@[14.23.4.2772,)", "kiwi@[0.5, 0.7)", "gamestages@[2.0, 3.0)", "crafttweaker"] 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Assets used by \"ResearchTable\" Mod.", 4 | "pack_format": 3 5 | } 6 | } 7 | --------------------------------------------------------------------------------