commit c19790efc421f3d4646a43968e592d3e419ee0b1 Author: TheBrokenRail Date: Fri Apr 3 22:32:34 2020 -0400 1.0 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3fb81fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# fabric + +run/ + +remappedSrc/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..141f1e4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# Changelog + +**1.0** +* Initial Release diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..1673e44 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,19 @@ +pipeline { + agent { + docker { + image 'openjdk:8-jdk' + } + } + stages { + stage('Build') { + steps { + sh './gradlew build' + } + post { + success { + archiveArtifacts artifacts: 'build/libs/*', fingerprint: true + } + } + } + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..886b254 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 TheBrokenRail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ae69e1 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# RelicCraft +Find magical relics throughout the world! + +This mod adds several magical items and blocks that can be found randomly throughout the world. + +This mod was created for [ModFest 1.15](https://modfest.github.io/1.15/) + +## Features +* Magical Orbs and Staffs With Randomly-Generated Actions +* Randomly-Generated Time Temples +* Time Dilaters +* Teleportation Restrictors +* Teleportation Beacons + +## Changelog +[View Changelog](CHANGELOG.md) diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7e58c8e --- /dev/null +++ b/build.gradle @@ -0,0 +1,105 @@ +plugins { + id 'fabric-loom' version '0.2.7-SNAPSHOT' + id 'com.matthewprenger.cursegradle' version '1.4.0' + id "com.github.johnrengelman.shadow" version "5.2.0" +} + +compileJava { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +archivesBaseName = project.archives_base_name +def mod_version = project.mod_version as Object +version = "${mod_version}+${project.minecraft_version}" +group = project.maven_group as Object + +minecraft { +} + +repositories { + jcenter() + maven { + url "https://dl.bintray.com/shedaniel/autoconfig1u/" + } +} + +dependencies { + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.minecraft_version}+build.${project.yarn_build}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + + modImplementation "io.github.prospector:modmenu:${project.mod_menu_version}" + + implementation "com.squareup.moshi:moshi:${project.moshi_version}" + shadow "com.squareup.moshi:moshi:${project.moshi_version}" +} + +processResources { + inputs.property 'version', mod_version + inputs.property 'name', rootProject.name + + from(sourceSets.main.resources.srcDirs) { + include 'fabric.mod.json' + expand 'version': mod_version, 'name': rootProject.name + } + + from(sourceSets.main.resources.srcDirs) { + exclude 'fabric.mod.json' + } +} + +// ensure that the encoding is set to UTF-8, no matter what the system default is +// this fixes some edge cases with special characters not displaying correctly +// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task +// if it is present. +// If you remove this task, sources will not be generated. +task sourcesJar(type: Jar, dependsOn: classes) { + classifier 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar + archives javadocJar +} + +jar { + from "LICENSE" +} + +if (project.hasProperty('curseforge.api_key')) { + curseforge { + apiKey = project.getProperty('curseforge.api_key') + project { + id = project.curseforge_id + changelog = 'A changelog can be found at https://gitea.thebrokenrail.com/TheBrokenRail/RelicCraft/src/branch/master/CHANGELOG.md' + releaseType = 'release' + addGameVersion project.simple_minecraft_version + addGameVersion 'Fabric' + mainArtifact(remapJar) { + displayName = "RelicCraft v${mod_version} for ${project.minecraft_version}" + } + afterEvaluate { + uploadTask.dependsOn('remapJar') + } + relations { + requiredDependency 'fabric-api' + } + } + options { + forgeGradleIntegration = false + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..d3b764f --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs = -Xmx1G + +# Fabric Properties + # check these on https://fabricmc.net/use + minecraft_version = 1.15.2 + curseforge_id = 373074 + simple_minecraft_version = 1.15.2 + yarn_build = 14 + fabric_loader_version = 0.7.9+build.190 + +# Mod Properties + mod_version = 1.0.0 + maven_group = com.thebrokenrail + archives_base_name = reliccraft + +# Dependencies + # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api + fabric_api_version = 0.5.1+build.294-1.15 + mod_menu_version = 1.10.2+build.32 + moshi_version = 1.9.2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..5c2d1cf Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..5baddfb --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Feb 29 21:58:32 EST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..8e25e6c --- /dev/null +++ b/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9618d8d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..3cef785 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,12 @@ +pluginManagement { + repositories { + jcenter() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } +} + +rootProject.name = 'RelicCraft' diff --git a/src/main/java/com/thebrokenrail/reliccraft/RelicCraft.java b/src/main/java/com/thebrokenrail/reliccraft/RelicCraft.java new file mode 100644 index 0000000..c4b151e --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/RelicCraft.java @@ -0,0 +1,189 @@ +package com.thebrokenrail.reliccraft; + +import com.thebrokenrail.reliccraft.advancement.ActivateTeleportationBeaconCriterion; +import com.thebrokenrail.reliccraft.advancement.ActivateTeleportationRestrictorCriterion; +import com.thebrokenrail.reliccraft.advancement.DilateTimeCriterion; +import com.thebrokenrail.reliccraft.advancement.DuplicateTimeDilaterCriterion; +import com.thebrokenrail.reliccraft.advancement.RevealRelicCriterion; +import com.thebrokenrail.reliccraft.advancement.UseTargetedEnderPearlCriterion; +import com.thebrokenrail.reliccraft.advancement.UseTeleportationBeaconCriterion; +import com.thebrokenrail.reliccraft.block.DragonEggHolderBlockEntity; +import com.thebrokenrail.reliccraft.block.TeleportationBeaconBlock; +import com.thebrokenrail.reliccraft.block.TeleportationRestrictorBlock; +import com.thebrokenrail.reliccraft.entity.RelicEntity; +import com.thebrokenrail.reliccraft.item.TargetedEnderPearlItem; +import com.thebrokenrail.reliccraft.item.TimeDilaterItem; +import com.thebrokenrail.reliccraft.item.RelicItem; +import com.thebrokenrail.reliccraft.mixin.CriteriaRegistryHook; +import com.thebrokenrail.reliccraft.recipe.RevealRelicRecipe; +import com.thebrokenrail.reliccraft.recipe.TimeDilaterRecipe; +import com.thebrokenrail.reliccraft.structure.TimeTempleFeature; +import com.thebrokenrail.reliccraft.structure.TimeTempleGenerator; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.entity.FabricEntityTypeBuilder; +import net.fabricmc.fabric.api.loot.v1.FabricLootPoolBuilder; +import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback; +import net.fabricmc.fabric.api.tag.TagRegistry; +import net.minecraft.block.Block; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.EntityCategory; +import net.minecraft.entity.EntityDimensions; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.loot.BinomialLootTableRange; +import net.minecraft.loot.LootTables; +import net.minecraft.loot.entry.ItemEntry; +import net.minecraft.recipe.SpecialRecipeSerializer; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.structure.StructurePieceType; +import net.minecraft.util.Identifier; +import net.minecraft.util.Rarity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.GenerationStep; +import net.minecraft.world.gen.chunk.FlatChunkGeneratorConfig; +import net.minecraft.world.gen.decorator.Decorator; +import net.minecraft.world.gen.decorator.DecoratorConfig; +import net.minecraft.world.gen.feature.ConfiguredFeature; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.FeatureConfig; +import net.minecraft.world.gen.feature.StructureFeature; + +import java.util.Locale; + +public class RelicCraft implements ModInitializer { + public static final String NAMESPACE = "reliccraft"; + + public static Item ORB_ITEM; + public static Item STAFF_ITEM; + public static Item TIME_DILATER_ITEM; + + public static Item TARGETED_ENDER_PEARL_ITEM; + + public static EntityType RELIC_ENTITY; + + public static SpecialRecipeSerializer REVEAL_RELIC_RECIPE; + public static SpecialRecipeSerializer TIME_DILATER_RECIPE; + + public static Block TELEPORTATION_RESTRICTOR_BLOCK; + public static Block TELEPORTATION_BEACON_BLOCK; + public static BlockEntityType DRAGON_EGG_HOLDER_BLOCK_ENTITY; + + public static final Identifier[] LOOT_TABLES = new Identifier[]{ + LootTables.SIMPLE_DUNGEON_CHEST, + LootTables.END_CITY_TREASURE_CHEST, + LootTables.NETHER_BRIDGE_CHEST, + LootTables.ABANDONED_MINESHAFT_CHEST, + LootTables.SHIPWRECK_TREASURE_CHEST, + LootTables.DESERT_PYRAMID_CHEST, + LootTables.JUNGLE_TEMPLE_CHEST, + LootTables.STRONGHOLD_LIBRARY_CHEST, + LootTables.PILLAGER_OUTPOST_CHEST, + LootTables.WOODLAND_MANSION_CHEST, + LootTables.BURIED_TREASURE_CHEST, + LootTables.FISHING_TREASURE_GAMEPLAY + }; + + public static ActivateTeleportationRestrictorCriterion ACTIVATE_TELEPORTATION_RESTRICTOR_CRITERION; + public static RevealRelicCriterion REVEAL_RELIC_CRITERION; + public static DilateTimeCriterion DILATE_TIME_CRITERION; + public static DuplicateTimeDilaterCriterion DUPLICATE_TIME_DILATER_CRITERION; + public static ActivateTeleportationBeaconCriterion ACTIVATE_TELEPORTATION_BEACON_CRITERION; + public static UseTeleportationBeaconCriterion USE_TELEPORTATION_BEACON_CRITERION; + public static UseTargetedEnderPearlCriterion USE_TARGETED_ENDER_PEARL; + + private boolean isSelectedLootTable(Identifier lootTable) { + for (Identifier id : LOOT_TABLES) { + if (id.equals(lootTable)) { + return true; + } + } + return false; + } + + private static final SoundEvent RELIC_SOUND_EFFECT = SoundEvents.BLOCK_ENCHANTMENT_TABLE_USE; + private static final SoundEvent INTERACT_TELEPORT_RESTRICTOR_SOUND_EFFECT = SoundEvents.BLOCK_END_PORTAL_FRAME_FILL; + + public static void playRelicSound(PlayerEntity player) { + player.playSound(RELIC_SOUND_EFFECT, SoundCategory.PLAYERS, 1.0f, 1.0f); + } + + public static void playInteractTeleportRestrictorSound(World world, BlockPos pos) { + world.playSound(null, pos, INTERACT_TELEPORT_RESTRICTOR_SOUND_EFFECT, SoundCategory.BLOCKS, 1.0f, 1.0f); + } + + public static StructureFeature TIME_TEMPLE_STRUCTURE_FEATURE; + public static StructurePieceType TIME_TEMPLE_STRUCTURE_PIECE; + public static final String TIME_TEMPLE_ID = "RelicCraft Time Temple"; + + @Override + public void onInitialize() { + ORB_ITEM = Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "orb"), new RelicItem()); + STAFF_ITEM = Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "staff"), new RelicItem()); + TIME_DILATER_ITEM = Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "time_dilater"), new TimeDilaterItem()); + + TARGETED_ENDER_PEARL_ITEM = Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "targeted_ender_pearl"), new TargetedEnderPearlItem()); + + RELIC_ENTITY = FabricEntityTypeBuilder.create(EntityCategory.MISC, (EntityType.EntityFactory) RelicEntity::new).size(EntityDimensions.fixed(0.25f, 0.25f)).build(); + + LootTableLoadingCallback.EVENT.register((resourceManager, lootManager, id, supplier, setter) -> { + if (isSelectedLootTable(id)) { + FabricLootPoolBuilder poolBuilder = FabricLootPoolBuilder.builder() + .withRolls(new BinomialLootTableRange(2, 0.5f)) + .withEntry(ItemEntry.builder(ORB_ITEM)) + .withEntry(ItemEntry.builder(STAFF_ITEM)) + .withFunction(new RelicLootTableFunction.Builder()); + + supplier.withPool(poolBuilder); + } + }); + + REVEAL_RELIC_RECIPE = Registry.register(Registry.RECIPE_SERIALIZER, new Identifier(NAMESPACE, "reveal_relic"), new SpecialRecipeSerializer<>(RevealRelicRecipe::new)); + TIME_DILATER_RECIPE = Registry.register(Registry.RECIPE_SERIALIZER, new Identifier(NAMESPACE, "time_dilater"), new SpecialRecipeSerializer<>(TimeDilaterRecipe::new)); + + TELEPORTATION_RESTRICTOR_BLOCK = Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "teleportation_restrictor"), new TeleportationRestrictorBlock()); + TELEPORTATION_BEACON_BLOCK = Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "teleportation_beacon"), new TeleportationBeaconBlock()); + DRAGON_EGG_HOLDER_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier(NAMESPACE, "dragon_egg_holder"), BlockEntityType.Builder.create(DragonEggHolderBlockEntity::new, TELEPORTATION_RESTRICTOR_BLOCK, TELEPORTATION_BEACON_BLOCK).build(null)); + + Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "teleportation_restrictor"), new BlockItem(TELEPORTATION_RESTRICTOR_BLOCK, new Item.Settings().group(ItemGroup.MISC).rarity(Rarity.UNCOMMON))); + Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "teleportation_beacon"), new BlockItem(TELEPORTATION_BEACON_BLOCK, new Item.Settings().group(ItemGroup.MISC).rarity(Rarity.UNCOMMON))); + + ACTIVATE_TELEPORTATION_RESTRICTOR_CRITERION = CriteriaRegistryHook.callRegister(new ActivateTeleportationRestrictorCriterion()); + REVEAL_RELIC_CRITERION = CriteriaRegistryHook.callRegister(new RevealRelicCriterion()); + DILATE_TIME_CRITERION = CriteriaRegistryHook.callRegister(new DilateTimeCriterion()); + DUPLICATE_TIME_DILATER_CRITERION = CriteriaRegistryHook.callRegister(new DuplicateTimeDilaterCriterion()); + ACTIVATE_TELEPORTATION_BEACON_CRITERION = CriteriaRegistryHook.callRegister(new ActivateTeleportationBeaconCriterion()); + USE_TELEPORTATION_BEACON_CRITERION = CriteriaRegistryHook.callRegister(new UseTeleportationBeaconCriterion()); + USE_TARGETED_ENDER_PEARL = CriteriaRegistryHook.callRegister(new UseTargetedEnderPearlCriterion()); + + //noinspection ResultOfMethodCallIgnored + TagRegistry.item(new Identifier(NAMESPACE, "relics")); + + TIME_TEMPLE_STRUCTURE_PIECE = Registry.register(Registry.STRUCTURE_PIECE, new Identifier(NAMESPACE, "time_temple"), TimeTempleGenerator.Piece::new); + TIME_TEMPLE_STRUCTURE_FEATURE = Registry.register(Registry.FEATURE, new Identifier(NAMESPACE, "time_temple"), new TimeTempleFeature(DefaultFeatureConfig::deserialize)); + Registry.register(Registry.STRUCTURE_FEATURE, new Identifier(NAMESPACE, "time_temple"), TIME_TEMPLE_STRUCTURE_FEATURE); + + Feature.STRUCTURES.put(TIME_TEMPLE_ID.toLowerCase(Locale.ROOT), TIME_TEMPLE_STRUCTURE_FEATURE); + + ConfiguredFeature configuredFeature = TIME_TEMPLE_STRUCTURE_FEATURE.configure(FeatureConfig.DEFAULT).createDecoratedFeature(Decorator.NOPE.configure(DecoratorConfig.DEFAULT)); + + for (Biome biome : Registry.BIOME) { + biome.addFeature(GenerationStep.Feature.SURFACE_STRUCTURES, configuredFeature); + if (biome.getCategory() == Biome.Category.PLAINS) { + biome.addStructureFeature(TIME_TEMPLE_STRUCTURE_FEATURE.configure(FeatureConfig.DEFAULT)); + } + } + + FlatChunkGeneratorConfig.FEATURE_TO_GENERATION_STEP.put(configuredFeature, GenerationStep.Feature.SURFACE_STRUCTURES); + FlatChunkGeneratorConfig.FEATURE_TO_FEATURE_CONFIG.put(configuredFeature, FeatureConfig.DEFAULT); + FlatChunkGeneratorConfig.STRUCTURE_TO_FEATURES.put(NAMESPACE + "_time_temple", new ConfiguredFeature[]{configuredFeature}); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/RelicLootTableFunction.java b/src/main/java/com/thebrokenrail/reliccraft/RelicLootTableFunction.java new file mode 100644 index 0000000..c5e2bcc --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/RelicLootTableFunction.java @@ -0,0 +1,42 @@ +package com.thebrokenrail.reliccraft; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.thebrokenrail.reliccraft.data.RelicData; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.condition.LootCondition; +import net.minecraft.loot.context.LootContext; +import net.minecraft.loot.function.ConditionalLootFunction; +import net.minecraft.loot.function.LootFunction; +import net.minecraft.nbt.CompoundTag; + +public class RelicLootTableFunction extends ConditionalLootFunction { + private RelicLootTableFunction(LootCondition[] conditions) { + super(conditions); + } + + public ItemStack process(ItemStack stack, LootContext context) { + CompoundTag tag = new CompoundTag(); + Moshi moshi = new Moshi.Builder().build(); + JsonAdapter jsonAdapter = moshi.adapter(RelicData.class); + tag.putString("RelicData", jsonAdapter.toJson(RelicData.generate(context.getRandom()))); + stack.setTag(tag); + double chance = 1.0d; + while (!(context.getRandom().nextDouble() > chance)) { + chance = chance * 0.25d; + } + return stack; + } + + public static class Builder extends ConditionalLootFunction.Builder { + @Override + protected RelicLootTableFunction.Builder getThisBuilder() { + return this; + } + + public LootFunction build() { + return new RelicLootTableFunction(getConditions()); + } + } +} + diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/ActivateTeleportationBeaconCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/ActivateTeleportationBeaconCriterion.java new file mode 100644 index 0000000..aec0a6c --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/ActivateTeleportationBeaconCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class ActivateTeleportationBeaconCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "activate_teleportation_beacon"); + + public ActivateTeleportationBeaconCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/ActivateTeleportationRestrictorCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/ActivateTeleportationRestrictorCriterion.java new file mode 100644 index 0000000..1cfde99 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/ActivateTeleportationRestrictorCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class ActivateTeleportationRestrictorCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "activate_teleportation_restrictor"); + + public ActivateTeleportationRestrictorCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/DilateTimeCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/DilateTimeCriterion.java new file mode 100644 index 0000000..345dcc7 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/DilateTimeCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class DilateTimeCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "dilate_time"); + + public DilateTimeCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/DuplicateTimeDilaterCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/DuplicateTimeDilaterCriterion.java new file mode 100644 index 0000000..4cca952 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/DuplicateTimeDilaterCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class DuplicateTimeDilaterCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "duplicate_time_dilater"); + + public DuplicateTimeDilaterCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/RevealRelicCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/RevealRelicCriterion.java new file mode 100644 index 0000000..5388f16 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/RevealRelicCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class RevealRelicCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "reveal_relic"); + + public RevealRelicCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/UseTargetedEnderPearlCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/UseTargetedEnderPearlCriterion.java new file mode 100644 index 0000000..858261a --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/UseTargetedEnderPearlCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class UseTargetedEnderPearlCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "use_targeted_ender_pearl"); + + public UseTargetedEnderPearlCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/advancement/UseTeleportationBeaconCriterion.java b/src/main/java/com/thebrokenrail/reliccraft/advancement/UseTeleportationBeaconCriterion.java new file mode 100644 index 0000000..161e075 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/advancement/UseTeleportationBeaconCriterion.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.advancement; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.advancement.criterion.AbstractCriterion; +import net.minecraft.advancement.criterion.AbstractCriterionConditions; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public class UseTeleportationBeaconCriterion extends AbstractCriterion { + private static final Identifier ID = new Identifier(RelicCraft.NAMESPACE, "use_teleportation_beacon"); + + public UseTeleportationBeaconCriterion() { + } + + public Identifier getId() { + return ID; + } + + public Conditions conditionsFromJson(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) { + return new Conditions(); + } + + public void trigger(ServerPlayerEntity player) { + test(player.getAdvancementTracker(), conditions -> true); + } + + public static class Conditions extends AbstractCriterionConditions { + public Conditions() { + super(ID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/block/AbstractDragonEggHolderBlock.java b/src/main/java/com/thebrokenrail/reliccraft/block/AbstractDragonEggHolderBlock.java new file mode 100644 index 0000000..ac27fc8 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/block/AbstractDragonEggHolderBlock.java @@ -0,0 +1,129 @@ +package com.thebrokenrail.reliccraft.block; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.container.Container; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; + +import java.util.Random; + +@SuppressWarnings("deprecation") +public abstract class AbstractDragonEggHolderBlock extends Block implements BlockEntityProvider { + public static final BooleanProperty ACTIVE = BooleanProperty.of("active"); + + public AbstractDragonEggHolderBlock(Settings settings) { + super(settings); + setDefaultState(getStateManager().getDefaultState().with(ACTIVE, false)); + } + + @Override + public int getLuminance(BlockState state) { + return state.get(ACTIVE) ? 7 : 0; + } + + @Override + public BlockEntity createBlockEntity(BlockView view) { + return new DragonEggHolderBlockEntity(); + } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + Inventory blockEntity = (Inventory) world.getBlockEntity(pos); + + if (blockEntity != null) { + ItemStack stack = player.getStackInHand(hand); + + if (!stack.isEmpty()) { + if (blockEntity.isValidInvStack(0, stack) && blockEntity.getInvStack(0).isEmpty()) { + blockEntity.setInvStack(0, stack.split(1)); + if (!world.isClient()) { + grantAdvancement(player); + } + return ActionResult.SUCCESS; + } else { + return ActionResult.PASS; + } + } else { + if (!blockEntity.getInvStack(0).isEmpty()) { + player.inventory.offerOrDrop(world, blockEntity.getInvStack(0)); + blockEntity.removeInvStack(0); + return ActionResult.SUCCESS; + } else { + return ActionResult.PASS; + } + } + } else { + return ActionResult.PASS; + } + } + + private boolean isActive(World world, BlockPos pos) { + return world.getBlockState(pos).get(ACTIVE); + } + + @Override + @Environment(EnvType.CLIENT) + public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { + if (isActive(world, pos)) { + if (random.nextInt(100) == 0) { + world.playSound(null, pos, SoundEvents.BLOCK_PORTAL_AMBIENT, SoundCategory.BLOCKS, 0.5F, random.nextFloat() * 0.4F + 0.8F); + } + + for (int i = 0; i < 24; ++i) { + double x = (double) pos.getX() + 0.5D + (double) (0.5F - random.nextFloat()); + double y = (double) pos.getY() + 0.5D + (double) (0.5F - random.nextFloat()); + double z = (double) pos.getZ() + 0.5D + (double) (0.5F - random.nextFloat()); + world.addParticle(ParticleTypes.PORTAL, x, y, z, (random.nextDouble() - 0.5D) * 2.0D, -random.nextDouble(), (random.nextDouble() - 0.5D) * 2.0D); + } + } + } + + @Override + public void onBlockRemoved(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof Inventory) { + ItemScatterer.spawn(world, pos, (Inventory) blockEntity); + } + + super.onBlockRemoved(state, world, pos, newState, moved); + } + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + builder.add(ACTIVE); + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return Container.calculateComparatorOutput(world.getBlockEntity(pos)); + } + + public abstract void tick(World world, BlockPos pos, Inventory inventory); + + public abstract void grantAdvancement(PlayerEntity player); +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/block/DragonEggHolderBlockEntity.java b/src/main/java/com/thebrokenrail/reliccraft/block/DragonEggHolderBlockEntity.java new file mode 100644 index 0000000..fa02836 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/block/DragonEggHolderBlockEntity.java @@ -0,0 +1,121 @@ +package com.thebrokenrail.reliccraft.block; + +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.DefaultedList; +import net.minecraft.util.Tickable; + +public class DragonEggHolderBlockEntity extends BlockEntity implements Inventory, Tickable { + public DragonEggHolderBlockEntity() { + super(RelicCraft.DRAGON_EGG_HOLDER_BLOCK_ENTITY); + } + + @Override + public void fromTag(CompoundTag tag) { + super.fromTag(tag); + DefaultedList list = DefaultedList.ofSize(getInvSize(), ItemStack.EMPTY); + Inventories.fromTag(tag, list); + stack = list.get(0); + } + + @Override + public CompoundTag toTag(CompoundTag tag) { + DefaultedList list = DefaultedList.ofSize(getInvSize(), ItemStack.EMPTY); + list.set(0, stack); + Inventories.toTag(tag, list); + return super.toTag(tag); + } + + private ItemStack stack = ItemStack.EMPTY; + + @Override + public int getInvSize() { + return 1; + } + + @Override + public int getInvMaxStackAmount() { + return 1; + } + + @Override + public boolean isInvEmpty() { + return stack.isEmpty(); + } + + @Override + public ItemStack getInvStack(int slot) { + return stack; + } + + @Override + public ItemStack takeInvStack(int slot, int amount) { + ItemStack newStack = getInvStack(0).split(amount); + markDirty(); + return newStack; + } + + @Override + public ItemStack removeInvStack(int slot) { + ItemStack newStack = getInvStack(0).copy(); + setInvStack(0, ItemStack.EMPTY); + return newStack; + } + + @Override + public void setInvStack(int slot, ItemStack stack) { + this.stack = stack; + if (stack.getCount() > getInvMaxStackAmount()) { + stack.setCount(getInvMaxStackAmount()); + } + markDirty(); + } + + @Override + public boolean canPlayerUseInv(PlayerEntity player) { + return true; + } + + @Override + public void clear() { + setInvStack(0, ItemStack.EMPTY); + } + + @Override + public void tick() { + if (hasWorld()) { + assert getWorld() != null; + Block block = getWorld().getBlockState(getPos()).getBlock(); + if (block instanceof AbstractDragonEggHolderBlock) { + ((AbstractDragonEggHolderBlock) block).tick(getWorld(), getPos(), this); + } + } + } + + @Override + public boolean isValidInvStack(int slot, ItemStack stack) { + return stack.getItem() == Items.DRAGON_EGG; + } + + @Override + public void markDirty() { + super.markDirty(); + if (hasWorld()) { + assert getWorld() != null; + BlockState state = getWorld().getBlockState(pos); + boolean active = !getInvStack(0).isEmpty(); + if (state.get(TeleportationRestrictorBlock.ACTIVE) != active) { + getWorld().setBlockState(getPos(), state.with(TeleportationRestrictorBlock.ACTIVE, active)); + RelicCraft.playInteractTeleportRestrictorSound(getWorld(), getPos()); + } + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/block/TeleportationBeaconBlock.java b/src/main/java/com/thebrokenrail/reliccraft/block/TeleportationBeaconBlock.java new file mode 100644 index 0000000..0d7c490 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/block/TeleportationBeaconBlock.java @@ -0,0 +1,27 @@ +package com.thebrokenrail.reliccraft.block; + +import com.thebrokenrail.reliccraft.RelicCraft; +import net.fabricmc.fabric.api.block.FabricBlockSettings; +import net.minecraft.block.Material; +import net.minecraft.block.MaterialColor; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.BlockSoundGroup; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class TeleportationBeaconBlock extends AbstractDragonEggHolderBlock { + public TeleportationBeaconBlock() { + super(FabricBlockSettings.of(Material.METAL, MaterialColor.IRON).strength(5.0F, 6.0F).sounds(BlockSoundGroup.METAL).build()); + } + + @Override + public void tick(World world, BlockPos pos, Inventory inventory) { + } + + @Override + public void grantAdvancement(PlayerEntity player) { + RelicCraft.ACTIVATE_TELEPORTATION_BEACON_CRITERION.trigger((ServerPlayerEntity) player); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/block/TeleportationRestrictorBlock.java b/src/main/java/com/thebrokenrail/reliccraft/block/TeleportationRestrictorBlock.java new file mode 100644 index 0000000..4cfc0e0 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/block/TeleportationRestrictorBlock.java @@ -0,0 +1,42 @@ +package com.thebrokenrail.reliccraft.block; + +import com.thebrokenrail.reliccraft.RelicCraft; +import net.fabricmc.fabric.api.block.FabricBlockSettings; +import net.minecraft.block.Material; +import net.minecraft.block.MaterialColor; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.world.World; + +import java.util.List; + +public class TeleportationRestrictorBlock extends AbstractDragonEggHolderBlock { + public interface TeleportingEntity { + boolean cannotTeleport(); + + void resetTeleportCooldown(); + } + + public TeleportationRestrictorBlock() { + super(FabricBlockSettings.of(Material.STONE, MaterialColor.BLACK).strength(50.0F, 1200.0F).build()); + } + + @Override + public void tick(World world, BlockPos pos, Inventory inventory) { + int radius = !inventory.getInvStack(0).isEmpty() ? 128 : 0; + Box box = new Box(pos).expand(radius); + List list = world.getNonSpectatingEntities(LivingEntity.class, box); + for (LivingEntity entity : list) { + ((TeleportingEntity) entity).resetTeleportCooldown(); + } + } + + @Override + public void grantAdvancement(PlayerEntity player) { + RelicCraft.ACTIVATE_TELEPORTATION_RESTRICTOR_CRITERION.trigger((ServerPlayerEntity) player); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/client/RelicCraftClient.java b/src/main/java/com/thebrokenrail/reliccraft/client/RelicCraftClient.java new file mode 100644 index 0000000..5bfb94c --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/client/RelicCraftClient.java @@ -0,0 +1,60 @@ +package com.thebrokenrail.reliccraft.client; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.client.entity.RelicEntityRenderer; +import com.thebrokenrail.reliccraft.item.RelicItem; +import com.thebrokenrail.reliccraft.packet.UpdateTimeDilationS2CPacket; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; +import net.fabricmc.fabric.impl.networking.ClientSidePacketRegistryImpl; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; + +@SuppressWarnings("unused") +@Environment(EnvType.CLIENT) +public class RelicCraftClient implements ClientModInitializer { + public static int generateColor(float h, float s, float v) { + float r, g, b, i, f, p, q, t; + i = (float) Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch ((int) (i % 6)) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + default: throw new UnsupportedOperationException(); + } + return rgbToDecimal(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)); + } + + private static int rgbToDecimal(int r, int g, int b) { + return (r << 16) | (g << 8) | b; + } + + private static int getStackColor(ItemStack stack) { + if (stack.getName().asString().equals("jeb_")) { + return generateColor(Util.getMeasuringTimeMs() / 3600f, 1f, 1f); + } else { + return RelicItem.getData(stack).color; + } + } + + @Override + public void onInitializeClient() { + ColorProviderRegistry.ITEM.register((stack, tintIndex) -> tintIndex > 0 ? -1 : getStackColor(stack), RelicCraft.ORB_ITEM); + ColorProviderRegistry.ITEM.register((stack, tintIndex) -> tintIndex > 0 ? -1 : getStackColor(stack), RelicCraft.STAFF_ITEM); + + EntityRendererRegistry.INSTANCE.register(RelicCraft.RELIC_ENTITY, (entityRenderDispatcher, context) -> new RelicEntityRenderer(entityRenderDispatcher)); + + ClientSidePacketRegistryImpl.INSTANCE.register(new Identifier(RelicCraft.NAMESPACE, "update_time_dilation"), UpdateTimeDilationS2CPacket::handle); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/client/entity/RelicEntityRenderer.java b/src/main/java/com/thebrokenrail/reliccraft/client/entity/RelicEntityRenderer.java new file mode 100644 index 0000000..d2337d2 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/client/entity/RelicEntityRenderer.java @@ -0,0 +1,20 @@ +package com.thebrokenrail.reliccraft.client.entity; + +import com.thebrokenrail.reliccraft.entity.RelicEntity; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.util.Identifier; + +@Environment(EnvType.CLIENT) +public class RelicEntityRenderer extends EntityRenderer { + public RelicEntityRenderer(EntityRenderDispatcher entityRenderDispatcher) { + super(entityRenderDispatcher); + } + + @Override + public Identifier getTexture(RelicEntity relicEntity) { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebrokenrail/reliccraft/data/Action.java b/src/main/java/com/thebrokenrail/reliccraft/data/Action.java new file mode 100644 index 0000000..a268a3b --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/data/Action.java @@ -0,0 +1,23 @@ +package com.thebrokenrail.reliccraft.data; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface Action { + void execute(World world, LivingEntity attacker, Entity target); + + void execute(World world, LivingEntity attacker, BlockPos pos); + + int getCost(); + + default PlayerEntity convertToPlayer(LivingEntity entity) { + if (entity instanceof PlayerEntity) { + return (PlayerEntity) entity; + } else { + return null; + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/data/Actions.java b/src/main/java/com/thebrokenrail/reliccraft/data/Actions.java new file mode 100644 index 0000000..705ad4d --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/data/Actions.java @@ -0,0 +1,357 @@ +package com.thebrokenrail.reliccraft.data; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.SpawnType; +import net.minecraft.entity.mob.ZombieEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public class Actions { + private static final Map actions = new HashMap<>(); + + public static void register(String id, Action action) { + actions.put(id, action); + } + + public static Action get(String id) { + return actions.get(id); + } + + private static String getRandomAction(int budget, Random random) { + List options = new ArrayList<>(); + + for (Map.Entry entry : actions.entrySet()) { + if (budget >= entry.getValue().getCost()) { + options.add(entry.getKey()); + } + } + + if (options.size() < 1) { + return null; + } else { + return options.get(random.nextInt(options.size())); + } + } + + public static String[] getRandomActions(Random random) { + List chosen = new ArrayList<>(); + int amount = random.nextInt(3) + 1; + for (int i = 0; i < amount; i++) { + int budget = random.nextInt(100) + 1; + String action = getRandomAction(budget, random); + if (action != null) { + chosen.add(action); + } + } + return chosen.toArray(new String[0]); + } + + public static class HalfHeartAction implements Action { + @Override + public int getCost() { + return 0; + } + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + if (target instanceof LivingEntity) { + ((LivingEntity) target).setHealth(1f); + } + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + } + } + + public static class SwapBlockAction implements Action { + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + execute(world, attacker, target.getBlockPos().down()); + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + BlockState state1 = world.getBlockState(attacker.getBlockPos().down()); + BlockState state2 = world.getBlockState(pos); + world.setBlockState(attacker.getBlockPos().down(), state2); + world.setBlockState(pos, state1); + } + + @Override + public int getCost() { + return 0; + } + } + + public static class DirtAction implements Action { + @Override + public int getCost() { + return 15; + } + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + target.remove(); + target.kill(); + world.setBlockState(target.getBlockPos(), Blocks.DIRT.getDefaultState()); + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + world.setBlockState(pos, Blocks.DIRT.getDefaultState()); + } + } + + public static class NetherAction implements Action { + @Override + public int getCost() { + return 25; + } + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + BlockPos pos = target.getBlockPos(); + BlockState state = world.getBlockState(pos); + world.setBlockState(pos, Blocks.NETHER_PORTAL.getDefaultState()); + target.changeDimension(world.dimension.getType() == DimensionType.THE_NETHER ? DimensionType.OVERWORLD : DimensionType.THE_NETHER); + world.setBlockState(pos, state); + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + world.setBlockState(pos, Blocks.LAVA.getDefaultState()); + } + } + + public static class EndAction implements Action { + @Override + public int getCost() { + return 50; + } + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + target.changeDimension(world.dimension.getType() == DimensionType.THE_END ? DimensionType.OVERWORLD : DimensionType.THE_END); + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + world.setBlockState(pos, Blocks.END_STONE.getDefaultState()); + } + } + + public static class DiamondAction extends ConversionAction { + @Override + public int getCost() { + return 99; + } + + @Override + public Item getTargetItem() { + return Items.GOLD_INGOT; + } + + @Override + public Item getConvertedItem() { + return Items.DIAMOND; + } + + @Override + public Block getTargetBlock() { + return Blocks.GOLD_BLOCK; + } + + @Override + public Block getConvertedBlock() { + return Blocks.DIAMOND_BLOCK; + } + } + + public abstract static class ConversionAction implements Action { + @Override + public abstract int getCost(); + + public abstract Item getTargetItem(); + + public abstract Item getConvertedItem(); + + public abstract Block getTargetBlock(); + + public abstract Block getConvertedBlock(); + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + if (target instanceof PlayerEntity) { + PlayerEntity player = (PlayerEntity) target; + for (int i = 0; i < player.inventory.getInvSize(); i++) { + ItemStack stack = player.inventory.getInvStack(i); + if (stack.getItem() == getTargetItem()) { + player.inventory.setInvStack(i, new ItemStack(getConvertedItem(), stack.getCount())); + } + } + } + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + if (world.getBlockState(pos).getBlock() == getTargetBlock()) { + world.setBlockState(pos, getConvertedBlock().getDefaultState()); + } + } + } + + public static class GoldAction extends ConversionAction { + @Override + public int getCost() { + return 45; + } + + @Override + public Item getTargetItem() { + return Items.COAL; + } + + @Override + public Item getConvertedItem() { + return Items.GOLD_INGOT; + } + + @Override + public Block getTargetBlock() { + return Blocks.COAL_BLOCK; + } + + @Override + public Block getConvertedBlock() { + return Blocks.GOLD_BLOCK; + } + } + + public static class BedrockAction implements Action { + @Override + public int getCost() { + return 60; + } + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + target.remove(); + target.kill(); + world.setBlockState(target.getBlockPos(), Blocks.BEDROCK.getDefaultState()); + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + world.setBlockState(pos, Blocks.BEDROCK.getDefaultState()); + } + } + + public static class HealAction implements Action { + @Override + public int getCost() { + return 0; + } + + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + if (target instanceof LivingEntity) { + ((LivingEntity) target).heal(Float.MAX_VALUE); + } + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + } + } + + public static class ZombifyAction implements Action { + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + ZombieEntity zombie = new ZombieEntity(world); + zombie.updatePosition(target.getX(), target.getY(), target.getZ()); + world.spawnEntity(zombie); + target.remove(); + target.kill(); + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + ZombieEntity zombie = new ZombieEntity(world); + zombie.updatePosition(attacker.getX(), attacker.getY(), attacker.getZ()); + world.spawnEntity(zombie); + attacker.remove(); + attacker.kill(); + } + + @Override + public int getCost() { + return 50; + } + } + + public static class RandomAction implements Action { + @Override + public void execute(World world, LivingEntity attacker, Entity target) { + if (!target.removed) { + target.remove(); + target.kill(); + } + int entityID = new Random().nextInt(Registry.ENTITY_TYPE.getIds().size()); + EntityType entityType = Registry.ENTITY_TYPE.get(entityID); + if (entityType.isSummonable()) { + Entity entity = entityType.spawn(world, null, null, convertToPlayer(attacker), target.getBlockPos(), SpawnType.CONVERSION, false, false); + if (entity != null) { + entity.updatePosition(target.getX(), target.getY(), target.getZ()); + } else { + execute(world, attacker, target); + } + } else { + execute(world, attacker, target); + } + } + + @Override + public void execute(World world, LivingEntity attacker, BlockPos pos) { + int blockID = new Random().nextInt(Registry.BLOCK.getIds().size()); + Block block = Registry.BLOCK.get(blockID); + world.setBlockState(pos, block.getDefaultState()); + } + + @Override + public int getCost() { + return 70; + } + } + + static { + register("half_heart_action", new HalfHeartAction()); + register("swap_block_action", new SwapBlockAction()); + register("heal_action", new HealAction()); + register("bedrock_action", new BedrockAction()); + register("gold_action", new GoldAction()); + register("diamond_action", new DiamondAction()); + register("end_action", new EndAction()); + register("nether_action", new NetherAction()); + register("dirt_action", new DirtAction()); + register("zombify_action", new ZombifyAction()); + register("random_action", new RandomAction()); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/data/RelicData.java b/src/main/java/com/thebrokenrail/reliccraft/data/RelicData.java new file mode 100644 index 0000000..f3ae205 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/data/RelicData.java @@ -0,0 +1,63 @@ +package com.thebrokenrail.reliccraft.data; + +import java.util.Random; + +public class RelicData { + public static class NameData { + public static final int VARIANT_MAX = 3; + public int variant = 0; + public static final int MAGIC_WORD_MAX = 7; + public int magicWord = 0; + } + + public static final int[] COLORS = new int[]{ + 65535, + 65280, + 16776960, + 16711935, + 255, + 16711680 + }; + + public int color = COLORS[0]; + + public NameData name = new NameData(); + + public boolean enchantmentGlint = false; + + public static final int MIN_DURABILITY = 20; + public static final int MAX_DURABILITY = 40; + + public int maxDurability = 0; + + public String[] attack = new String[0]; + + public static class UseData { + public enum Mode { + PROJECTILE, + TARGET, + SELF + } + public String[] actions = new String[0]; + public Mode mode = Mode.SELF; + } + + public UseData use = new UseData(); + + public static RelicData generate(Random random) { + RelicData data = new RelicData(); + NameData name = new NameData(); + name.variant = random.nextInt(NameData.VARIANT_MAX); + name.magicWord = random.nextInt(NameData.MAGIC_WORD_MAX); + data.name = name; + data.enchantmentGlint = random.nextBoolean(); + data.maxDurability = random.nextInt(MAX_DURABILITY + 1) + MIN_DURABILITY; + data.attack = Actions.getRandomActions(random); + UseData use = new UseData(); + use.mode = UseData.Mode.values()[random.nextInt(UseData.Mode.values().length)]; + use.actions = Actions.getRandomActions(random); + data.use = use; + data.color = COLORS[random.nextInt(COLORS.length)]; + return data; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/entity/RelicEntity.java b/src/main/java/com/thebrokenrail/reliccraft/entity/RelicEntity.java new file mode 100644 index 0000000..1d83802 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/entity/RelicEntity.java @@ -0,0 +1,82 @@ +package com.thebrokenrail.reliccraft.entity; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.data.Action; +import com.thebrokenrail.reliccraft.data.Actions; +import com.thebrokenrail.reliccraft.item.RelicItem; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.thrown.ThrownItemEntity; +import net.minecraft.item.Item; +import net.minecraft.network.Packet; +import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.world.World; + +import java.util.List; +import java.util.Objects; + +@SuppressWarnings("unused") +public class RelicEntity extends ThrownItemEntity { + public RelicEntity(EntityType entityType, World world) { + super(entityType, world); + } + + public RelicEntity(World world, LivingEntity owner) { + super(RelicCraft.RELIC_ENTITY, owner, world); + } + + public RelicEntity(World world, double x, double y, double z) { + super(RelicCraft.RELIC_ENTITY, x, y, z, world); + } + + public RelicEntity(World world) { + super(RelicCraft.RELIC_ENTITY, world); + } + + @Override + protected void onCollision(HitResult hitResult) { + if (!getEntityWorld().isClient()) { + String[] actions = RelicItem.getData(getItem()).use.actions; + String id = actions[random.nextInt(actions.length)]; + Action action = Actions.get(id); + if (action != null) { + if (hitResult.getType() == HitResult.Type.BLOCK) { + BlockHitResult blockHitResult = (BlockHitResult) hitResult; + action.execute(getEntityWorld(), getOwner(), blockHitResult.getBlockPos()); + } else if (hitResult.getType() == HitResult.Type.ENTITY) { + Entity entity = ((EntityHitResult) hitResult).getEntity(); + action.execute(world, getOwner(), entity); + } + } + remove(); + } + } + + @Override + public void tick() { + super.tick(); + if (!getEntityWorld().isClient()) { + List viewers = Objects.requireNonNull(getServer()).getPlayerManager().getPlayerList(); + for (ServerPlayerEntity viewer : viewers) { + ((ServerWorld) getEntityWorld()).spawnParticles(viewer, ParticleTypes.WITCH, true, getX(), getY(), getZ(), 8, 0.1d, 0.1d, 0.1d, 0d); + } + } + } + + @Override + protected Item getDefaultItem() { + return RelicCraft.STAFF_ITEM; + } + + @Override + public Packet createSpawnPacket() { + return new EntitySpawnS2CPacket(this); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/item/RelicItem.java b/src/main/java/com/thebrokenrail/reliccraft/item/RelicItem.java new file mode 100644 index 0000000..d25580e --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/item/RelicItem.java @@ -0,0 +1,221 @@ +package com.thebrokenrail.reliccraft.item; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.data.Action; +import com.thebrokenrail.reliccraft.data.Actions; +import com.thebrokenrail.reliccraft.data.RelicData; +import com.thebrokenrail.reliccraft.entity.RelicEntity; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.BlockState; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.Rarity; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.List; + +public class RelicItem extends Item { + public RelicItem() { + super(new Settings().rarity(Rarity.UNCOMMON).maxDamage(1)); + } + + @Override + public Text getName(ItemStack stack) { + RelicData data = getData(stack); + return new TranslatableText("text." + RelicCraft.NAMESPACE + ".relic.title_variant." + data.name.variant, super.getName(stack), new TranslatableText("text." + RelicCraft.NAMESPACE + ".relic.magic_word." + data.name.magicWord)); + } + + public static RelicData getData(ItemStack stack) { + CompoundTag tag = stack.getTag(); + if (tag == null) { + return new RelicData(); + } + + Moshi moshi = new Moshi.Builder().build(); + JsonAdapter jsonAdapter = moshi.adapter(RelicData.class); + + try { + return jsonAdapter.fromJson(tag.getString("RelicData")); + } catch (Throwable e) { + return new RelicData(); + } + } + + public int getMaxDamage(ItemStack stack) { + return getData(stack).maxDurability; + } + + @Override + public boolean hasEnchantmentGlint(ItemStack stack) { + RelicData data = getData(stack); + return super.hasEnchantmentGlint(stack) || data.enchantmentGlint; + } + + @Override + public boolean postHit(ItemStack stack, LivingEntity target, LivingEntity attacker) { + if (attacker instanceof PlayerEntity) { + RelicData data = getData(stack); + if (!attacker.getEntityWorld().isClient()) { + String id = data.attack[RANDOM.nextInt(data.attack.length)]; + Action action = Actions.get(id); + action.execute(attacker.getEntityWorld(), attacker, target); + } + + damage(stack, (PlayerEntity) attacker, Hand.MAIN_HAND); + return true; + } else { + return false; + } + } + + @Override + public boolean canMine(BlockState state, World world, BlockPos pos, PlayerEntity miner) { + RelicData data = getData(miner.getMainHandStack()); + if (!world.isClient()) { + String id = data.attack[RANDOM.nextInt(data.attack.length)]; + Action action = Actions.get(id); + action.execute(miner.getEntityWorld(), miner, pos); + } + + damage(miner.getMainHandStack(), miner, Hand.MAIN_HAND); + return false; + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + ItemStack stack = user.getStackInHand(hand); + RelicData data = getData(stack); + if (data.use.mode == RelicData.UseData.Mode.PROJECTILE) { + if (!world.isClient()) { + RelicEntity entity = new RelicEntity(world, user); + entity.setItem(stack); + entity.setProperties(user, user.pitch, user.yaw, 0.0f, 1.5f, 1.0f); + world.spawnEntity(entity); + } + + damage(stack, user, hand); + return new TypedActionResult<>(ActionResult.SUCCESS, stack); + } else if (data.use.mode == RelicData.UseData.Mode.SELF) { + if (!world.isClient()) { + String id = data.use.actions[RANDOM.nextInt(data.use.actions.length)]; + Action action = Actions.get(id); + action.execute(user.getEntityWorld(), user, user); + } + + damage(stack, user, hand); + return new TypedActionResult<>(ActionResult.SUCCESS, stack); + } else { + return new TypedActionResult<>(ActionResult.PASS, stack); + } + } + + @Override + public boolean useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { + RelicData data = getData(stack); + if (data.use.mode == RelicData.UseData.Mode.TARGET) { + if (!user.getEntityWorld().isClient()) { + String id = data.use.actions[RANDOM.nextInt(data.use.actions.length)]; + Action action = Actions.get(id); + action.execute(user.getEntityWorld(), user, entity); + } + + damage(stack, user, hand); + return true; + } else { + return false; + } + } + + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + assert context.getPlayer() != null; + RelicData data = getData(context.getStack()); + if (data.use.mode == RelicData.UseData.Mode.TARGET) { + if (!context.getWorld().isClient()) { + String id = data.use.actions[RANDOM.nextInt(data.use.actions.length)]; + Action action = Actions.get(id); + action.execute(context.getPlayer().getEntityWorld(), context.getPlayer(), context.getBlockPos()); + } + + damage(context.getStack(), context.getPlayer(), context.getHand()); + return ActionResult.SUCCESS; + } else { + return ActionResult.PASS; + } + } + + @Override + public boolean canRepair(ItemStack stack, ItemStack ingredient) { + return ingredient.getItem() == Items.BLAZE_POWDER; + } + + public static final String RELIC_REVEALED_KEY = "RelicRevealed"; + + @Environment(EnvType.CLIENT) + @Override + public void appendTooltip(ItemStack stack, World world, List tooltip, TooltipContext context) { + super.appendTooltip(stack, world, tooltip, context); + + CompoundTag tag = stack.getTag(); + if (tag == null) { + tag = new CompoundTag(); + } + byte revealed = tag.getByte(RELIC_REVEALED_KEY); + + if (revealed >= 2) { + RelicData data = getData(stack); + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_attack").formatted(Formatting.WHITE)); + for (String action : data.attack) { + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_attack.action", new TranslatableText("text." + RelicCraft.NAMESPACE + ".relic.action." + action).formatted(Formatting.GRAY))); + } + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_use").formatted(Formatting.WHITE)); + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_use.mode", new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_use.mode." + data.use.mode.name().toLowerCase()).formatted(Formatting.GRAY)).formatted(Formatting.WHITE)); + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_use.actions").formatted(Formatting.WHITE)); + for (String action : data.use.actions) { + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.on_use.actions.action", new TranslatableText("text." + RelicCraft.NAMESPACE + ".relic.action." + action).formatted(Formatting.GRAY))); + } + } else if (revealed == 1) { + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.relic.not_crafted").formatted(Formatting.WHITE)); + } + } + + @Override + public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) { + CompoundTag tag = stack.getTag(); + if (tag == null) { + tag = new CompoundTag(); + } + byte revealed = tag.getByte(RELIC_REVEALED_KEY); + if (revealed == 1) { + if (entity instanceof ServerPlayerEntity) { + RelicCraft.REVEAL_RELIC_CRITERION.trigger((ServerPlayerEntity) entity); + } + tag.putByte(RELIC_REVEALED_KEY, (byte) 2); + } + stack.setTag(tag); + } + + private void damage(ItemStack stack, PlayerEntity player, Hand hand) { + stack.damage(RANDOM.nextInt(4) + 1, player, e -> e.sendToolBreakStatus(hand)); + player.getItemCooldownManager().set(this, 10); + RelicCraft.playRelicSound(player); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/item/TargetedEnderPearlItem.java b/src/main/java/com/thebrokenrail/reliccraft/item/TargetedEnderPearlItem.java new file mode 100644 index 0000000..c02d427 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/item/TargetedEnderPearlItem.java @@ -0,0 +1,116 @@ +package com.thebrokenrail.reliccraft.item; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.block.AbstractDragonEggHolderBlock; +import com.thebrokenrail.reliccraft.block.TeleportationRestrictorBlock; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.Language; +import net.minecraft.util.Rarity; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; + +import java.util.List; + +public class TargetedEnderPearlItem extends Item { + public TargetedEnderPearlItem() { + super(new Settings().rarity(Rarity.UNCOMMON).maxCount(16)); + } + + @Override + public boolean hasEnchantmentGlint(ItemStack stack) { + return true; + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + ItemStack stack = user.getStackInHand(hand); + + if (!world.isClient()) { + RelicCraft.playRelicSound(user); + + CompoundTag tag = stack.getTag(); + if (tag == null) { + tag = new CompoundTag(); + } + + BlockPos target = new BlockPos(tag.getInt("TargetX"), tag.getInt("TargetY"), tag.getInt("TargetZ")); + Vec3d teleportTarget = new Vec3d(target.getX() + 0.5d, target.getY() + 1.0d, target.getZ() + 0.5d); + DimensionType dimension = DimensionType.byId(new Identifier(tag.getString("TargetDimension"))); + + if (user.dimension != dimension || dimension == null) { + user.sendMessage(new TranslatableText("chat." + RelicCraft.NAMESPACE + ".teleportation_beacon_in_different_dimension")); + } else { + if (((TeleportationRestrictorBlock.TeleportingEntity) user).cannotTeleport()) { + user.sendMessage(new TranslatableText("chat." + RelicCraft.NAMESPACE + ".teleportation_beacon_restricted")); + } else if (world.getBlockState(target).getBlock() != RelicCraft.TELEPORTATION_BEACON_BLOCK || !world.getBlockState(target).get(AbstractDragonEggHolderBlock.ACTIVE)) { + user.sendMessage(new TranslatableText("chat." + RelicCraft.NAMESPACE + ".missing_teleportation_beacon")); + } else { + Vec3d oldPos = user.getPos(); + if (user.teleport(teleportTarget.getX(), teleportTarget.getY(), teleportTarget.getZ(), true)) { + world.playSound(null, oldPos.getX(), oldPos.getY(), oldPos.getZ(), SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT, SoundCategory.PLAYERS, 1.0f, 1.0f); + world.playSound(null, teleportTarget.getX(), teleportTarget.getY(), teleportTarget.getZ(), SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT, SoundCategory.PLAYERS, 1.0f, 1.0f); + + RelicCraft.USE_TARGETED_ENDER_PEARL.trigger((ServerPlayerEntity) user); + + user.damage(DamageSource.FALL, 16.0f); + + user.fallDistance = 0f; + } else { + user.sendMessage(new TranslatableText("chat." + RelicCraft.NAMESPACE + ".teleportation_beacon_obstructed")); + } + } + } + } + + if (!user.isCreative()) { + stack.decrement(1); + } + + return new TypedActionResult<>(ActionResult.SUCCESS, stack); + } + + @Override + @Environment(EnvType.CLIENT) + public void appendTooltip(ItemStack stack, World world, List tooltip, TooltipContext context) { + super.appendTooltip(stack, world, tooltip, context); + + CompoundTag tag = stack.getTag(); + if (tag == null) { + tag = new CompoundTag(); + } + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.targeted_ender_pearl.x", new LiteralText(String.valueOf(tag.getInt("TargetX"))).formatted(Formatting.GRAY)).formatted(Formatting.WHITE)); + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.targeted_ender_pearl.y", new LiteralText(String.valueOf(tag.getInt("TargetY"))).formatted(Formatting.GRAY)).formatted(Formatting.WHITE)); + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.targeted_ender_pearl.z", new LiteralText(String.valueOf(tag.getInt("TargetZ"))).formatted(Formatting.GRAY)).formatted(Formatting.WHITE)); + + Identifier id = new Identifier(tag.getString("TargetDimension")); + String key = "text." + RelicCraft.NAMESPACE + ".dimension." + id.getNamespace() + '.' + id.getPath(); + Text dimensionText; + if (Language.getInstance().hasTranslation(key)) { + dimensionText = new TranslatableText(key); + } else { + dimensionText = new LiteralText(id.toString()); + } + dimensionText.formatted(Formatting.GRAY); + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.targeted_ender_pearl.dimension", dimensionText).formatted(Formatting.WHITE)); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/item/TimeDilaterItem.java b/src/main/java/com/thebrokenrail/reliccraft/item/TimeDilaterItem.java new file mode 100644 index 0000000..fc89788 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/item/TimeDilaterItem.java @@ -0,0 +1,92 @@ +package com.thebrokenrail.reliccraft.item; + +import com.thebrokenrail.reliccraft.RelicCraft; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.Rarity; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; + +import java.util.List; + +public class TimeDilaterItem extends Item { + public enum TimeSpeed { + NORMAL, + FAST, + VERY_FAST + } + + public interface DilatedWorld { + void setTimeSpeed(TimeSpeed speed); + TimeSpeed getTimeSpeed(); + } + + public TimeDilaterItem() { + super(new Settings().group(ItemGroup.MISC).maxDamage(9).rarity(Rarity.UNCOMMON)); + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + ItemStack stack = user.getStackInHand(hand); + if (!world.isClient()) { + DilatedWorld dilatedWorld = (DilatedWorld) world; + switch (dilatedWorld.getTimeSpeed()) { + case FAST: { + dilatedWorld.setTimeSpeed(TimeSpeed.VERY_FAST); + break; + } + case VERY_FAST: { + dilatedWorld.setTimeSpeed(TimeSpeed.NORMAL); + break; + } + case NORMAL: { + dilatedWorld.setTimeSpeed(TimeSpeed.FAST); + break; + } + } + assert world.getServer() != null; + world.getServer().getPlayerManager().sendToAll(new TranslatableText("chat." + RelicCraft.NAMESPACE + ".announce_time_speed_change", user.getDisplayName(), new LiteralText("[").append(new TranslatableText("chat." + RelicCraft.NAMESPACE + ".announce_time_speed_change." + dilatedWorld.getTimeSpeed().name().toLowerCase())).append("]").formatted(Formatting.YELLOW))); + RelicCraft.DILATE_TIME_CRITERION.trigger((ServerPlayerEntity) user); + } + + RelicCraft.playRelicSound(user); + stack.damage(1, user, e -> e.sendToolBreakStatus(hand)); + return new TypedActionResult<>(ActionResult.SUCCESS, stack); + } + + @Override + @Environment(EnvType.CLIENT) + public void appendTooltip(ItemStack stack, World world, List tooltip, TooltipContext context) { + super.appendTooltip(stack, world, tooltip, context); + + if (world != null) { + tooltip.add(new TranslatableText("item." + RelicCraft.NAMESPACE + ".tooltip.time_dilater", new TranslatableText("chat." + RelicCraft.NAMESPACE + ".announce_time_speed_change." + ((DilatedWorld) world).getTimeSpeed().name().toLowerCase()).formatted(Formatting.GRAY)).formatted(Formatting.WHITE)); + } + } + + @Override + public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) { + CompoundTag tag = stack.getTag(); + if (tag == null) { + tag = new CompoundTag(); + } + if (entity instanceof ServerPlayerEntity && tag.getByte("Artificial") == 1) { + RelicCraft.DUPLICATE_TIME_DILATER_CRITERION.trigger((ServerPlayerEntity) entity); + tag.putByte("Artificial", (byte) 2); + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/CriteriaRegistryHook.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/CriteriaRegistryHook.java new file mode 100644 index 0000000..ddceb1b --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/CriteriaRegistryHook.java @@ -0,0 +1,14 @@ +package com.thebrokenrail.reliccraft.mixin; + +import net.minecraft.advancement.criterion.Criterion; +import net.minecraft.advancement.criterion.Criterions; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Criterions.class) +public interface CriteriaRegistryHook { + @Invoker("register") + static > T callRegister(T criterion) { + return criterion; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinClientPlayNetworkHandler.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinClientPlayNetworkHandler.java new file mode 100644 index 0000000..433210e --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinClientPlayNetworkHandler.java @@ -0,0 +1,46 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.entity.RelicEntity; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@SuppressWarnings("unused") +@Environment(EnvType.CLIENT) +@Mixin(ClientPlayNetworkHandler.class) +public class MixinClientPlayNetworkHandler { + @Shadow + private ClientWorld world; + + @Inject(method = "onEntitySpawn", at = @At(value = "TAIL")) + public void onEntitySpawn(EntitySpawnS2CPacket packet, CallbackInfo info) { + EntityType entityType = packet.getEntityTypeId(); + Entity entity = null; + + if (entityType == RelicCraft.RELIC_ENTITY) { + entity = new RelicEntity(world, packet.getX(), packet.getY(), packet.getZ()); + } + + if (entity != null) { + double x = packet.getX(); + double y = packet.getY(); + double z = packet.getZ(); + entity.updateTrackedPosition(x, y, z); + entity.pitch = (float) (packet.getPitch() * 360) / 250F; + entity.yaw = (float) (packet.getYaw() * 360) / 250F; + entity.setEntityId(packet.getId()); + entity.setUuid(packet.getUuid()); + world.addEntity(packet.getId(), entity); + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEnderDragonFight.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEnderDragonFight.java new file mode 100644 index 0000000..1fbdd2b --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEnderDragonFight.java @@ -0,0 +1,17 @@ +package com.thebrokenrail.reliccraft.mixin; + +import net.minecraft.entity.boss.dragon.EnderDragonFight; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@SuppressWarnings("unused") +@Mixin(EnderDragonFight.class) +public class MixinEnderDragonFight { + @SuppressWarnings("SameReturnValue") + @Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/entity/boss/dragon/EnderDragonFight;previouslyKilled:Z", opcode = Opcodes.GETFIELD), method = "dragonKilled") + public boolean forceDragonEggSpawn(EnderDragonFight enderDragonFight) { + return false; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEnderPearlItem.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEnderPearlItem.java new file mode 100644 index 0000000..4d9b0d9 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEnderPearlItem.java @@ -0,0 +1,70 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.block.AbstractDragonEggHolderBlock; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.EnderPearlItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +import org.spongepowered.asm.mixin.Mixin; + +import java.util.Objects; + +@SuppressWarnings("unused") +@Mixin(EnderPearlItem.class) +public class MixinEnderPearlItem extends Item { + public MixinEnderPearlItem(Settings settings) { + super(settings); + } + + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + World world = context.getWorld(); + BlockPos pos = context.getBlockPos(); + String dimension = Objects.requireNonNull(DimensionType.getId(world.getDimension().getType())).toString(); + BlockState state = world.getBlockState(pos); + PlayerEntity user = context.getPlayer(); + + if (!world.isClient()) { + assert user != null; + RelicCraft.playRelicSound(user); + } + + if (user != null && state.getBlock() == RelicCraft.TELEPORTATION_BEACON_BLOCK && state.get(AbstractDragonEggHolderBlock.ACTIVE)) { + CompoundTag tag = new CompoundTag(); + tag.putInt("TargetX", pos.getX()); + tag.putInt("TargetY", pos.getY()); + tag.putInt("TargetZ", pos.getZ()); + tag.putString("TargetDimension", dimension); + + ItemStack itemStack = new ItemStack(RelicCraft.TARGETED_ENDER_PEARL_ITEM); + itemStack.setTag(tag); + + ItemStack itemStack2 = user.getStackInHand(context.getHand()); + + if (!user.isCreative()) { + itemStack2.decrement(1); + } + + if (!user.inventory.insertStack(itemStack.copy())) { + user.dropItem(itemStack, false); + } + + if (!world.isClient()) { + RelicCraft.USE_TELEPORTATION_BEACON_CRITERION.trigger((ServerPlayerEntity) user); + } + + return ActionResult.SUCCESS; + } else { + return ActionResult.PASS; + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEntity.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEntity.java new file mode 100644 index 0000000..459623a --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinEntity.java @@ -0,0 +1,33 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.block.TeleportationRestrictorBlock; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@SuppressWarnings("unused") +@Mixin(Entity.class) +public class MixinEntity implements TeleportationRestrictorBlock.TeleportingEntity { + @Unique + private int teleportCooldown = 0; + + @Override + public void resetTeleportCooldown() { + teleportCooldown = 5; + } + + @Inject(at = @At("HEAD"), method = "tick") + public void tick(CallbackInfo info) { + if (teleportCooldown > 0) { + teleportCooldown--; + } + } + + @Override + public boolean cannotTeleport() { + return teleportCooldown > 0; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinItemStack.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinItemStack.java new file mode 100644 index 0000000..6a8cb99 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinItemStack.java @@ -0,0 +1,19 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.item.RelicItem; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@SuppressWarnings("unused") +@Mixin(ItemStack.class) +public class MixinItemStack { + @Inject(at = @At("HEAD"), method = "getMaxDamage", cancellable = true) + public void getMaxDamage(CallbackInfoReturnable info) { + if (((ItemStack) (Object) this).getItem() instanceof RelicItem) { + info.setReturnValue(((RelicItem) ((ItemStack) (Object) this).getItem()).getMaxDamage((ItemStack) (Object) this)); + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLevelProperties.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLevelProperties.java new file mode 100644 index 0000000..5775f06 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLevelProperties.java @@ -0,0 +1,41 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.mojang.datafixers.DataFixer; +import com.thebrokenrail.reliccraft.item.TimeDilaterItem; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.LevelProperties; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@SuppressWarnings("unused") +@Mixin(LevelProperties.class) +public class MixinLevelProperties implements TimeDilaterItem.DilatedWorld { + @Unique + private TimeDilaterItem.TimeSpeed timeSpeed = TimeDilaterItem.TimeSpeed.NORMAL; + + @Inject(at = @At("RETURN"), method = "(Lnet/minecraft/nbt/CompoundTag;Lcom/mojang/datafixers/DataFixer;ILnet/minecraft/nbt/CompoundTag;)V") + public void init(CompoundTag compoundTag, DataFixer dataFixer, int i, CompoundTag compoundTag2, CallbackInfo info) { + try { + timeSpeed = TimeDilaterItem.TimeSpeed.valueOf(compoundTag.getString("RelicCraftTimeSpeed")); + } catch (IllegalArgumentException ignored) { + } + } + + @Inject(at = @At("RETURN"), method = "updateProperties") + public void updateProperties(CompoundTag levelTag, CompoundTag playerTag, CallbackInfo ci) { + levelTag.putString("RelicCraftTimeSpeed", timeSpeed.name()); + } + + @Override + public TimeDilaterItem.TimeSpeed getTimeSpeed() { + return timeSpeed; + } + + @Override + public void setTimeSpeed(TimeDilaterItem.TimeSpeed timeSpeed) { + this.timeSpeed = timeSpeed; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLivingEntity.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLivingEntity.java new file mode 100644 index 0000000..29c4e1f --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLivingEntity.java @@ -0,0 +1,18 @@ +package com.thebrokenrail.reliccraft.mixin; + +import net.minecraft.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@SuppressWarnings("unused") +@Mixin(LivingEntity.class) +public class MixinLivingEntity extends MixinEntity { + @Inject(at = @At("HEAD"), method = "teleport", cancellable = true) + public void teleport(double x, double y, double z, boolean particleEffects, CallbackInfoReturnable info) { + if (cannotTeleport()) { + info.setReturnValue(false); + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLocateCommand.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLocateCommand.java new file mode 100644 index 0000000..b08ba30 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinLocateCommand.java @@ -0,0 +1,27 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.mojang.brigadier.CommandDispatcher; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.LocateCommand; +import net.minecraft.server.command.ServerCommandSource; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@SuppressWarnings("unused") +@Mixin(LocateCommand.class) +public abstract class MixinLocateCommand { + @Shadow + private static int execute(ServerCommandSource source, String structure) { + throw new UnsupportedOperationException(); + } + + @Inject(method = "register", at = @At(value = "RETURN")) + private static void onRegister(CommandDispatcher dispatcher, CallbackInfo info) { + dispatcher.register(CommandManager.literal("locate").requires(source -> source.hasPermissionLevel(2)) + .then(CommandManager.literal("RelicCraft_Time_Temple").executes(ctx -> execute(ctx.getSource(), RelicCraft.TIME_TEMPLE_ID)))); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinNetherStarItem.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinNetherStarItem.java new file mode 100644 index 0000000..7e0fe4a --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinNetherStarItem.java @@ -0,0 +1,16 @@ +package com.thebrokenrail.reliccraft.mixin; + +import net.minecraft.item.Item; +import net.minecraft.item.NetherStarItem; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@SuppressWarnings("unused") +@Mixin(NetherStarItem.class) +public class MixinNetherStarItem { + @ModifyVariable(at = @At("HEAD"), method = "", argsOnly = true) + private static Item.Settings init(Item.Settings settings) { + return settings.maxDamage(6); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinServerWorld.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinServerWorld.java new file mode 100644 index 0000000..a261033 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinServerWorld.java @@ -0,0 +1,19 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.packet.UpdateTimeDilationS2CPacket; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.function.BooleanSupplier; + +@SuppressWarnings("unused") +@Mixin(ServerWorld.class) +public abstract class MixinServerWorld extends MixinWorld { + @Inject(at = @At("RETURN"), method = "tick") + public void tick(BooleanSupplier shouldKeepTicking, CallbackInfo info) { + UpdateTimeDilationS2CPacket.send((ServerWorld) (Object) this, getTimeSpeed()); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinThrownEnderpearlEntity.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinThrownEnderpearlEntity.java new file mode 100644 index 0000000..e8ce5f8 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinThrownEnderpearlEntity.java @@ -0,0 +1,23 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.block.TeleportationRestrictorBlock; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.thrown.ThrownEnderpearlEntity; +import net.minecraft.util.hit.HitResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@SuppressWarnings("unused") +@Mixin(ThrownEnderpearlEntity.class) +public class MixinThrownEnderpearlEntity { + @Inject(at = @At("HEAD"), method = "onCollision", cancellable = true) + public void onCollision(HitResult hitResult, CallbackInfo info) { + LivingEntity owner = ((ThrownEnderpearlEntity) (Object) this).getOwner(); + if (owner != null && ((TeleportationRestrictorBlock.TeleportingEntity) owner).cannotTeleport()) { + ((ThrownEnderpearlEntity) (Object) this).remove(); + info.cancel(); + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinWorld.java b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinWorld.java new file mode 100644 index 0000000..bf43952 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/mixin/MixinWorld.java @@ -0,0 +1,50 @@ +package com.thebrokenrail.reliccraft.mixin; + +import com.thebrokenrail.reliccraft.item.TimeDilaterItem; +import net.minecraft.world.World; +import net.minecraft.world.level.LevelProperties; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@SuppressWarnings("unused") +@Mixin(World.class) +public abstract class MixinWorld implements TimeDilaterItem.DilatedWorld { + @Shadow + public abstract boolean isClient(); + + @Shadow + @Final + protected LevelProperties properties; + + @Shadow + public abstract long getTime(); + + @ModifyConstant(constant = @Constant(longValue = 1L), method = "tickTime") + public long tickTime(long value) { + switch (getTimeSpeed()) { + case FAST: { + return value * 4L; + } + case VERY_FAST: { + return value * 8L; + } + default: + case NORMAL: { + return value; + } + } + } + + @Override + public void setTimeSpeed(TimeDilaterItem.TimeSpeed timeSpeed) { + ((TimeDilaterItem.DilatedWorld) properties).setTimeSpeed(timeSpeed); + } + + @Override + public TimeDilaterItem.TimeSpeed getTimeSpeed() { + return ((TimeDilaterItem.DilatedWorld) properties).getTimeSpeed(); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/packet/UpdateTimeDilationS2CPacket.java b/src/main/java/com/thebrokenrail/reliccraft/packet/UpdateTimeDilationS2CPacket.java new file mode 100644 index 0000000..80aa88e --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/packet/UpdateTimeDilationS2CPacket.java @@ -0,0 +1,39 @@ +package com.thebrokenrail.reliccraft.packet; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.item.TimeDilaterItem; +import io.netty.buffer.Unpooled; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.Packet; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; +import net.minecraft.world.World; + +@SuppressWarnings("unused") +public class UpdateTimeDilationS2CPacket { + public static void send(World world, TimeDilaterItem.TimeSpeed speed) { + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + buf.writeString(speed.name()); + + Packet packet = new CustomPayloadS2CPacket(new Identifier(RelicCraft.NAMESPACE, "update_time_dilation"), buf); + for (PlayerEntity player : world.getPlayers()) { + ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, packet); + } + } + + @Environment(EnvType.CLIENT) + public static void handle(PacketContext context, PacketByteBuf buf) { + TimeDilaterItem.TimeSpeed speed = TimeDilaterItem.TimeSpeed.valueOf(buf.readString()); + + MinecraftClient client = MinecraftClient.getInstance(); + assert client.world != null; + + ((TimeDilaterItem.DilatedWorld) client.world).setTimeSpeed(speed); + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/recipe/RevealRelicRecipe.java b/src/main/java/com/thebrokenrail/reliccraft/recipe/RevealRelicRecipe.java new file mode 100644 index 0000000..19d9a82 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/recipe/RevealRelicRecipe.java @@ -0,0 +1,102 @@ +package com.thebrokenrail.reliccraft.recipe; + +import com.thebrokenrail.reliccraft.RelicCraft; +import com.thebrokenrail.reliccraft.item.RelicItem; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.SpecialCraftingRecipe; +import net.minecraft.util.DefaultedList; +import net.minecraft.util.Identifier; +import net.minecraft.world.World; + +import java.util.Random; + +public class RevealRelicRecipe extends SpecialCraftingRecipe { + public RevealRelicRecipe(Identifier id) { + super(id); + } + + public boolean matches(CraftingInventory craftingInventory, World world) { + ItemStack itemStack = ItemStack.EMPTY; + int netherStar = 0; + + for (int i = 0; i < craftingInventory.getInvSize(); ++i) { + ItemStack itemStack2 = craftingInventory.getInvStack(i); + if (!itemStack2.isEmpty()) { + if (itemStack2.getItem() instanceof RelicItem) { + if (!itemStack.isEmpty()) { + return false; + } + + itemStack = itemStack2; + } else if (itemStack2.getItem() == Items.NETHER_STAR) { + netherStar++; + } else { + return false; + } + } + } + + return !itemStack.isEmpty() && netherStar == 1; + } + + public ItemStack craft(CraftingInventory craftingInventory) { + ItemStack itemStack = ItemStack.EMPTY; + + for (int i = 0; i < craftingInventory.getInvSize(); i++) { + ItemStack itemStack2 = craftingInventory.getInvStack(i); + if (!itemStack2.isEmpty()) { + Item item = itemStack2.getItem(); + if (item instanceof RelicItem) { + if (!itemStack.isEmpty()) { + return ItemStack.EMPTY; + } + + itemStack = itemStack2.copy(); + break; + } + } + } + + if (!itemStack.isEmpty()) { + CompoundTag tag = itemStack.getTag(); + if (tag == null) { + tag = new CompoundTag(); + } + tag.putByte(RelicItem.RELIC_REVEALED_KEY, (byte) 1); + itemStack.setTag(tag); + return itemStack; + } else { + return ItemStack.EMPTY; + } + } + + @Environment(EnvType.CLIENT) + public boolean fits(int width, int height) { + return width * height >= 2; + } + + public RecipeSerializer getSerializer() { + return RelicCraft.REVEAL_RELIC_RECIPE; + } + + @Override + public DefaultedList getRemainingStacks(CraftingInventory inventory) { + DefaultedList defaultedList = DefaultedList.ofSize(inventory.getInvSize(), ItemStack.EMPTY); + for (int i = 0; i < defaultedList.size(); i++) { + ItemStack stack = inventory.getInvStack(i); + if (stack.getItem().hasRecipeRemainder()) { + defaultedList.set(i, new ItemStack(stack.getItem().getRecipeRemainder())); + } else if (stack.getItem() == Items.NETHER_STAR && !stack.damage(1, new Random(), null)) { + defaultedList.set(i, stack.copy()); + } + } + return defaultedList; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/recipe/TimeDilaterRecipe.java b/src/main/java/com/thebrokenrail/reliccraft/recipe/TimeDilaterRecipe.java new file mode 100644 index 0000000..698c026 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/recipe/TimeDilaterRecipe.java @@ -0,0 +1,51 @@ +package com.thebrokenrail.reliccraft.recipe; + +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.recipe.Ingredient; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.ShapelessRecipe; +import net.minecraft.util.DefaultedList; +import net.minecraft.util.Identifier; + +import java.util.Random; + +public class TimeDilaterRecipe extends ShapelessRecipe { + private static final DefaultedList INGREDIENTS; + private static final ItemStack OUTPUT; + + static { + INGREDIENTS = DefaultedList.of(); + INGREDIENTS.add(Ingredient.ofItems(Items.NETHER_STAR)); + INGREDIENTS.add(Ingredient.ofItems(RelicCraft.TIME_DILATER_ITEM)); + INGREDIENTS.add(Ingredient.ofItems(Items.CLOCK)); + + OUTPUT = new ItemStack(RelicCraft.TIME_DILATER_ITEM); + CompoundTag tag = new CompoundTag(); + tag.putByte("Artificial", (byte) 1); + OUTPUT.setTag(tag); + } + + public TimeDilaterRecipe(Identifier id) { + super(id, "", OUTPUT, INGREDIENTS); + } + + public RecipeSerializer getSerializer() { + return RelicCraft.TIME_DILATER_RECIPE; + } + + @Override + public DefaultedList getRemainingStacks(CraftingInventory inventory) { + DefaultedList defaultedList = DefaultedList.ofSize(inventory.getInvSize(), ItemStack.EMPTY); + for (int i = 0; i < defaultedList.size(); i++) { + ItemStack stack = inventory.getInvStack(i); + if (stack.getItem() == Items.NETHER_STAR && !stack.damage(1, new Random(), null) || stack.getItem() == RelicCraft.TIME_DILATER_ITEM) { + defaultedList.set(i, stack.copy()); + } + } + return defaultedList; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleFeature.java b/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleFeature.java new file mode 100644 index 0000000..82e6360 --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleFeature.java @@ -0,0 +1,34 @@ +package com.thebrokenrail.reliccraft.structure; + +import com.mojang.datafixers.Dynamic; +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.world.gen.feature.AbstractTempleFeature; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; + +import java.util.function.Function; + +public class TimeTempleFeature extends AbstractTempleFeature { + public TimeTempleFeature(Function, ? extends DefaultFeatureConfig> configFactory) { + super(configFactory); + } + + @Override + protected int getSeedModifier() { + return 0; + } + + @Override + public StructureStartFactory getStructureStartFactory() { + return TimeTempleStructureStart::new; + } + + @Override + public String getName() { + return RelicCraft.TIME_TEMPLE_ID; + } + + @Override + public int getRadius() { + return 8; + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleGenerator.java b/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleGenerator.java new file mode 100644 index 0000000..92ada3a --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleGenerator.java @@ -0,0 +1,127 @@ +package com.thebrokenrail.reliccraft.structure; + +import com.thebrokenrail.reliccraft.RelicCraft; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.state.property.Property; +import net.minecraft.structure.SimpleStructurePiece; +import net.minecraft.structure.Structure; +import net.minecraft.structure.StructureManager; +import net.minecraft.structure.StructurePiece; +import net.minecraft.structure.StructurePlacementData; +import net.minecraft.structure.processor.BlockIgnoreStructureProcessor; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.Heightmap; +import net.minecraft.world.IWorld; +import net.minecraft.world.gen.chunk.ChunkGenerator; + +import java.util.Collection; +import java.util.List; +import java.util.Random; + +public class TimeTempleGenerator { + public static void addPieces(StructureManager structureManager, BlockPos blockPos, BlockRotation rotation, List list) { + list.add(new Piece(structureManager, new Identifier(RelicCraft.NAMESPACE, "time_temple"), blockPos, rotation)); + } + + public static class Piece extends SimpleStructurePiece { + private final Identifier template; + private final BlockRotation rotation; + + public Piece(StructureManager manager, Identifier identifier, BlockPos pos, BlockRotation rotation) { + super(RelicCraft.TIME_TEMPLE_STRUCTURE_PIECE, 0); + this.template = identifier; + this.pos = pos; + this.rotation = rotation; + initializeStructureData(manager); + } + + public Piece(StructureManager manager, CompoundTag tag) { + super(RelicCraft.TIME_TEMPLE_STRUCTURE_PIECE, tag); + template = new Identifier(tag.getString("Template")); + rotation = BlockRotation.valueOf(tag.getString("Rot")); + initializeStructureData(manager); + } + + private void initializeStructureData(StructureManager manager) { + Structure structure = manager.getStructureOrBlank(template); + StructurePlacementData structurePlacementData = new StructurePlacementData().setRotation(rotation).setMirrored(BlockMirror.NONE).setIgnoreEntities(true).addProcessor(BlockIgnoreStructureProcessor.IGNORE_STRUCTURE_BLOCKS); + setStructureData(structure, pos, structurePlacementData); + } + + @Override + protected void toNbt(CompoundTag tag) { + super.toNbt(tag); + tag.putString("Template", template.toString()); + tag.putString("Rot", rotation.name()); + } + + @Override + public boolean generate(IWorld world, ChunkGenerator generator, Random random, BlockBox box, ChunkPos chunkPos) { + int yHeight = 0; + int area = 0; + for (int x = getBoundingBox().minX; x <= getBoundingBox().maxX; x++) { + for (int z = getBoundingBox().minZ; z <= getBoundingBox().maxZ; z++) { + yHeight = yHeight + world.getTopY(Heightmap.Type.WORLD_SURFACE_WG, x, z); + area++; + } + } + yHeight = yHeight / area; + + BlockPos originalPos = pos; + pos = pos.add(0, yHeight - 90, 0); + + boolean result = super.generate(world, generator, random, box, chunkPos); + + if (result) { + for (int x = getBoundingBox().minX; x <= getBoundingBox().maxX; x++) { + for (int y = getBoundingBox().minY; y <= getBoundingBox().maxY; y++) { + for (int z = getBoundingBox().minZ; z <= getBoundingBox().maxZ; z++) { + BlockPos blockPos = new BlockPos(x, y, z); + if (box.contains(blockPos)) { + BlockState state = world.getBlockState(blockPos); + + boolean damaged = random.nextFloat() < 0.6f; + if (damaged) { + if (state.getBlock() == Blocks.STONE_BRICKS) { + boolean mossy = random.nextFloat() < 0.5f; + world.setBlockState(blockPos, convertState(state, mossy ? Blocks.MOSSY_STONE_BRICKS : Blocks.CRACKED_STONE_BRICKS), 3); + } else if (world.getBlockState(blockPos).getBlock() == Blocks.STONE_BRICK_STAIRS) { + world.setBlockState(blockPos, convertState(state, Blocks.MOSSY_STONE_BRICK_STAIRS), 3); + } else if (world.getBlockState(blockPos).getBlock() == Blocks.STONE_BRICK_SLAB) { + world.setBlockState(blockPos, convertState(state, Blocks.MOSSY_STONE_BRICK_SLAB), 3); + } + } + } + } + } + } + } + + pos = originalPos; + return result; + } + + private BlockState convertState(BlockState oldState, Block newBlock) { + BlockState newState = newBlock.getDefaultState(); + Collection> properties = oldState.getProperties(); + //noinspection rawtypes + for (Property property : properties) { + //noinspection unchecked + newState = newState.with(property, oldState.get(property)); + } + return newState; + } + + @Override + protected void handleMetadata(String metadata, BlockPos pos, IWorld world, Random random, BlockBox boundingBox) { + } + } +} diff --git a/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleStructureStart.java b/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleStructureStart.java new file mode 100644 index 0000000..82c9c0c --- /dev/null +++ b/src/main/java/com/thebrokenrail/reliccraft/structure/TimeTempleStructureStart.java @@ -0,0 +1,26 @@ +package com.thebrokenrail.reliccraft.structure; + +import net.minecraft.structure.StructureManager; +import net.minecraft.structure.StructureStart; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.feature.StructureFeature; + +public class TimeTempleStructureStart extends StructureStart { + public TimeTempleStructureStart(StructureFeature feature, int chunkX, int chunkZ, BlockBox box, int references, long l) { + super(feature, chunkX, chunkZ, box, references, l); + } + + @Override + public void initialize(ChunkGenerator chunkGenerator, StructureManager structureManager, int x, int z, Biome biome) { + int i = x * 16; + int j = z * 16; + BlockPos blockPos = new BlockPos(i, 90, j); + BlockRotation blockRotation = BlockRotation.values()[random.nextInt(BlockRotation.values().length)]; + TimeTempleGenerator.addPieces(structureManager, blockPos, blockRotation, children); + setBoundingBoxFromChildren(); + } +} diff --git a/src/main/resources/assets/reliccraft/blockstates/teleportation_beacon.json b/src/main/resources/assets/reliccraft/blockstates/teleportation_beacon.json new file mode 100644 index 0000000..70c8539 --- /dev/null +++ b/src/main/resources/assets/reliccraft/blockstates/teleportation_beacon.json @@ -0,0 +1,10 @@ +{ + "variants": { + "active=false": { + "model": "reliccraft:block/teleportation_beacon" + }, + "active=true": { + "model": "reliccraft:block/active_teleportation_beacon" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/blockstates/teleportation_restrictor.json b/src/main/resources/assets/reliccraft/blockstates/teleportation_restrictor.json new file mode 100644 index 0000000..e9d96be --- /dev/null +++ b/src/main/resources/assets/reliccraft/blockstates/teleportation_restrictor.json @@ -0,0 +1,10 @@ +{ + "variants": { + "active=false": { + "model": "reliccraft:block/teleportation_restrictor" + }, + "active=true": { + "model": "reliccraft:block/active_teleportation_restrictor" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/lang/en_us.json b/src/main/resources/assets/reliccraft/lang/en_us.json new file mode 100644 index 0000000..f3c044a --- /dev/null +++ b/src/main/resources/assets/reliccraft/lang/en_us.json @@ -0,0 +1,67 @@ +{ + "text.reliccraft.relic.title_variant.0": "The %s of %s", + "text.reliccraft.relic.title_variant.1": "%s of %s", + "text.reliccraft.relic.title_variant.2": "The %s %s", + "text.reliccraft.relic.magic_word.0": "Solarus", + "text.reliccraft.relic.magic_word.1": "Galagus", + "text.reliccraft.relic.magic_word.2": "Galactus", + "text.reliccraft.relic.magic_word.3": "Galagon", + "text.reliccraft.relic.magic_word.4": "Extremus", + "text.reliccraft.relic.magic_word.5": "Enchantus", + "text.reliccraft.relic.magic_word.6": "Magicus", + "item.reliccraft.orb": "Orb", + "item.reliccraft.staff": "Staff", + "item.reliccraft.targeted_ender_pearl": "Targeted Ender Pearl", + "item.reliccraft.time_dilater": "Time Dilater", + "chat.reliccraft.announce_time_speed_change": "%s has dilated the world's speed to %s", + "chat.reliccraft.announce_time_speed_change.fast": "Fast", + "chat.reliccraft.announce_time_speed_change.very_fast": "Very Fast", + "chat.reliccraft.announce_time_speed_change.normal": "Normal", + "chat.reliccraft.missing_teleportation_beacon": "Your Teleportation Beacon has been deactivated or destroyed", + "chat.reliccraft.teleportation_beacon_obstructed": "Your Teleportation Beacon is obstructed", + "chat.reliccraft.teleportation_beacon_restricted": "A Teleportation Restrictor is im effect", + "chat.reliccraft.teleportation_beacon_in_different_dimension": "Your Teleportation Beacon is in a different dimension", + "item.reliccraft.tooltip.relic.on_use": "On Use:", + "item.reliccraft.tooltip.relic.on_use.mode": " Mode: %s", + "item.reliccraft.tooltip.relic.on_use.mode.projectile": "Shoot Projectile", + "item.reliccraft.tooltip.relic.on_use.mode.target": "Use On Target", + "item.reliccraft.tooltip.relic.on_use.mode.self": "Use On Self", + "item.reliccraft.tooltip.relic.on_use.actions": " Actions:", + "item.reliccraft.tooltip.relic.on_use.actions.action": " %s", + "item.reliccraft.tooltip.relic.on_attack": "On Attack:", + "item.reliccraft.tooltip.relic.on_attack.action": " %s", + "item.reliccraft.tooltip.relic.not_crafted": "Craft To Reveal Secrets", + "item.reliccraft.tooltip.time_dilater": "Current Time Dilation: %s", + "item.reliccraft.tooltip.targeted_ender_pearl.x": "X: %s", + "item.reliccraft.tooltip.targeted_ender_pearl.y": "Y: %s", + "item.reliccraft.tooltip.targeted_ender_pearl.z": "Z: %s", + "item.reliccraft.tooltip.targeted_ender_pearl.dimension": "Dimension: %s", + "text.reliccraft.relic.action.heal_action": "Heal", + "text.reliccraft.relic.action.bedrock_action": "Turn To Bedrock", + "text.reliccraft.relic.action.gold_action": "Turn Coal To Gold", + "text.reliccraft.relic.action.diamond_action": "Turn Gold To Diamond", + "text.reliccraft.relic.action.end_action": "Go To The End", + "text.reliccraft.relic.action.nether_action": "Go To The Nether", + "text.reliccraft.relic.action.dirt_action": "Turn To Dirt", + "text.reliccraft.relic.action.zombify_action": "Zombify", + "text.reliccraft.relic.action.random_action": "Randomize", + "text.reliccraft.relic.action.half_heart_action": "Half-Heart", + "text.reliccraft.relic.action.swap_block_action": "Swap Blocks", + "block.reliccraft.teleportation_restrictor": "Teleportation Restrictor", + "block.reliccraft.teleportation_beacon": "Teleportation Beacon", + "advancements.reliccraft.root.title": "RelicCraft", + "advancements.reliccraft.root.description": "Explore Ancient Relics and Magic!", + "advancements.reliccraft.activate_teleportation_restrictor.title": "Teleportation Ban", + "advancements.reliccraft.activate_teleportation_restrictor.description": "Activate a Teleportation Restrictor with a Dragon Egg", + "advancements.reliccraft.activate_teleportation_beacon.title": "Teleportation Master", + "advancements.reliccraft.activate_teleportation_beacon.description": "Activate a Teleportation Beacon with a Dragon Egg, then create a Targeted Ender Pearl by using an Ender Pearl on it, and then finally use the Targeted Ender Pearl", + "advancements.reliccraft.reveal_relic.title": "Master Archaeologist", + "advancements.reliccraft.reveal_relic.description": "Combine a Relic with a Nether Star", + "advancements.reliccraft.dilate_time.title": "Time Master", + "advancements.reliccraft.dilate_time.description": "Use a Time Dilater", + "advancements.reliccraft.duplicate_time_dilater.title": "Time Lord", + "advancements.reliccraft.duplicate_time_dilater.description": "Duplicate a Time Dilater", + "text.reliccraft.dimension.minecraft.overworld": "The Overworld", + "text.reliccraft.dimension.minecraft.the_nether": "The Nether", + "text.reliccraft.dimension.minecraft.the_end": "The End" +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/block/active_teleportation_beacon.json b/src/main/resources/assets/reliccraft/models/block/active_teleportation_beacon.json new file mode 100644 index 0000000..67d5299 --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/block/active_teleportation_beacon.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "reliccraft:block/active_teleportation_beacon" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/block/active_teleportation_restrictor.json b/src/main/resources/assets/reliccraft/models/block/active_teleportation_restrictor.json new file mode 100644 index 0000000..cbf4a3c --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/block/active_teleportation_restrictor.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "reliccraft:block/active_teleportation_restrictor" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/block/teleportation_beacon.json b/src/main/resources/assets/reliccraft/models/block/teleportation_beacon.json new file mode 100644 index 0000000..a8b8b4b --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/block/teleportation_beacon.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "reliccraft:block/teleportation_beacon" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/block/teleportation_restrictor.json b/src/main/resources/assets/reliccraft/models/block/teleportation_restrictor.json new file mode 100644 index 0000000..6911e35 --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/block/teleportation_restrictor.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "reliccraft:block/teleportation_restrictor" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/item/orb.json b/src/main/resources/assets/reliccraft/models/item/orb.json new file mode 100644 index 0000000..62b8b8e --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/item/orb.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "reliccraft:item/orb" + } +} diff --git a/src/main/resources/assets/reliccraft/models/item/staff.json b/src/main/resources/assets/reliccraft/models/item/staff.json new file mode 100644 index 0000000..770d0bc --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/item/staff.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "reliccraft:item/staff_orb", + "layer1": "reliccraft:item/staff_handle" + } +} diff --git a/src/main/resources/assets/reliccraft/models/item/targeted_ender_pearl.json b/src/main/resources/assets/reliccraft/models/item/targeted_ender_pearl.json new file mode 100644 index 0000000..0c5a0fc --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/item/targeted_ender_pearl.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/ender_pearl" +} diff --git a/src/main/resources/assets/reliccraft/models/item/teleportation_beacon.json b/src/main/resources/assets/reliccraft/models/item/teleportation_beacon.json new file mode 100644 index 0000000..f96ab67 --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/item/teleportation_beacon.json @@ -0,0 +1,11 @@ +{ + "parent": "reliccraft:block/teleportation_beacon", + "overrides": [ + { + "predicate": { + "custom_model_data": 1 + }, + "model": "reliccraft:block/active_teleportation_beacon" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/item/teleportation_restrictor.json b/src/main/resources/assets/reliccraft/models/item/teleportation_restrictor.json new file mode 100644 index 0000000..5b8fd3b --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/item/teleportation_restrictor.json @@ -0,0 +1,11 @@ +{ + "parent": "reliccraft:block/teleportation_restrictor", + "overrides": [ + { + "predicate": { + "custom_model_data": 1 + }, + "model": "reliccraft:block/active_teleportation_restrictor" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/models/item/time_dilater.json b/src/main/resources/assets/reliccraft/models/item/time_dilater.json new file mode 100644 index 0000000..c9715f0 --- /dev/null +++ b/src/main/resources/assets/reliccraft/models/item/time_dilater.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "reliccraft:item/time_dilater" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reliccraft/textures/block/active_teleportation_beacon.png b/src/main/resources/assets/reliccraft/textures/block/active_teleportation_beacon.png new file mode 100644 index 0000000..3f08980 Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/block/active_teleportation_beacon.png differ diff --git a/src/main/resources/assets/reliccraft/textures/block/active_teleportation_restrictor.png b/src/main/resources/assets/reliccraft/textures/block/active_teleportation_restrictor.png new file mode 100644 index 0000000..fabb7d3 Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/block/active_teleportation_restrictor.png differ diff --git a/src/main/resources/assets/reliccraft/textures/block/teleportation_beacon.png b/src/main/resources/assets/reliccraft/textures/block/teleportation_beacon.png new file mode 100644 index 0000000..ea7ab2a Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/block/teleportation_beacon.png differ diff --git a/src/main/resources/assets/reliccraft/textures/block/teleportation_restrictor.png b/src/main/resources/assets/reliccraft/textures/block/teleportation_restrictor.png new file mode 100644 index 0000000..fe6e09f Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/block/teleportation_restrictor.png differ diff --git a/src/main/resources/assets/reliccraft/textures/item/orb.png b/src/main/resources/assets/reliccraft/textures/item/orb.png new file mode 100644 index 0000000..0a29d29 Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/item/orb.png differ diff --git a/src/main/resources/assets/reliccraft/textures/item/staff_handle.png b/src/main/resources/assets/reliccraft/textures/item/staff_handle.png new file mode 100644 index 0000000..7a5a9ce Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/item/staff_handle.png differ diff --git a/src/main/resources/assets/reliccraft/textures/item/staff_orb.png b/src/main/resources/assets/reliccraft/textures/item/staff_orb.png new file mode 100644 index 0000000..4b4bd61 Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/item/staff_orb.png differ diff --git a/src/main/resources/assets/reliccraft/textures/item/time_dilater.png b/src/main/resources/assets/reliccraft/textures/item/time_dilater.png new file mode 100644 index 0000000..064a93f Binary files /dev/null and b/src/main/resources/assets/reliccraft/textures/item/time_dilater.png differ diff --git a/src/main/resources/data/reliccraft/advancements/activate_teleportation_beacon.json b/src/main/resources/data/reliccraft/advancements/activate_teleportation_beacon.json new file mode 100644 index 0000000..463edb6 --- /dev/null +++ b/src/main/resources/data/reliccraft/advancements/activate_teleportation_beacon.json @@ -0,0 +1,33 @@ +{ + "parent": "reliccraft:root", + "display": { + "icon": { + "item": "reliccraft:teleportation_beacon", + "nbt": "{CustomModelData: 1}" + }, + "title": { + "translate": "advancements.reliccraft.activate_teleportation_beacon.title" + }, + "description": { + "translate": "advancements.reliccraft.activate_teleportation_beacon.description" + }, + "frame": "challenge", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "activate": { + "trigger": "reliccraft:activate_teleportation_beacon" + }, + "create_pearl": { + "trigger": "reliccraft:use_teleportation_beacon" + }, + "use_pearl": { + "trigger": "reliccraft:use_targeted_ender_pearl" + } + }, + "rewards": { + "experience": 100 + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/advancements/activate_teleportation_restrictor.json b/src/main/resources/data/reliccraft/advancements/activate_teleportation_restrictor.json new file mode 100644 index 0000000..6201b4f --- /dev/null +++ b/src/main/resources/data/reliccraft/advancements/activate_teleportation_restrictor.json @@ -0,0 +1,27 @@ +{ + "parent": "reliccraft:root", + "display": { + "icon": { + "item": "reliccraft:teleportation_restrictor", + "nbt": "{CustomModelData: 1}" + }, + "title": { + "translate": "advancements.reliccraft.activate_teleportation_restrictor.title" + }, + "description": { + "translate": "advancements.reliccraft.activate_teleportation_restrictor.description" + }, + "frame": "challenge", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "activate": { + "trigger": "reliccraft:activate_teleportation_restrictor" + } + }, + "rewards": { + "experience": 100 + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/advancements/dilate_time.json b/src/main/resources/data/reliccraft/advancements/dilate_time.json new file mode 100644 index 0000000..0d18087 --- /dev/null +++ b/src/main/resources/data/reliccraft/advancements/dilate_time.json @@ -0,0 +1,28 @@ +{ + "parent": "reliccraft:root", + "display": { + "icon": { + "item": "reliccraft:time_dilater" + }, + "title": { + "translate": "advancements.reliccraft.dilate_time.title" + }, + "description": { + "translate": "advancements.reliccraft.dilate_time.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "dilate_time": { + "trigger": "reliccraft:dilate_time" + } + }, + "rewards": { + "recipes": [ + "sorcerycraft:time_dilater" + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/advancements/duplicate_time_dilater.json b/src/main/resources/data/reliccraft/advancements/duplicate_time_dilater.json new file mode 100644 index 0000000..3ccbf7e --- /dev/null +++ b/src/main/resources/data/reliccraft/advancements/duplicate_time_dilater.json @@ -0,0 +1,26 @@ +{ + "parent": "reliccraft:dilate_time", + "display": { + "icon": { + "item": "reliccraft:time_dilater" + }, + "title": { + "translate": "advancements.reliccraft.duplicate_time_dilater.title" + }, + "description": { + "translate": "advancements.reliccraft.duplicate_time_dilater.description" + }, + "frame": "challenge", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "duplicate_time_dilater": { + "trigger": "reliccraft:duplicate_time_dilater" + } + }, + "rewards": { + "experience": 100 + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/advancements/reveal_relic.json b/src/main/resources/data/reliccraft/advancements/reveal_relic.json new file mode 100644 index 0000000..7aa955a --- /dev/null +++ b/src/main/resources/data/reliccraft/advancements/reveal_relic.json @@ -0,0 +1,26 @@ +{ + "parent": "reliccraft:root", + "display": { + "icon": { + "item": "minecraft:nether_star" + }, + "title": { + "translate": "advancements.reliccraft.reveal_relic.title" + }, + "description": { + "translate": "advancements.reliccraft.reveal_relic.description" + }, + "frame": "challenge", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "reveal_relic": { + "trigger": "reliccraft:reveal_relic" + } + }, + "rewards": { + "experience": 100 + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/advancements/root.json b/src/main/resources/data/reliccraft/advancements/root.json new file mode 100644 index 0000000..dc2cd2b --- /dev/null +++ b/src/main/resources/data/reliccraft/advancements/root.json @@ -0,0 +1,36 @@ +{ + "display": { + "icon": { + "item": "minecraft:ender_chest" + }, + "title": { + "translate": "advancements.reliccraft.root.title" + }, + "description": { + "translate": "advancements.reliccraft.root.description" + }, + "frame": "task", + "show_toast": false, + "announce_to_chat": false, + "hidden": false, + "background": "minecraft:textures/gui/advancements/backgrounds/stone.png" + }, + "criteria": { + "obtain_relic": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "reliccraft:relics" + } + ] + } + } + }, + "rewards": { + "recipes": [ + "reliccraft:teleportation_restrictor", + "reliccraft:teleportation_beacon" + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/loot_tables/blocks/teleportation_beacon.json b/src/main/resources/data/reliccraft/loot_tables/blocks/teleportation_beacon.json new file mode 100644 index 0000000..728a770 --- /dev/null +++ b/src/main/resources/data/reliccraft/loot_tables/blocks/teleportation_beacon.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "reliccraft:teleportation_beacon" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/loot_tables/blocks/teleportation_restrictor.json b/src/main/resources/data/reliccraft/loot_tables/blocks/teleportation_restrictor.json new file mode 100644 index 0000000..3b60453 --- /dev/null +++ b/src/main/resources/data/reliccraft/loot_tables/blocks/teleportation_restrictor.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "reliccraft:teleportation_restrictor" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/recipes/reveal_relic.json b/src/main/resources/data/reliccraft/recipes/reveal_relic.json new file mode 100644 index 0000000..13da6ab --- /dev/null +++ b/src/main/resources/data/reliccraft/recipes/reveal_relic.json @@ -0,0 +1,3 @@ +{ + "type": "reliccraft:reveal_relic" +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/recipes/teleportation_beacon.json b/src/main/resources/data/reliccraft/recipes/teleportation_beacon.json new file mode 100644 index 0000000..463f1e7 --- /dev/null +++ b/src/main/resources/data/reliccraft/recipes/teleportation_beacon.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "BIB", + "ISI", + "BIB" + ], + "key": { + "B": { + "item": "minecraft:blaze_powder" + }, + "S": { + "item": "minecraft:nether_star" + }, + "I": { + "item": "minecraft:iron_ingot" + } + }, + "result": { + "item": "reliccraft:teleportation_beacon" + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/recipes/teleportation_restrictor.json b/src/main/resources/data/reliccraft/recipes/teleportation_restrictor.json new file mode 100644 index 0000000..a2374da --- /dev/null +++ b/src/main/resources/data/reliccraft/recipes/teleportation_restrictor.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "OIO", + "ISI", + "OIO" + ], + "key": { + "O": { + "item": "minecraft:obsidian" + }, + "S": { + "item": "minecraft:nether_star" + }, + "I": { + "item": "minecraft:iron_ingot" + } + }, + "result": { + "item": "reliccraft:teleportation_restrictor" + } +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/recipes/time_dilater.json b/src/main/resources/data/reliccraft/recipes/time_dilater.json new file mode 100644 index 0000000..53c57b3 --- /dev/null +++ b/src/main/resources/data/reliccraft/recipes/time_dilater.json @@ -0,0 +1,3 @@ +{ + "type": "reliccraft:time_dilater" +} \ No newline at end of file diff --git a/src/main/resources/data/reliccraft/structures/time_temple.nbt b/src/main/resources/data/reliccraft/structures/time_temple.nbt new file mode 100644 index 0000000..c3366e0 Binary files /dev/null and b/src/main/resources/data/reliccraft/structures/time_temple.nbt differ diff --git a/src/main/resources/data/reliccraft/tags/items/relics.json b/src/main/resources/data/reliccraft/tags/items/relics.json new file mode 100644 index 0000000..0fe691e --- /dev/null +++ b/src/main/resources/data/reliccraft/tags/items/relics.json @@ -0,0 +1,10 @@ +{ + "replace": false, + "values": [ + "reliccraft:staff", + "reliccraft:orb", + "reliccraft:time_dilater", + "reliccraft:teleportation_restrictor", + "reliccraft:teleportation_beacon" + ] +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..1a791ee --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "schemaVersion": 1, + "id": "reliccraft", + "version": "${version}", + "name": "${name}", + "description": "Find magical relics throughout the world!", + "authors": [ + "TheBrokenRail" + ], + "contact": { + "homepage": "https://thebrokenrail.com/", + "sources": "https://gitea.thebrokenrail.com/TheBrokenRail/RelicCraft.git", + "issues": "https://gitea.thebrokenrail.com/TheBrokenRail/RelicCraft/issues" + }, + "license": "MIT", + "icon": "assets/reliccraft/textures/item/time_dilater.png", + "environment": "*", + "entrypoints": { + "main": [ + "com.thebrokenrail.reliccraft.RelicCraft" + ], + "client": [ + "com.thebrokenrail.reliccraft.client.RelicCraftClient" + ] + }, + "mixins": [ + "reliccraft.mixins.json" + ], + "depends": { + "fabricloader": ">=0.7.4", + "fabric": "*", + "minecraft": "1.15.x" + } +} diff --git a/src/main/resources/reliccraft.mixins.json b/src/main/resources/reliccraft.mixins.json new file mode 100644 index 0000000..9bca61f --- /dev/null +++ b/src/main/resources/reliccraft.mixins.json @@ -0,0 +1,25 @@ +{ + "required": true, + "package": "com.thebrokenrail.reliccraft.mixin", + "compatibilityLevel": "JAVA_8", + "client": [ + "MixinClientPlayNetworkHandler" + ], + "mixins": [ + "CriteriaRegistryHook", + "MixinEnderDragonFight", + "MixinEnderPearlItem", + "MixinEntity", + "MixinItemStack", + "MixinLevelProperties", + "MixinLivingEntity", + "MixinLocateCommand", + "MixinNetherStarItem", + "MixinServerWorld", + "MixinThrownEnderpearlEntity", + "MixinWorld" + ], + "injectors": { + "defaultRequire": 1 + } +}